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)
|
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
|
// AddProject adds a new project to the database
|
||||||
func AddProject(w http.ResponseWriter, r *http.Request) {
|
func AddProject(w http.ResponseWriter, r *http.Request) {
|
||||||
var body db.Project
|
|
||||||
|
|
||||||
user := context.Get(r, "user").(*db.User)
|
user := context.Get(r, "user").(*db.User)
|
||||||
|
|
||||||
@ -36,25 +139,43 @@ func AddProject(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !helpers.Bind(w, r, &body) {
|
var bodyWithDemo struct {
|
||||||
|
db.Project
|
||||||
|
Demo bool `json:"demo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if !helpers.Bind(w, r, &bodyWithDemo) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := helpers.Store(r).CreateProject(body)
|
body := bodyWithDemo.Project
|
||||||
|
|
||||||
|
store := helpers.Store(r)
|
||||||
|
|
||||||
|
body, err := store.CreateProject(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helpers.WriteError(w, err)
|
helpers.WriteError(w, err)
|
||||||
return
|
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 {
|
if err != nil {
|
||||||
helpers.WriteError(w, err)
|
helpers.WriteError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bodyWithDemo.Demo {
|
||||||
|
err = createDemoProject(body.ID, store)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
helpers.WriteError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
desc := "Project Created"
|
desc := "Project Created"
|
||||||
oType := db.EventProject
|
oType := db.EventProject
|
||||||
_, err = helpers.Store(r).CreateEvent(db.Event{
|
_, err = store.CreateEvent(db.Event{
|
||||||
UserID: &user.ID,
|
UserID: &user.ID,
|
||||||
ProjectID: &body.ID,
|
ProjectID: &body.ID,
|
||||||
Description: &desc,
|
Description: &desc,
|
||||||
|
225
web/src/App.vue
225
web/src/App.vue
@ -261,17 +261,52 @@
|
|||||||
</v-list>
|
</v-list>
|
||||||
|
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<v-menu top max-width="235" nudge-top="12">
|
<v-list class="pa-0">
|
||||||
<template v-slot:activator="{ on, attrs }">
|
<v-list-item>
|
||||||
<v-list class="pa-0">
|
<v-switch
|
||||||
<v-list-item>
|
v-model="darkMode"
|
||||||
<v-switch
|
inset
|
||||||
v-model="darkMode"
|
:label="$t('darkMode')"
|
||||||
inset
|
persistent-hint
|
||||||
:label="$t('darkMode')"
|
></v-switch>
|
||||||
persistent-hint
|
|
||||||
></v-switch>
|
<v-spacer />
|
||||||
</v-list-item>
|
|
||||||
|
<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
|
<v-list-item
|
||||||
key="project"
|
key="project"
|
||||||
v-bind="attrs"
|
v-bind="attrs"
|
||||||
@ -285,72 +320,43 @@
|
|||||||
<v-list-item-title>{{ user.name }}</v-list-item-title>
|
<v-list-item-title>{{ user.name }}</v-list-item-title>
|
||||||
</v-list-item-content>
|
</v-list-item-content>
|
||||||
</v-list-item>
|
</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>
|
</v-list>
|
||||||
</template>
|
</v-menu>
|
||||||
|
|
||||||
<v-list>
|
</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="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>
|
</template>
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
|
|
||||||
@ -546,6 +552,49 @@ const PROJECT_COLORS = [
|
|||||||
'green',
|
'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 {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
@ -574,6 +623,17 @@ export default {
|
|||||||
task: null,
|
task: null,
|
||||||
template: null,
|
template: null,
|
||||||
darkMode: false,
|
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: {
|
computed: {
|
||||||
|
|
||||||
|
lang() {
|
||||||
|
const locale = localStorage.getItem('lang');
|
||||||
|
|
||||||
|
if (!locale) {
|
||||||
|
return getSystemLang();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLangInfo(locale || 'en');
|
||||||
|
},
|
||||||
|
|
||||||
projectId() {
|
projectId() {
|
||||||
return parseInt(this.$route.params.projectId, 10) || null;
|
return parseInt(this.$route.params.projectId, 10) || null;
|
||||||
},
|
},
|
||||||
@ -768,6 +839,12 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
selectLanguage(lang) {
|
||||||
|
localStorage.setItem('lang', lang);
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
|
||||||
async onTaskLogDialogClosed() {
|
async onTaskLogDialogClosed() {
|
||||||
const query = { ...this.$route.query, t: undefined };
|
const query = { ...this.$route.query, t: undefined };
|
||||||
await this.$router.replace({ query });
|
await this.$router.replace({ query });
|
||||||
|
@ -48,6 +48,9 @@
|
|||||||
import ItemFormBase from '@/components/ItemFormBase';
|
import ItemFormBase from '@/components/ItemFormBase';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
props: {
|
||||||
|
demoProject: Boolean,
|
||||||
|
},
|
||||||
mixins: [ItemFormBase],
|
mixins: [ItemFormBase],
|
||||||
methods: {
|
methods: {
|
||||||
getItemsUrl() {
|
getItemsUrl() {
|
||||||
@ -56,6 +59,9 @@ export default {
|
|||||||
getSingleItemUrl() {
|
getSingleItemUrl() {
|
||||||
return `/api/project/${this.itemId}`;
|
return `/api/project/${this.itemId}`;
|
||||||
},
|
},
|
||||||
|
beforeSave() {
|
||||||
|
this.item.demo = this.demoProject;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,7 +3,13 @@ import VueI18n from 'vue-i18n';
|
|||||||
import { messages } from '../lang';
|
import { messages } from '../lang';
|
||||||
|
|
||||||
Vue.use(VueI18n);
|
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({
|
export default new VueI18n({
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: 'en',
|
||||||
locale,
|
locale,
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
v-if="can(USER_PERMISSIONS.updateProject)"
|
v-if="can(USER_PERMISSIONS.updateProject)"
|
||||||
key="settings"
|
key="settings"
|
||||||
:to="`/project/${projectId}/settings`"
|
:to="`/project/${projectId}/settings`"
|
||||||
>{{ $t('settings') }}
|
>
|
||||||
|
{{ $t('settings') }}
|
||||||
</v-tab>
|
</v-tab>
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
|
||||||
|
@ -8,10 +8,14 @@
|
|||||||
|
|
||||||
<div class="project-settings-form">
|
<div class="project-settings-form">
|
||||||
<div style="height: 300px;">
|
<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>
|
||||||
|
|
||||||
<div class="text-right">
|
<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>
|
<v-btn color="primary" @click="createProject()">{{ $t('create') }}</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -29,6 +33,7 @@ export default {
|
|||||||
components: { ProjectForm },
|
components: { ProjectForm },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
demoProject: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -45,6 +50,12 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async createProject() {
|
async createProject() {
|
||||||
|
this.demoProject = false;
|
||||||
|
await this.$refs.editForm.save();
|
||||||
|
},
|
||||||
|
|
||||||
|
async createDemoProject() {
|
||||||
|
this.demoProject = true;
|
||||||
await this.$refs.editForm.save();
|
await this.$refs.editForm.save();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user