mirror of
https://github.com/semaphoreui/semaphore.git
synced 2025-01-20 15:29:28 +01:00
feat(ui): language switcher
This commit is contained in:
parent
41c60b9eae
commit
985f3f3a03
@ -24,9 +24,112 @@ func GetProjects(w http.ResponseWriter, r *http.Request) {
|
||||
helpers.WriteJSON(w, http.StatusOK, projects)
|
||||
}
|
||||
|
||||
func createDemoProject(projectID int, store db.Store) (err error) {
|
||||
var noneKey db.AccessKey
|
||||
var demoRepo db.Repository
|
||||
var emptyEnv db.Environment
|
||||
|
||||
var buildInv db.Inventory
|
||||
var devInv db.Inventory
|
||||
var prodInv db.Inventory
|
||||
|
||||
noneKey, err = store.CreateAccessKey(db.AccessKey{
|
||||
Name: "None",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
demoRepo, err = store.CreateRepository(db.Repository{
|
||||
Name: "Demo Project",
|
||||
ProjectID: projectID,
|
||||
GitURL: "https://github.com/semaphoreui/demo-project.git",
|
||||
GitBranch: "main",
|
||||
SSHKeyID: noneKey.ID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
emptyEnv, err = store.CreateEnvironment(db.Environment{
|
||||
Name: "Empty",
|
||||
ProjectID: projectID,
|
||||
JSON: "{}",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
buildInv, err = store.CreateInventory(db.Inventory{
|
||||
Name: "Build",
|
||||
ProjectID: projectID,
|
||||
Inventory: "[builder]\nlocalhost",
|
||||
Type: "static",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
devInv, err = store.CreateInventory(db.Inventory{
|
||||
ProjectID: projectID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
prodInv, err = store.CreateInventory(db.Inventory{
|
||||
ProjectID: projectID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = store.CreateTemplate(db.Template{
|
||||
Name: "Build",
|
||||
Playbook: "build.yml",
|
||||
ProjectID: projectID,
|
||||
InventoryID: buildInv.ID,
|
||||
EnvironmentID: &emptyEnv.ID,
|
||||
RepositoryID: demoRepo.ID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = store.CreateTemplate(db.Template{
|
||||
Name: "Deploy to Dev",
|
||||
Playbook: "deploy.yml",
|
||||
ProjectID: projectID,
|
||||
InventoryID: devInv.ID,
|
||||
EnvironmentID: &emptyEnv.ID,
|
||||
RepositoryID: demoRepo.ID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = store.CreateTemplate(db.Template{
|
||||
Name: "Deploy to Production",
|
||||
Playbook: "deploy.yml",
|
||||
ProjectID: projectID,
|
||||
InventoryID: prodInv.ID,
|
||||
EnvironmentID: &emptyEnv.ID,
|
||||
RepositoryID: demoRepo.ID,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddProject adds a new project to the database
|
||||
func AddProject(w http.ResponseWriter, r *http.Request) {
|
||||
var body db.Project
|
||||
|
||||
user := context.Get(r, "user").(*db.User)
|
||||
|
||||
@ -36,25 +139,43 @@ func AddProject(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !helpers.Bind(w, r, &body) {
|
||||
var bodyWithDemo struct {
|
||||
db.Project
|
||||
Demo bool `json:"demo"`
|
||||
}
|
||||
|
||||
if !helpers.Bind(w, r, &bodyWithDemo) {
|
||||
return
|
||||
}
|
||||
|
||||
body, err := helpers.Store(r).CreateProject(body)
|
||||
body := bodyWithDemo.Project
|
||||
|
||||
store := helpers.Store(r)
|
||||
|
||||
body, err := store.CreateProject(body)
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = helpers.Store(r).CreateProjectUser(db.ProjectUser{ProjectID: body.ID, UserID: user.ID, Role: db.ProjectOwner})
|
||||
_, err = store.CreateProjectUser(db.ProjectUser{ProjectID: body.ID, UserID: user.ID, Role: db.ProjectOwner})
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if bodyWithDemo.Demo {
|
||||
err = createDemoProject(body.ID, store)
|
||||
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
desc := "Project Created"
|
||||
oType := db.EventProject
|
||||
_, err = helpers.Store(r).CreateEvent(db.Event{
|
||||
_, err = store.CreateEvent(db.Event{
|
||||
UserID: &user.ID,
|
||||
ProjectID: &body.ID,
|
||||
Description: &desc,
|
||||
|
225
web/src/App.vue
225
web/src/App.vue
@ -261,17 +261,52 @@
|
||||
</v-list>
|
||||
|
||||
<template v-slot:append>
|
||||
<v-menu top max-width="235" nudge-top="12">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-list class="pa-0">
|
||||
<v-list-item>
|
||||
<v-switch
|
||||
v-model="darkMode"
|
||||
inset
|
||||
:label="$t('darkMode')"
|
||||
persistent-hint
|
||||
></v-switch>
|
||||
</v-list-item>
|
||||
<v-list class="pa-0">
|
||||
<v-list-item>
|
||||
<v-switch
|
||||
v-model="darkMode"
|
||||
inset
|
||||
:label="$t('darkMode')"
|
||||
persistent-hint
|
||||
></v-switch>
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<v-menu top min-width="150" max-width="235" nudge-top="12" :position-x="50" absolute>
|
||||
<template v-slot:activator="{on, attrs}">
|
||||
<v-btn
|
||||
icon
|
||||
x-large
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
<span style="font-size: 30px;">{{ lang.flag }}</span>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list dense>
|
||||
<v-list-item
|
||||
v-for="lang in languages"
|
||||
:key="lang.id"
|
||||
@click="selectLanguage(lang.id)"
|
||||
>
|
||||
|
||||
<v-list-item-icon>
|
||||
{{ lang.flag }}
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ lang.title }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
</v-list-item>
|
||||
|
||||
<v-menu top max-width="235" nudge-top="12">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-list-item
|
||||
key="project"
|
||||
v-bind="attrs"
|
||||
@ -285,72 +320,43 @@
|
||||
<v-list-item-title>{{ user.name }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<v-list>
|
||||
<v-list-item key="users" to="/users" v-if="user.admin">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-account-multiple</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
{{ $t('users') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item key="edit" @click="userDialog = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
{{ $t('editAccount') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item key="sign_out" @click="signOut()">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-exit-to-app</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
{{ $t('signOut') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</template>
|
||||
</v-menu>
|
||||
|
||||
<v-list>
|
||||
<v-list-item key="users" to="/users" v-if="user.admin">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-account-multiple</v-icon>
|
||||
</v-list-item-icon>
|
||||
</v-list>
|
||||
|
||||
<v-list-item-content>
|
||||
{{ $t('users') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item key="edit" @click="userDialog = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
{{ $t('editAccount') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<!--
|
||||
<v-list-item key="password" @click="passwordDialog = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-information</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
System Information
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item key="password" @click="passwordDialog = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-tune</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
System Settings
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item key="password" @click="passwordDialog = true">-->
|
||||
<!-- <v-list-item-icon>-->
|
||||
<!-- <v-icon>mdi-lock</v-icon>-->
|
||||
<!-- </v-list-item-icon>-->
|
||||
|
||||
<!-- <v-list-item-content>-->
|
||||
<!-- Change Password-->
|
||||
<!-- </v-list-item-content>-->
|
||||
<!-- </v-list-item>-->
|
||||
|
||||
<v-list-item key="sign_out" @click="signOut()">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-exit-to-app</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
{{ $t('signOut') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-navigation-drawer>
|
||||
|
||||
@ -546,6 +552,49 @@ const PROJECT_COLORS = [
|
||||
'green',
|
||||
];
|
||||
|
||||
const LANGUAGES = {
|
||||
en: {
|
||||
flag: '🇺🇸',
|
||||
title: 'English',
|
||||
},
|
||||
ru: {
|
||||
flag: '🇷🇺',
|
||||
title: 'Russian',
|
||||
},
|
||||
de: {
|
||||
flag: '🇩🇪',
|
||||
title: 'German',
|
||||
},
|
||||
zh: {
|
||||
flag: '🇨🇳',
|
||||
title: 'Chinese',
|
||||
},
|
||||
fr: {
|
||||
flag: '🇫🇷',
|
||||
title: 'French',
|
||||
},
|
||||
pt: {
|
||||
flag: '🇵🇹',
|
||||
title: 'Portuguese',
|
||||
},
|
||||
};
|
||||
|
||||
function getLangInfo(locale) {
|
||||
let res = LANGUAGES[locale];
|
||||
|
||||
if (!res) {
|
||||
res = LANGUAGES.en;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function getSystemLang() {
|
||||
const locale = navigator.language.split('-')[0];
|
||||
|
||||
return getLangInfo(locale || 'en');
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
@ -574,6 +623,17 @@ export default {
|
||||
task: null,
|
||||
template: null,
|
||||
darkMode: false,
|
||||
languages: [
|
||||
{
|
||||
id: '',
|
||||
flag: getSystemLang().flag,
|
||||
title: 'System',
|
||||
},
|
||||
...Object.keys(LANGUAGES).map((lang) => ({
|
||||
id: lang,
|
||||
...LANGUAGES[lang],
|
||||
})),
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
@ -608,6 +668,17 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
lang() {
|
||||
const locale = localStorage.getItem('lang');
|
||||
|
||||
if (!locale) {
|
||||
return getSystemLang();
|
||||
}
|
||||
|
||||
return getLangInfo(locale || 'en');
|
||||
},
|
||||
|
||||
projectId() {
|
||||
return parseInt(this.$route.params.projectId, 10) || null;
|
||||
},
|
||||
@ -768,6 +839,12 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
selectLanguage(lang) {
|
||||
localStorage.setItem('lang', lang);
|
||||
window.location.reload();
|
||||
},
|
||||
|
||||
async onTaskLogDialogClosed() {
|
||||
const query = { ...this.$route.query, t: undefined };
|
||||
await this.$router.replace({ query });
|
||||
|
@ -48,6 +48,9 @@
|
||||
import ItemFormBase from '@/components/ItemFormBase';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
demoProject: Boolean,
|
||||
},
|
||||
mixins: [ItemFormBase],
|
||||
methods: {
|
||||
getItemsUrl() {
|
||||
@ -56,6 +59,9 @@ export default {
|
||||
getSingleItemUrl() {
|
||||
return `/api/project/${this.itemId}`;
|
||||
},
|
||||
beforeSave() {
|
||||
this.item.demo = this.demoProject;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -3,7 +3,13 @@ import VueI18n from 'vue-i18n';
|
||||
import { messages } from '../lang';
|
||||
|
||||
Vue.use(VueI18n);
|
||||
const locale = navigator.language.split('-')[0];
|
||||
|
||||
let locale = localStorage.getItem('lang');
|
||||
|
||||
if (!locale) {
|
||||
locale = navigator.language.split('-')[0];
|
||||
}
|
||||
|
||||
export default new VueI18n({
|
||||
fallbackLocale: 'en',
|
||||
locale,
|
||||
|
@ -12,7 +12,8 @@
|
||||
v-if="can(USER_PERMISSIONS.updateProject)"
|
||||
key="settings"
|
||||
:to="`/project/${projectId}/settings`"
|
||||
>{{ $t('settings') }}
|
||||
>
|
||||
{{ $t('settings') }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
|
@ -8,10 +8,14 @@
|
||||
|
||||
<div class="project-settings-form">
|
||||
<div style="height: 300px;">
|
||||
<ProjectForm item-id="new" ref="editForm" @save="onSave"/>
|
||||
<ProjectForm item-id="new" ref="editForm" @save="onSave" :demo-project="true" />
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<v-btn
|
||||
color="secondary" class="mr-3" @click="createDemoProject()"
|
||||
>Create Demo Project</v-btn>
|
||||
|
||||
<v-btn color="primary" @click="createProject()">{{ $t('create') }}</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
@ -29,6 +33,7 @@ export default {
|
||||
components: { ProjectForm },
|
||||
data() {
|
||||
return {
|
||||
demoProject: false,
|
||||
};
|
||||
},
|
||||
|
||||
@ -45,6 +50,12 @@ export default {
|
||||
},
|
||||
|
||||
async createProject() {
|
||||
this.demoProject = false;
|
||||
await this.$refs.editForm.save();
|
||||
},
|
||||
|
||||
async createDemoProject() {
|
||||
this.demoProject = true;
|
||||
await this.$refs.editForm.save();
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user