i18n-dashboard 0.13.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +3 -0
  2. package/package.json +1 -1
  3. package/src/components/GitRepoManager.vue +4 -4
  4. package/src/components/ScanModal.vue +3 -3
  5. package/src/components/TranslationRow.vue +1 -1
  6. package/src/components/dashboard/WidgetConfigModal.vue +6 -5
  7. package/src/components/dashboard/WidgetGrid.vue +2 -2
  8. package/src/components/dashboard/WidgetPicker.vue +6 -5
  9. package/src/components/dashboard/widgets/ActivityWidget.vue +4 -3
  10. package/src/components/dashboard/widgets/LanguagesCoverageWidget.vue +4 -3
  11. package/src/components/dashboard/widgets/ProjectsWidget.vue +2 -2
  12. package/src/components/dashboard/widgets/ReviewWidget.vue +5 -4
  13. package/src/components/dashboard/widgets/StatWidget.vue +5 -4
  14. package/src/composables/useAuth.ts +2 -10
  15. package/src/composables/useDashboard.ts +7 -7
  16. package/src/composables/useKeys.ts +3 -3
  17. package/src/composables/useLanguages.ts +6 -6
  18. package/src/composables/useProfile.ts +1 -1
  19. package/src/composables/useProject.ts +8 -23
  20. package/src/composables/useReview.ts +5 -12
  21. package/src/composables/useSettings.ts +2 -2
  22. package/src/composables/useStats.ts +2 -2
  23. package/src/composables/useUsers.ts +3 -3
  24. package/src/composables/useWidgetData.ts +2 -2
  25. package/src/consts/commons.const.ts +20 -5
  26. package/src/consts/dashboard.const.ts +6 -5
  27. package/src/consts/languages.const.ts +2 -2
  28. package/src/consts/translation-job.const.ts +2 -0
  29. package/src/enums/translation-job.enum.ts +5 -0
  30. package/src/interfaces/auth.interface.ts +8 -0
  31. package/src/interfaces/commons.interface.ts +9 -9
  32. package/src/interfaces/dashboard.interface.ts +12 -0
  33. package/src/interfaces/job.interface.ts +1 -1
  34. package/src/interfaces/key.interface.ts +8 -8
  35. package/src/interfaces/languages.interface.ts +3 -3
  36. package/src/{server/interfaces → interfaces}/profile.interface.ts +9 -9
  37. package/src/{server/interfaces → interfaces}/project-config.interface.ts +1 -1
  38. package/src/interfaces/project-snapshot.interface.ts +26 -0
  39. package/src/interfaces/project.interface.ts +18 -3
  40. package/src/interfaces/review.interface.ts +7 -0
  41. package/src/interfaces/scan.interface.ts +2 -2
  42. package/src/{server/interfaces → interfaces}/scanner.interface.ts +4 -4
  43. package/src/interfaces/settings.interface.ts +1 -1
  44. package/src/interfaces/stat.interface.ts +5 -5
  45. package/src/{server/interfaces → interfaces}/translation-job.interface.ts +3 -3
  46. package/src/interfaces/translation.interface.ts +2 -2
  47. package/src/interfaces/user.interface.ts +3 -3
  48. package/src/pages/projects/[id]/review.vue +1 -1
  49. package/src/pages/projects/[id]/translations/index.vue +1 -1
  50. package/src/pages/projects/[id]/users.vue +4 -4
  51. package/src/server/api/auth/login.post.ts +1 -1
  52. package/src/server/api/auth/logout.post.ts +1 -1
  53. package/src/server/api/auth/me.get.ts +1 -1
  54. package/src/server/api/auth/me.put.ts +1 -1
  55. package/src/server/api/auth/password.put.ts +1 -1
  56. package/src/server/api/auth/refresh.post.ts +1 -1
  57. package/src/server/api/auth/status.get.ts +1 -1
  58. package/src/server/api/config.get.ts +1 -1
  59. package/src/server/api/dashboard/layout.get.ts +1 -1
  60. package/src/server/api/dashboard/layout.post.ts +1 -1
  61. package/src/server/api/export.get.ts +1 -1
  62. package/src/server/api/languages/index.post.ts +1 -1
  63. package/src/server/api/onboarding.post.ts +1 -1
  64. package/src/server/api/profile.get.ts +2 -2
  65. package/src/server/api/project-snapshot.post.ts +2 -28
  66. package/src/server/api/projects/detect.post.ts +1 -1
  67. package/src/server/api/scan.post.ts +1 -1
  68. package/src/server/api/setup.post.ts +1 -1
  69. package/src/server/api/stats/global.get.ts +1 -1
  70. package/src/server/api/translations/bulk-status.post.ts +1 -1
  71. package/src/server/api/translations/index.post.ts +1 -1
  72. package/src/server/api/translations/job/[id].get.ts +1 -1
  73. package/src/server/api/translations/status.post.ts +1 -1
  74. package/src/server/api/translations/translate-all.post.ts +1 -1
  75. package/src/server/api/users/[id]/profile.get.ts +3 -3
  76. package/src/server/api/users/[id]/roles.put.ts +1 -1
  77. package/src/server/api/users/[id].delete.ts +1 -1
  78. package/src/server/api/users/[id].put.ts +1 -1
  79. package/src/server/api/users/index.get.ts +1 -1
  80. package/src/server/api/users/index.post.ts +2 -2
  81. package/src/server/consts/commons.const.ts +5 -20
  82. package/src/server/db/index.ts +4 -4
  83. package/src/server/middleware/auth.ts +2 -2
  84. package/src/server/routes/locale/[lang].get.ts +1 -1
  85. package/src/server/utils/auth.util.ts +10 -10
  86. package/src/server/utils/auto-translate.util.ts +1 -1
  87. package/src/server/utils/project-config.util.ts +3 -3
  88. package/src/server/utils/{scanner.uti.ts → scanner.util.ts} +13 -13
  89. package/src/server/utils/translation-job.util.ts +14 -13
  90. package/src/services/auth.service.ts +10 -10
  91. package/src/services/base.service.ts +13 -13
  92. package/src/services/job.service.ts +6 -6
  93. package/src/services/key.service.ts +10 -10
  94. package/src/services/language.service.ts +8 -8
  95. package/src/services/profile.service.ts +8 -8
  96. package/src/services/project.service.ts +11 -11
  97. package/src/services/scan.service.ts +8 -8
  98. package/src/services/settings.service.ts +5 -5
  99. package/src/services/stats.service.ts +6 -6
  100. package/src/services/translation.service.ts +6 -6
  101. package/src/services/user.service.ts +10 -10
  102. package/src/types/auth.type.ts +3 -0
  103. package/src/types/commons.type.ts +1 -1
  104. package/src/types/dashboard.type.ts +5 -15
  105. package/src/consts/commons.const.js +0 -6
  106. package/src/server/consts/translation-job.const.ts +0 -8
  107. package/src/server/types/auth.type.ts +0 -3
  108. /package/src/{server/consts → consts}/auto-translate.const.ts +0 -0
  109. /package/src/{server/consts → consts}/scanner.const.ts +0 -0
  110. /package/src/{server/enums → enums}/auth.enum.ts +0 -0
  111. /package/src/{server/enums → enums}/translation.enum.ts +0 -0
  112. /package/src/{server/utils → utils}/lang-api.util.ts +0 -0
package/README.md CHANGED
@@ -94,3 +94,6 @@ Open an issue or discussion!
94
94
  ## 📄 License
95
95
 
96
96
  MIT
97
+
98
+ ---
99
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18n-dashboard",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "A web dashboard to manage vue-i18n translation keys with database persistence",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,19 +15,19 @@
15
15
  </template>
16
16
 
17
17
  <script setup lang="ts">
18
- import type { GitRepo } from '~/interfaces/project.interface'
18
+ import type { IGitRepo } from '~/interfaces/project.interface'
19
19
 
20
20
  const { t } = useT()
21
21
 
22
22
  const props = defineProps<{
23
- modelValue: GitRepo | null | undefined
23
+ modelValue: IGitRepo | null | undefined
24
24
  }>()
25
25
 
26
26
  const emit = defineEmits<{
27
- 'update:modelValue': [value: GitRepo | null]
27
+ 'update:modelValue': [value: IGitRepo | null]
28
28
  }>()
29
29
 
30
- const local = reactive<GitRepo>({ url: '', branch: '', token: '' })
30
+ const local = reactive<IGitRepo>({ url: '', branch: '', token: '' })
31
31
 
32
32
  watch(() => props.modelValue, (val) => {
33
33
  local.url = val?.url ?? ''
@@ -96,13 +96,13 @@
96
96
  </template>
97
97
 
98
98
  <script setup lang="ts">
99
- import type { GitRepo } from '~/interfaces/project.interface'
99
+ import type { IGitRepo } from '~/interfaces/project.interface'
100
100
 
101
101
  const { t } = useT()
102
102
 
103
103
  const props = defineProps<{
104
104
  projectId: number
105
- project?: { languages?: { code: string; name: string }[]; root_path?: string; git_repo?: GitRepo | null }
105
+ project?: { languages?: { code: string; name: string }[]; root_path?: string; git_repo?: IGitRepo | null }
106
106
  }>()
107
107
 
108
108
  const emit = defineEmits<{ done: [] }>()
@@ -111,7 +111,7 @@ const open = defineModel<boolean>('open', { default: false })
111
111
 
112
112
  const mode = ref<'local' | 'git'>('local')
113
113
  const localPath = ref(props.project?.root_path ?? '')
114
- const gitRepo = ref<GitRepo | null>(null)
114
+ const gitRepo = ref<IGitRepo | null>(null)
115
115
  const saveRepo = ref(false)
116
116
  const loading = ref(false)
117
117
  const result = ref<any>(null)
@@ -218,7 +218,7 @@
218
218
  </template>
219
219
 
220
220
  <script setup lang="ts">
221
- import { TRANSLATION_STATUS } from '../server/enums/translation.enum'
221
+ import { TRANSLATION_STATUS } from '~/enums/translation.enum'
222
222
 
223
223
  const { t } = useT()
224
224
 
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import type { PropType } from 'vue'
3
- import type { WidgetConfig, WidgetDataSource, DataSourceType } from '~/types/dashboard.type'
3
+ import type { TDataSourceType } from '~/types/dashboard.type'
4
+ import type { IWidgetConfig, IWidgetDataSource } from '~/interfaces/dashboard.interface'
4
5
  import { WIDGET_REGISTRY } from '~/consts/dashboard.const'
5
6
 
6
7
  const props = defineProps({
@@ -9,7 +10,7 @@ const props = defineProps({
9
10
  required: true,
10
11
  },
11
12
  widget: {
12
- type: Object as PropType<WidgetConfig | null>,
13
+ type: Object as PropType<IWidgetConfig | null>,
13
14
  default: null,
14
15
  },
15
16
  index: {
@@ -20,13 +21,13 @@ const props = defineProps({
20
21
 
21
22
  const emit = defineEmits<{
22
23
  (e: 'update:open', value: boolean): void
23
- (e: 'save', value: { dataSource: WidgetDataSource | undefined; title: string | undefined }): void
24
+ (e: 'save', value: { dataSource: IWidgetDataSource | undefined; title: string | undefined }): void
24
25
  }>()
25
26
 
26
27
  const { t } = useT()
27
28
  const { visibleProjects } = useProject()
28
29
 
29
- const draftSource = ref<DataSourceType>('global')
30
+ const draftSource = ref<TDataSourceType>('global')
30
31
  const draftProjectId = ref<number | undefined>()
31
32
  const draftTitle = ref('')
32
33
 
@@ -53,7 +54,7 @@ const hasDataSource = computed(() => {
53
54
  })
54
55
 
55
56
  function save() {
56
- const dataSource: WidgetDataSource = draftSource.value === 'project'
57
+ const dataSource: IWidgetDataSource = draftSource.value === 'project'
57
58
  ? { type: 'project', projectId: draftProjectId.value }
58
59
  : { type: 'global' }
59
60
  emit('save', { dataSource, title: draftTitle.value || undefined })
@@ -1,5 +1,5 @@
1
1
  <script lang="ts" setup>
2
- import type { WidgetType } from '~/types/dashboard.type'
2
+ import type { TWidgetType } from '~/types/dashboard.type'
3
3
  import { WIDGET_REGISTRY, WIDGET_SIZE_CLASSES } from '~/consts/dashboard.const'
4
4
 
5
5
  const { t } = useT()
@@ -30,7 +30,7 @@ function sizeClass(size: string) {
30
30
  return WIDGET_SIZE_CLASSES[size as keyof typeof WIDGET_SIZE_CLASSES] ?? 'col-span-1 row-span-1'
31
31
  }
32
32
 
33
- function widgetComponent(type: WidgetType) {
33
+ function widgetComponent(type: TWidgetType) {
34
34
  switch (type) {
35
35
  case 'stat-keys':
36
36
  case 'stat-coverage':
@@ -1,5 +1,6 @@
1
1
  <script lang="ts" setup>
2
- import type { WidgetConfig, WidgetSize } from '~/types/dashboard.type'
2
+ import type { TWidgetSize } from '~/types/dashboard.type'
3
+ import type { IWidgetConfig } from '~/interfaces/dashboard.interface'
3
4
  import { WIDGET_REGISTRY } from '~/consts/dashboard.const'
4
5
 
5
6
  const { t } = useT()
@@ -10,7 +11,7 @@ const props = defineProps<{
10
11
 
11
12
  const emit = defineEmits<{
12
13
  'update:modelValue': [value: boolean]
13
- 'add': [widget: WidgetConfig]
14
+ 'add': [widget: IWidgetConfig]
14
15
  }>()
15
16
 
16
17
  const open = computed({
@@ -18,16 +19,16 @@ const open = computed({
18
19
  set: (v) => emit('update:modelValue', v),
19
20
  })
20
21
 
21
- const selectedSizes = ref<Record<string, WidgetSize>>({})
22
+ const selectedSizes = ref<Record<string, TWidgetSize>>({})
22
23
 
23
- function getSelectedSize(type: string): WidgetSize {
24
+ function getSelectedSize(type: string): TWidgetSize {
24
25
  return selectedSizes.value[type] ?? WIDGET_REGISTRY[type as keyof typeof WIDGET_REGISTRY].defaultSize
25
26
  }
26
27
 
27
28
  function addWidget(type: string) {
28
29
  const size = getSelectedSize(type)
29
30
  const id = Date.now().toString(36)
30
- emit('add', { id, type: type as WidgetConfig['type'], size })
31
+ emit('add', { id, type: type as IWidgetConfig['type'], size })
31
32
  open.value = false
32
33
  }
33
34
  </script>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import type { PropType } from 'vue'
3
- import type { WidgetSize, WidgetDataSource } from '~/types/dashboard.type'
3
+ import type { TWidgetSize } from '~/types/dashboard.type'
4
+ import type { IWidgetDataSource } from '~/interfaces/dashboard.interface'
4
5
 
5
6
  const props = defineProps({
6
7
  id: {
@@ -8,7 +9,7 @@ const props = defineProps({
8
9
  required: true,
9
10
  },
10
11
  size: {
11
- type: String as PropType<WidgetSize>,
12
+ type: String as PropType<TWidgetSize>,
12
13
  required: true,
13
14
  },
14
15
  editing: {
@@ -16,7 +17,7 @@ const props = defineProps({
16
17
  required: true,
17
18
  },
18
19
  dataSource: {
19
- type: Object as PropType<WidgetDataSource | undefined>,
20
+ type: Object as PropType<IWidgetDataSource | undefined>,
20
21
  default: undefined,
21
22
  },
22
23
  title: {
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import type { PropType } from 'vue'
3
- import type { WidgetSize, WidgetDataSource } from '~/types/dashboard.type'
3
+ import type { TWidgetSize } from '~/types/dashboard.type'
4
+ import type { IWidgetDataSource } from '~/interfaces/dashboard.interface'
4
5
 
5
6
  const props = defineProps({
6
7
  id: {
@@ -8,7 +9,7 @@ const props = defineProps({
8
9
  required: true,
9
10
  },
10
11
  size: {
11
- type: String as PropType<WidgetSize>,
12
+ type: String as PropType<TWidgetSize>,
12
13
  required: true,
13
14
  },
14
15
  editing: {
@@ -16,7 +17,7 @@ const props = defineProps({
16
17
  required: true,
17
18
  },
18
19
  dataSource: {
19
- type: Object as PropType<WidgetDataSource | undefined>,
20
+ type: Object as PropType<IWidgetDataSource | undefined>,
20
21
  default: undefined,
21
22
  },
22
23
  title: {
@@ -1,8 +1,8 @@
1
1
  <script lang="ts" setup>
2
- import type { WidgetSize } from '~/types/dashboard.type'
2
+ import type { TWidgetSize } from '~/types/dashboard.type'
3
3
 
4
4
  const props = defineProps<{
5
- size: WidgetSize
5
+ size: TWidgetSize
6
6
  editing: boolean
7
7
  }>()
8
8
 
@@ -1,7 +1,8 @@
1
1
  <script lang="ts" setup>
2
2
  import type { PropType } from 'vue'
3
- import type { WidgetSize, WidgetDataSource } from '~/types/dashboard.type'
4
- import { TRANSLATION_STATUS } from '~/server/enums/translation.enum'
3
+ import type { TWidgetSize } from '~/types/dashboard.type'
4
+ import type { IWidgetDataSource } from '~/interfaces/dashboard.interface'
5
+ import { TRANSLATION_STATUS } from '~/enums/translation.enum'
5
6
 
6
7
  const props = defineProps({
7
8
  id: {
@@ -9,7 +10,7 @@ const props = defineProps({
9
10
  required: true,
10
11
  },
11
12
  size: {
12
- type: String as PropType<WidgetSize>,
13
+ type: String as PropType<TWidgetSize>,
13
14
  required: true,
14
15
  },
15
16
  editing: {
@@ -17,7 +18,7 @@ const props = defineProps({
17
18
  required: true,
18
19
  },
19
20
  dataSource: {
20
- type: Object as PropType<WidgetDataSource | undefined>,
21
+ type: Object as PropType<IWidgetDataSource | undefined>,
21
22
  default: undefined,
22
23
  },
23
24
  title: {
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import type { PropType } from 'vue'
3
- import type { WidgetType, WidgetSize, WidgetDataSource } from '~/types/dashboard.type'
3
+ import type { TWidgetType, TWidgetSize } from '~/types/dashboard.type'
4
+ import type { IWidgetDataSource } from '~/interfaces/dashboard.interface'
4
5
 
5
6
  const props = defineProps({
6
7
  id: {
@@ -8,11 +9,11 @@ const props = defineProps({
8
9
  required: true,
9
10
  },
10
11
  type: {
11
- type: String as PropType<WidgetType>,
12
+ type: String as PropType<TWidgetType>,
12
13
  required: true,
13
14
  },
14
15
  size: {
15
- type: String as PropType<WidgetSize>,
16
+ type: String as PropType<TWidgetSize>,
16
17
  required: true,
17
18
  },
18
19
  editing: {
@@ -20,7 +21,7 @@ const props = defineProps({
20
21
  required: true,
21
22
  },
22
23
  dataSource: {
23
- type: Object as PropType<WidgetDataSource | undefined>,
24
+ type: Object as PropType<IWidgetDataSource | undefined>,
24
25
  default: undefined,
25
26
  },
26
27
  title: {
@@ -1,15 +1,7 @@
1
1
  import { authService } from '../services/auth.service'
2
+ import type { IAuthUser } from '../interfaces/auth.interface'
2
3
 
3
- export interface AuthUser {
4
- id: number
5
- email: string
6
- name: string
7
- is_super_admin: boolean
8
- is_active: boolean
9
- roles: Array<{ role: string; project_id: number | null; project_name?: string }>
10
- }
11
-
12
- const _currentUser = ref<AuthUser | null>(null)
4
+ const _currentUser = ref<IAuthUser | null>(null)
13
5
 
14
6
  export function useAuth() {
15
7
  const currentUser = _currentUser
@@ -1,13 +1,13 @@
1
- import type { WidgetConfig, WidgetDataSource } from '../types/dashboard.type'
2
- import type { WidgetSize } from '../types/dashboard.type'
1
+ import type { IWidgetConfig, IWidgetDataSource } from '../interfaces/dashboard.interface'
2
+ import type { TWidgetSize } from '../types/dashboard.type'
3
3
  import { DEFAULT_LAYOUT } from '../consts/dashboard.const'
4
4
 
5
5
  export function useDashboard() {
6
6
  const { data, refresh } = useAsyncData('dashboard-layout', () => $fetch('/api/dashboard/layout'), { server: false })
7
- const layout = computed<WidgetConfig[]>(() => (data.value as WidgetConfig[]) ?? DEFAULT_LAYOUT)
7
+ const layout = computed<IWidgetConfig[]>(() => (data.value as IWidgetConfig[]) ?? DEFAULT_LAYOUT)
8
8
 
9
9
  const editing = ref(false)
10
- const localLayout = ref<WidgetConfig[]>([])
10
+ const localLayout = ref<IWidgetConfig[]>([])
11
11
 
12
12
  function startEditing() {
13
13
  localLayout.value = [...layout.value]
@@ -38,15 +38,15 @@ export function useDashboard() {
38
38
  localLayout.value.splice(index, 1)
39
39
  }
40
40
 
41
- function addWidget(widget: WidgetConfig) {
41
+ function addWidget(widget: IWidgetConfig) {
42
42
  localLayout.value.push(widget)
43
43
  }
44
44
 
45
- function resizeWidget(index: number, size: WidgetSize) {
45
+ function resizeWidget(index: number, size: TWidgetSize) {
46
46
  localLayout.value[index].size = size
47
47
  }
48
48
 
49
- function updateWidgetConfig(index: number, patch: { dataSource?: WidgetDataSource | undefined; title?: string | undefined }) {
49
+ function updateWidgetConfig(index: number, patch: { dataSource?: IWidgetDataSource | undefined; title?: string | undefined }) {
50
50
  if (index < 0 || index >= localLayout.value.length) return
51
51
  localLayout.value[index] = { ...localLayout.value[index], ...patch }
52
52
  }
@@ -1,10 +1,10 @@
1
1
  import { keyService } from '../services/key.service'
2
2
  import { translationService } from '../services/translation.service'
3
3
  import { scanService } from '../services/scan.service'
4
- import type { KeysQuery, KeysResponse } from '../services/key.service'
4
+ import type { IKeysQuery, IKeysResponse } from '../interfaces/key.interface'
5
5
 
6
6
  export function useKeys(options: {
7
- queryParams?: Ref<KeysQuery>
7
+ queryParams?: Ref<IKeysQuery>
8
8
  id?: Ref<string | string[]>
9
9
  } = {}) {
10
10
  const toast = useToast()
@@ -14,7 +14,7 @@ export function useKeys(options: {
14
14
 
15
15
  // ── List mode ─────────────────────────────────────────────────────────────
16
16
 
17
- const data = ref<KeysResponse | null>(null)
17
+ const data = ref<IKeysResponse | null>(null)
18
18
  const listPending = ref(false)
19
19
 
20
20
  async function refresh() {
@@ -2,7 +2,7 @@ import { LANGUAGES } from '../consts/languages.const'
2
2
  import { languageService } from '../services/language.service'
3
3
  import { translationService } from '../services/translation.service'
4
4
  import { jobService } from '../services/job.service'
5
- import type { Language, LanguageItem, CreateLanguagePayload } from '../interfaces/languages.interface'
5
+ import type { ILanguage, ILanguageItem, ICreateLanguagePayload } from '../interfaces/languages.interface'
6
6
 
7
7
  // ── Static language lookup ───────────────────────────────────────────────────
8
8
 
@@ -25,7 +25,7 @@ export function useLanguages() {
25
25
  )
26
26
  })
27
27
 
28
- function findLanguage(code: string): Language | undefined {
28
+ function findLanguage(code: string): ILanguage | undefined {
29
29
  // Exact match first, then fall back to base language (fr-CA → fr)
30
30
  return LANGUAGES.find(l => l.code === code)
31
31
  ?? LANGUAGES.find(l => l.code === code.split('-')[0])
@@ -38,7 +38,7 @@ export function useLanguages() {
38
38
 
39
39
  // ── Project languages (API) ──────────────────────────────────────────────
40
40
 
41
- const data = ref<LanguageItem[]>([])
41
+ const data = ref<ILanguageItem[]>([])
42
42
  const pending = ref(false)
43
43
 
44
44
  async function refresh() {
@@ -60,7 +60,7 @@ export function useLanguages() {
60
60
  const projectLanguages = computed(() => data.value ?? [])
61
61
 
62
62
  const adding = ref(false)
63
- async function addLanguage(payload: Omit<CreateLanguagePayload, 'project_id'>): Promise<void> {
63
+ async function addLanguage(payload: Omit<ICreateLanguagePayload, 'project_id'>): Promise<void> {
64
64
  if (!currentProject.value) return
65
65
  adding.value = true
66
66
  try {
@@ -88,7 +88,7 @@ export function useLanguages() {
88
88
  }
89
89
  }
90
90
 
91
- async function setDefault(lang: LanguageItem): Promise<void> {
91
+ async function setDefault(lang: ILanguageItem): Promise<void> {
92
92
  if (!currentProject.value) return
93
93
  try {
94
94
  await languageService.setDefault(lang, currentProject.value.id)
@@ -97,7 +97,7 @@ export function useLanguages() {
97
97
  catch {}
98
98
  }
99
99
 
100
- async function setFallback(lang: LanguageItem, fallbackCode: string | null): Promise<void> {
100
+ async function setFallback(lang: ILanguageItem, fallbackCode: string | null): Promise<void> {
101
101
  await $fetch(`/api/languages/${lang.id}`, {
102
102
  method: 'PUT',
103
103
  body: { fallback_code: fallbackCode },
@@ -1,7 +1,7 @@
1
1
  import { profileService } from '../services/profile.service'
2
2
  import { authService } from '../services/auth.service'
3
3
  import { userService } from '../services/user.service'
4
- import type { ProfilePeriod } from '../server/interfaces/profile.interface'
4
+ import type { ProfilePeriod } from '~/interfaces/profile.interface'
5
5
 
6
6
  export function useProfile(userId?: MaybeRefOrGetter<number | string>) {
7
7
  const toast = useToast()
@@ -1,28 +1,13 @@
1
1
  import { projectService } from '~/services/project.service'
2
2
  import { scanService } from '~/services/scan.service'
3
- import type { ProjectPayload } from '~/interfaces/project.interface'
4
-
5
- export interface Project {
6
- id: number
7
- name: string
8
- root_path: string
9
- source_url?: string
10
- locales_path: string
11
- key_separator: string
12
- color: string
13
- description?: string
14
- key_count?: number
15
- language_count?: number
16
- is_system?: boolean
17
- git_repo?: { name?: string; url: string; branch?: string; token?: string } | null
18
- }
3
+ import type { IProject, IProjectPayload } from '~/interfaces/project.interface'
19
4
 
20
- export function canScanProject(project: Project): boolean {
5
+ export function canScanProject(project: IProject): boolean {
21
6
  if (project.root_path && project.root_path !== '__DASHBOARD_UI__') return true
22
7
  return !!project.git_repo?.url
23
8
  }
24
9
 
25
- export function canSyncProject(project: Project): boolean {
10
+ export function canSyncProject(project: IProject): boolean {
26
11
  if (project.root_path && project.root_path !== '__DASHBOARD_UI__') return true
27
12
  return !!project.git_repo?.url
28
13
  }
@@ -36,20 +21,20 @@ export function canSyncProject(project: Project): boolean {
36
21
  export function useProject() {
37
22
  const { currentUser } = useAuth()
38
23
 
39
- const { data: projectsData, pending, refresh: fetchProjects } = useAsyncData<Project[]>(
24
+ const { data: projectsData, pending, refresh: fetchProjects } = useAsyncData<IProject[]>(
40
25
  'all-projects',
41
26
  () => projectService.getAll(),
42
27
  { default: () => [], server: false },
43
28
  )
44
29
 
45
- const projects = computed(() => (projectsData.value ?? []) as Project[])
30
+ const projects = computed(() => (projectsData.value ?? []) as IProject[])
46
31
 
47
32
  // Not route-dependent — safe to watch from anywhere (including layout onMount)
48
33
  const systemProject = computed(() => projects.value.find(p => p.is_system) ?? null)
49
34
 
50
35
  // Route-dependent: only returns a value when inside a /projects/[id]/* page
51
36
  const route = useRoute()
52
- const currentProject = computed((): Project | null => {
37
+ const currentProject = computed((): IProject | null => {
53
38
  const paramId = route.params.id
54
39
  if (!paramId) return null
55
40
  const id = Number(Array.isArray(paramId) ? paramId[0] : paramId)
@@ -73,7 +58,7 @@ export function useProject() {
73
58
  const router = useRouter()
74
59
 
75
60
  const saving = ref(false)
76
- async function createProject(payload: ProjectPayload): Promise<any> {
61
+ async function createProject(payload: IProjectPayload): Promise<any> {
77
62
  saving.value = true
78
63
  try {
79
64
  const project = await projectService.create(payload)
@@ -89,7 +74,7 @@ export function useProject() {
89
74
  }
90
75
  }
91
76
 
92
- async function updateProject(id: number, payload: Partial<ProjectPayload>): Promise<boolean> {
77
+ async function updateProject(id: number, payload: Partial<IProjectPayload>): Promise<boolean> {
93
78
  saving.value = true
94
79
  try {
95
80
  await projectService.update(id, payload)
@@ -1,14 +1,7 @@
1
1
  import { keyService } from '../services/key.service'
2
2
  import { translationService } from '../services/translation.service'
3
- import { TRANSLATION_STATUS } from '../server/enums/translation.enum'
4
-
5
- export interface ReviewItem {
6
- id: number
7
- key: string
8
- key_description?: string
9
- language_code: string
10
- value: string
11
- }
3
+ import { TRANSLATION_STATUS } from '~/enums/translation.enum'
4
+ import type { IReviewItem } from '../interfaces/review.interface'
12
5
 
13
6
  export function useReview() {
14
7
  const toast = useToast()
@@ -34,9 +27,9 @@ export function useReview() {
34
27
 
35
28
  watch(() => currentProject.value?.id, refresh, { immediate: true })
36
29
 
37
- const reviewItems = computed<ReviewItem[]>(() => {
30
+ const reviewItems = computed<IReviewItem[]>(() => {
38
31
  const keys = data.value?.data ?? []
39
- const result: ReviewItem[] = []
32
+ const result: IReviewItem[] = []
40
33
  for (const k of keys) {
41
34
  for (const [lang, tr] of Object.entries(k.translations as Record<string, any>)) {
42
35
  if (tr?.status === TRANSLATION_STATUS.DRAFT && tr?.value) {
@@ -50,7 +43,7 @@ export function useReview() {
50
43
  const processingId = ref<number | null>(null)
51
44
  const processingAction = ref('')
52
45
 
53
- async function setStatus(item: ReviewItem, status: TRANSLATION_STATUS): Promise<void> {
46
+ async function setStatus(item: IReviewItem, status: TRANSLATION_STATUS): Promise<void> {
54
47
  processingId.value = item.id
55
48
  processingAction.value = status
56
49
  try {
@@ -1,5 +1,5 @@
1
1
  import { settingsService } from '../services/settings.service'
2
- import type { SettingsPayload } from '../interfaces/settings.interface'
2
+ import type { ISettingsPayload } from '../interfaces/settings.interface'
3
3
 
4
4
  export function useSettings() {
5
5
  const toast = useToast()
@@ -26,7 +26,7 @@ export function useSettings() {
26
26
  const settings = computed(() => data.value ?? {})
27
27
 
28
28
  const saving = ref(false)
29
- async function saveSettings(payload: SettingsPayload): Promise<void> {
29
+ async function saveSettings(payload: ISettingsPayload): Promise<void> {
30
30
  saving.value = true
31
31
  try {
32
32
  await settingsService.saveSettings(payload)
@@ -1,10 +1,10 @@
1
1
  import { statsService } from '../services/stats.service'
2
- import type { StatsResponse } from '../services/stats.service'
2
+ import type { IStatsResponse } from '../interfaces/stat.interface'
3
3
 
4
4
  export function useStats() {
5
5
  const { currentProject } = useProject()
6
6
 
7
- const { data, pending, refresh } = useAsyncData<StatsResponse | null>(
7
+ const { data, pending, refresh } = useAsyncData<IStatsResponse | null>(
8
8
  'project-stats',
9
9
  () => statsService.getStats(currentProject.value?.id),
10
10
  { watch: [() => currentProject.value?.id] },
@@ -1,5 +1,5 @@
1
1
  import { userService } from '../services/user.service'
2
- import type { CreateUserPayload, RoleEntry } from '../interfaces/user.interface'
2
+ import type { ICreateUserPayload, IRoleEntry } from '../interfaces/user.interface'
3
3
 
4
4
  export function useUsers(scope: 'project' | 'global' = 'project') {
5
5
  const toast = useToast()
@@ -37,7 +37,7 @@ export function useUsers(scope: 'project' | 'global' = 'project') {
37
37
  // ── Mutations ──────────────────────────────────────────────────────────────
38
38
 
39
39
  const saving = ref(false)
40
- async function createUser(payload: CreateUserPayload): Promise<string | null> {
40
+ async function createUser(payload: ICreateUserPayload): Promise<string | null> {
41
41
  saving.value = true
42
42
  try {
43
43
  const result = await userService.create(payload)
@@ -56,7 +56,7 @@ export function useUsers(scope: 'project' | 'global' = 'project') {
56
56
  }
57
57
 
58
58
  const rolesSaving = ref(false)
59
- async function updateRoles(userId: number, roles: RoleEntry[]): Promise<boolean> {
59
+ async function updateRoles(userId: number, roles: IRoleEntry[]): Promise<boolean> {
60
60
  rolesSaving.value = true
61
61
  try {
62
62
  await userService.updateRoles(userId, roles)
@@ -1,7 +1,7 @@
1
1
  import type { Ref } from 'vue'
2
- import type { WidgetDataSource } from '~/types/dashboard.type'
2
+ import type { IWidgetDataSource } from '~/interfaces/dashboard.interface'
3
3
 
4
- export function useWidgetData(widgetId: string, dataSource: Ref<WidgetDataSource | undefined>) {
4
+ export function useWidgetData(widgetId: string, dataSource: Ref<IWidgetDataSource | undefined>) {
5
5
  const { currentProject, projects } = useProject()
6
6
 
7
7
  const effectiveSource = computed(() => dataSource.value ?? { type: 'global' as const })
@@ -1,6 +1,21 @@
1
- import { dirname } from 'path'
2
- import { fileURLToPath } from 'url'
1
+ export const PUBLIC_ROUTES = [
2
+ '/api/auth/login',
3
+ '/api/auth/logout',
4
+ '/api/auth/me',
5
+ '/api/auth/refresh',
6
+ '/api/auth/status',
7
+ '/api/setup',
8
+ '/api/ui-locale',
9
+ '/api/config',
10
+ // '/api/db-config' is intentionally NOT public — it can reconfigure and
11
+ // reset the entire database. It is accessible only during the onboarding
12
+ // wizard (before any user exists) via the auth middleware's setup-mode
13
+ // bypass, and requires super_admin authentication at all other times.
14
+ ]
3
15
 
4
- export const _dirname = typeof __dirname !== 'undefined'
5
- ? __dirname
6
- : dirname(fileURLToPath(import.meta.url))
16
+ // Routes accessible without authentication only while onboarding is incomplete
17
+ // (no users in the database yet). Once a super admin exists, these routes
18
+ // require a valid session.
19
+ export const SETUP_ONLY_ROUTES = [
20
+ '/api/db-config',
21
+ ]