mirror of
https://github.com/abhinavxd/libredesk.git
synced 2025-10-23 05:11:57 +00:00
feat: translate sso
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
<form @submit="onSubmit" class="space-y-6">
|
||||
<FormField v-slot="{ componentField }" name="provider">
|
||||
<FormItem>
|
||||
<FormLabel>Provider</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.provider') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a provider" />
|
||||
<SelectValue :placeholder="t('form.field.selectProvider')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.name') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Google" v-bind="componentField" />
|
||||
</FormControl>
|
||||
@@ -32,9 +32,9 @@
|
||||
|
||||
<FormField v-slot="{ componentField }" name="provider_url">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Provider URL</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.providerURL') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Provider URL" v-bind="componentField" />
|
||||
<Input type="text" placeholder="https://accounts.google.com" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -42,9 +42,9 @@
|
||||
|
||||
<FormField v-slot="{ componentField }" name="client_id">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Client ID</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.clientID') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Client ID" v-bind="componentField" />
|
||||
<Input type="text" placeholder="" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -52,9 +52,9 @@
|
||||
|
||||
<FormField v-slot="{ componentField }" name="client_secret">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Client Secret</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.clientSecret') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="Client Secret" v-bind="componentField" />
|
||||
<Input type="password" placeholder="" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -62,11 +62,11 @@
|
||||
|
||||
<FormField v-slot="{ componentField }" name="redirect_uri" v-if="!isNewForm">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Callback URL</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.callbackURL') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Redirect URL" v-bind="componentField" readonly />
|
||||
<Input type="text" placeholder="" v-bind="componentField" readonly />
|
||||
</FormControl>
|
||||
<FormDescription>Set this URI for callback.</FormDescription>
|
||||
<FormDescription>{{ $t('admin.sso.setThisUrlForCallback') }}</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -76,10 +76,9 @@
|
||||
<FormControl>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox :checked="value" @update:checked="handleChange" />
|
||||
<Label>Enabled</Label>
|
||||
<Label>{{ $t('form.field.enabled') }}</Label>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormDescription></FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -93,10 +92,11 @@ import { watch } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { oidcLoginFormSchema } from './formSchema.js'
|
||||
import { createFormSchema } from './formSchema.js'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { vAutoAnimate } from '@formkit/auto-animate/vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
@@ -127,7 +127,7 @@ const props = defineProps({
|
||||
submitLabel: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => 'Save'
|
||||
default: () => ''
|
||||
},
|
||||
isNewForm: {
|
||||
type: Boolean
|
||||
@@ -137,9 +137,12 @@ const props = defineProps({
|
||||
required: false
|
||||
}
|
||||
})
|
||||
const { t } = useI18n()
|
||||
|
||||
const submitLabel = props.submitLabel || t('globals.buttons.save')
|
||||
|
||||
const form = useForm({
|
||||
validationSchema: toTypedSchema(oidcLoginFormSchema)
|
||||
validationSchema: toTypedSchema(createFormSchema(t)),
|
||||
})
|
||||
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
|
@@ -2,11 +2,11 @@ import { h } from 'vue'
|
||||
import dropdown from './dataTableDropdown.vue'
|
||||
import { format } from 'date-fns'
|
||||
|
||||
export const columns = [
|
||||
export const createColumns = (t) => [
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Name')
|
||||
return h('div', { class: 'text-center' }, t('form.field.name'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('name'))
|
||||
@@ -15,7 +15,7 @@ export const columns = [
|
||||
{
|
||||
accessorKey: 'provider',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Provider')
|
||||
return h('div', { class: 'text-center' }, t('form.field.provider'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('provider'))
|
||||
@@ -23,16 +23,16 @@ export const columns = [
|
||||
},
|
||||
{
|
||||
accessorKey: 'enabled',
|
||||
header: () => h('div', { class: 'text-center' }, 'Enabled'),
|
||||
header: () => h('div', { class: 'text-center' }, t('form.field.enabled')),
|
||||
cell: ({ row }) => {
|
||||
const enabled = row.getValue('enabled')
|
||||
return h('div', { class: 'text-center' }, enabled ? 'Yes' : 'No')
|
||||
return h('div', { class: 'text-center' }, enabled ? t('globals.messages.yes') : t('globals.messages.no'))
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: 'updated_at',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Updated at')
|
||||
return h('div', { class: 'text-center' }, t('form.field.updatedAt'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center' }, format(row.getValue('updated_at'), 'PPpp'))
|
||||
|
@@ -2,30 +2,35 @@
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="ghost" class="w-8 h-8 p-0">
|
||||
<span class="sr-only">Open menu</span>
|
||||
<span class="sr-only"></span>
|
||||
<MoreHorizontal class="w-4 h-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem :as-child="true">
|
||||
<RouterLink :to="{ name: 'edit-sso', params: { id: props.role.id } }">Edit</RouterLink>
|
||||
<RouterLink :to="{ name: 'edit-sso', params: { id: props.role.id } }">
|
||||
{{ $t('globals.buttons.edit') }}
|
||||
</RouterLink>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="() => (alertOpen = true)">Delete</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="() => (alertOpen = true)">{{
|
||||
$t('globals.buttons.delete')
|
||||
}}</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<AlertDialog :open="alertOpen" @update:open="alertOpen = $event">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete OIDC Provider</AlertDialogTitle>
|
||||
<AlertDialogTitle>{{ $t('globals.messages.areYouAbsolutelySure') }}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete the OIDC provider
|
||||
configuration.
|
||||
{{ $t('admin.sso.deleteConfirmation') }}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction @click="handleDelete">Delete</AlertDialogAction>
|
||||
<AlertDialogCancel>{{ $t('globals.buttons.cancel') }}</AlertDialogCancel>
|
||||
<AlertDialogAction @click="handleDelete">
|
||||
{{ $t('globals.buttons.delete') }}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
@@ -1,20 +1,24 @@
|
||||
import * as z from 'zod'
|
||||
|
||||
export const oidcLoginFormSchema = z.object({
|
||||
export const createFormSchema = (t) => z.object({
|
||||
disabled: z.boolean().optional(),
|
||||
name: z.string({
|
||||
required_error: 'Name is required.'
|
||||
required_error: t('globals.messages.required'),
|
||||
}),
|
||||
provider: z.string().optional(),
|
||||
provider_url: z
|
||||
.string({
|
||||
required_error: 'Provider URL is required.'
|
||||
required_error: t('globals.messages.required'),
|
||||
})
|
||||
.url({
|
||||
message: 'Provider URL must be a valid URL.'
|
||||
message: t('form.error.validUrl'),
|
||||
}),
|
||||
client_id: z.string(),
|
||||
client_secret: z.string(),
|
||||
client_id: z.string({
|
||||
required_error: t('globals.messages.required'),
|
||||
}),
|
||||
client_secret: z.string({
|
||||
required_error: t('globals.messages.required'),
|
||||
}),
|
||||
redirect_uri: z.string().readonly().optional(),
|
||||
enabled: z.boolean().default(true).optional(),
|
||||
})
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<div class="mb-5">
|
||||
<CustomBreadcrumb :links="breadcrumbLinks" />
|
||||
</div>
|
||||
<Spinner v-if="isLoading"></Spinner>
|
||||
<Spinner v-if="isLoading" />
|
||||
<OIDCForm
|
||||
:initial-values="oidc"
|
||||
:submitForm="submitForm"
|
||||
@@ -21,9 +21,11 @@ import { CustomBreadcrumb } from '@/components/ui/breadcrumb'
|
||||
import { EMITTER_EVENTS } from '@/constants/emitterEvents.js'
|
||||
import { useEmitter } from '@/composables/useEmitter'
|
||||
import { handleHTTPError } from '@/utils/http'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const oidc = ref({
|
||||
provider: 'Google'
|
||||
})
|
||||
@@ -47,7 +49,6 @@ const submitForm = async (values) => {
|
||||
} catch (error) {
|
||||
formLoading.value = false
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
@@ -61,37 +62,32 @@ const submitForm = async (values) => {
|
||||
values.client_secret = ''
|
||||
}
|
||||
await api.updateOIDC(props.id, values)
|
||||
toastDescription = 'Provider updated successfully'
|
||||
toastDescription = t('globals.messages.updatedSuccessfully', {
|
||||
name: t('globals.entities.provider')
|
||||
})
|
||||
} else {
|
||||
await api.createOIDC(values)
|
||||
router.push({ name: 'sso-list' })
|
||||
toastDescription = 'Provider created successfully'
|
||||
toastDescription = t('globals.messages.createdSuccessfully', {
|
||||
name: t('globals.entities.provider')
|
||||
})
|
||||
}
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Success',
|
||||
description: toastDescription
|
||||
})
|
||||
} catch (error) {
|
||||
if (props.id) {
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error reloading OIDC providers',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
} else {
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
}
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const breadCrumLabel = () => {
|
||||
return props.id ? 'Edit' : 'New'
|
||||
return props.id ? t('globals.buttons.edit') : t('globals.buttons.new')
|
||||
}
|
||||
|
||||
const isNewForm = computed(() => {
|
||||
@@ -99,7 +95,7 @@ const isNewForm = computed(() => {
|
||||
})
|
||||
|
||||
const breadcrumbLinks = [
|
||||
{ path: 'sso-list', label: 'SSO' },
|
||||
{ path: 'sso-list', label: t('globals.entities.sso') },
|
||||
{ path: '', label: breadCrumLabel() }
|
||||
]
|
||||
|
||||
@@ -111,7 +107,6 @@ onMounted(async () => {
|
||||
oidc.value = resp.data.data
|
||||
} catch (error) {
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
|
@@ -5,12 +5,16 @@
|
||||
<div></div>
|
||||
<div>
|
||||
<RouterLink :to="{ name: 'new-sso' }">
|
||||
<Button>New SSO</Button>
|
||||
<Button>{{
|
||||
$t('globals.messages.new', {
|
||||
name: $t('globals.entities.sso')
|
||||
})
|
||||
}}</Button>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<DataTable :columns="columns" :data="oidc" />
|
||||
<DataTable :columns="createColumns(t)" :data="oidc" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -18,15 +22,16 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import DataTable from '@/components/datatable/DataTable.vue'
|
||||
import { columns } from '@/features/admin/oidc/dataTableColumns.js'
|
||||
import { createColumns } from '@/features/admin/oidc/dataTableColumns.js'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useEmitter } from '@/composables/useEmitter'
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Spinner } from '@/components/ui/spinner'
|
||||
import { EMITTER_EVENTS } from '@/constants/emitterEvents.js'
|
||||
import api from '@/api'
|
||||
|
||||
const oidc = ref([])
|
||||
const { t } = useI18n()
|
||||
const isLoading = ref(false)
|
||||
const emit = useEmitter()
|
||||
|
||||
|
10
i18n/en.json
10
i18n/en.json
@@ -48,6 +48,7 @@
|
||||
"globals.entities.view": "View | Views",
|
||||
"globals.entities.email": "Email | Emails",
|
||||
"globals.entities.condition": "Condition | Conditions",
|
||||
"globals.entities.sso": "SSO | SSOs",
|
||||
"globals.messages.adjustFilters": "Try adjusting your filters",
|
||||
"globals.messages.errorUploadingFile": "Error uploading file",
|
||||
"globals.messages.errorUpdating": "Error updating {name}",
|
||||
@@ -218,6 +219,11 @@
|
||||
"navigation.edit": "Edit",
|
||||
"navigation.delete": "Delete",
|
||||
"form.field.name": "Name",
|
||||
"form.field.provider": "Provider",
|
||||
"form.field.providerURL": "Provider URL",
|
||||
"form.field.clientID": "Client ID",
|
||||
"form.field.clientSecret": "Client Secret",
|
||||
"form.field.callbackURL": "Callback URL",
|
||||
"form.field.subject": "Subject",
|
||||
"form.field.isDefault": "Is default",
|
||||
"form.field.body": "Body",
|
||||
@@ -254,6 +260,7 @@
|
||||
"form.field.selectTeam": "Select team",
|
||||
"form.field.selectTag": "Select tag",
|
||||
"form.field.selectAction": "Select action",
|
||||
"form.field.selectProvider": "Select provider",
|
||||
"form.field.selectUser": "Select user",
|
||||
"form.field.selectValue": "Select value",
|
||||
"form.field.selectTeams": "Select teams",
|
||||
@@ -268,6 +275,7 @@
|
||||
"form.error.name.required": "Name is required",
|
||||
"form.error.description.required": "Description is required",
|
||||
"form.error.time.invalid": "Invalid time format (HH:mm)",
|
||||
"form.error.validUrl": "Invalid URL",
|
||||
"admin.general.updated": "Settings updated successfully",
|
||||
"admin.general.site_name": "Site Name",
|
||||
"admin.general.site_name.description": "Name for your support desk.",
|
||||
@@ -488,6 +496,8 @@
|
||||
"admin.template.deleteConfirmation": "This action cannot be undone. This will permanently delete this template.",
|
||||
"admin.template.makeSureTemplateHasContent": "Make sure the template has {content} only once.",
|
||||
"admin.template.onlyOneDefaultOutgoingTemplate": "You can have only one default outgoing email template.",
|
||||
"admin.sso.deleteConfirmation": "This action cannot be undone. This will permanently delete this SSO configuration.",
|
||||
"admin.sso.setThisUrlForCallback": "Set this URI for callback.",
|
||||
"globals.buttons.save": "Save",
|
||||
"globals.buttons.save_changes": "Save changes",
|
||||
"globals.buttons.cancel": "Cancel",
|
||||
|
Reference in New Issue
Block a user