@initsolusidigital/worksuite-shell 0.0.0-stage → 0.3.0

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 (75) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +122 -2
  3. package/package.json +44 -4
  4. package/src/components/ai/AppAssistantDraft.vue +120 -0
  5. package/src/components/ai/AppAssistantWidget.vue +245 -0
  6. package/src/components/ai/AppCitedAnswer.vue +86 -0
  7. package/src/components/approvals/AppApprovalInbox.vue +265 -0
  8. package/src/components/approvals/AppApprovalSubjectModal.vue +197 -0
  9. package/src/components/chat/AppChatBubble.vue +324 -0
  10. package/src/components/chat/AppChatList.vue +249 -0
  11. package/src/components/chat/AppChatPanel.vue +315 -0
  12. package/src/components/chat/AppChatWidget.vue +126 -0
  13. package/src/components/communications/AppChannelBadge.vue +47 -0
  14. package/src/components/communications/AppConversationThread.vue +439 -0
  15. package/src/components/customFields/CustomFieldFilterPanel.vue +50 -0
  16. package/src/components/customFields/CustomFieldInput.vue +422 -0
  17. package/src/components/customFields/CustomFieldValue.vue +129 -0
  18. package/src/components/customFields/CustomFieldsSection.vue +65 -0
  19. package/src/components/customFields/fieldTypes.js +23 -0
  20. package/src/components/dashboard/AppCustomWidget.vue +138 -0
  21. package/src/components/dashboard/AppCustomWidgetForm.vue +173 -0
  22. package/src/components/dashboard/AppDashboardGrid.vue +200 -0
  23. package/src/components/dashboard/AppDashboardToolbar.vue +66 -0
  24. package/src/components/dashboard/AppSubAppsCatalog.vue +89 -0
  25. package/src/components/dataTools/AppImportExport.vue +724 -0
  26. package/src/components/dataTools/AppImportSchemaGuide.vue +130 -0
  27. package/src/components/hrMetrics/AppHrMetricsDashboard.vue +231 -0
  28. package/src/components/hrMetrics/AppHrMetricsEmployees.vue +87 -0
  29. package/src/components/hrMetrics/AppHrMetricsStat.vue +61 -0
  30. package/src/components/kpi/AppKpiAppraisalConfig.vue +284 -0
  31. package/src/components/kpi/AppKpiAppraisals.vue +733 -0
  32. package/src/components/kpi/AppKpiDefinitionModal.vue +317 -0
  33. package/src/components/kpi/AppKpiEntryModal.vue +122 -0
  34. package/src/components/kpi/AppKpiLeaderboard.vue +108 -0
  35. package/src/components/kpi/AppKpiMyCard.vue +134 -0
  36. package/src/components/kpi/AppKpiPeriodPicker.vue +115 -0
  37. package/src/components/kpi/AppKpiReportTable.vue +214 -0
  38. package/src/components/kpi/AppKpiScorecard.vue +242 -0
  39. package/src/components/kpi/AppKpiTargetsModal.vue +299 -0
  40. package/src/components/kpi/AppKpiTeam.vue +221 -0
  41. package/src/components/kpi/AppKpiWeightProfiles.vue +244 -0
  42. package/src/components/kpi/AppKpiWorkspace.vue +479 -0
  43. package/src/components/layout/AppGlobalSearch.vue +149 -0
  44. package/src/components/layout/AppLanguagePopup.vue +94 -0
  45. package/src/components/layout/AppLauncherPopup.vue +147 -0
  46. package/src/components/layout/AppLegalConsentModal.vue +484 -0
  47. package/src/components/layout/AppNavbar.vue +402 -0
  48. package/src/components/layout/AppNotificationContent.vue +173 -0
  49. package/src/components/layout/AppNotificationDrawer.vue +98 -0
  50. package/src/components/layout/AppNotificationPopup.vue +67 -0
  51. package/src/components/layout/AppPlatformBanners.vue +192 -0
  52. package/src/components/layout/AppSidebar.vue +226 -0
  53. package/src/components/layout/AppSidebarNav.vue +119 -0
  54. package/src/components/layout/AppUserMenu.vue +89 -0
  55. package/src/components/layout/AppUserMenuContent.vue +59 -0
  56. package/src/composables/useKpi.js +232 -0
  57. package/src/composables/useLgViewport.js +25 -0
  58. package/src/composables/useNavigation.js +177 -0
  59. package/src/layouts/AppLayout.vue +207 -0
  60. package/src/locales/en.json +1362 -0
  61. package/src/locales/id.json +1396 -0
  62. package/src/pages/auth/AccountBlocked.vue +55 -0
  63. package/src/pages/auth/IdentityRedirect.vue +37 -0
  64. package/src/pages/profile/Layout.vue +210 -0
  65. package/src/pages/profile/partials/AccountSection.vue +139 -0
  66. package/src/pages/profile/partials/ApprovalDelegationSection.vue +389 -0
  67. package/src/pages/profile/partials/DevicesCard.vue +222 -0
  68. package/src/pages/profile/partials/PreferencesSection.vue +87 -0
  69. package/src/pages/profile/partials/SecuritySection.vue +93 -0
  70. package/src/pages/profile/partials/SessionsCard.vue +418 -0
  71. package/src/pages/profile/partials/SessionsSection.vue +58 -0
  72. package/src/pages/profile/partials/SupportAccessSection.vue +173 -0
  73. package/src/pages/profile/partials/TrustedDevicesCard.vue +141 -0
  74. package/src/pages/profile/partials/TwoFactorSection.vue +304 -0
  75. package/src/shellSetup.js +46 -0
@@ -0,0 +1,89 @@
1
+ <script setup>
2
+ // Kartu Sub App di Dashboard. Dipasang renderer widget tiap app di
3
+ // dalam kartu widget `subApps`-nya; data & aturan klik sepenuhnya di sini, jadi perubahan aturan
4
+ // status app cukup di satu berkas, bukan di widget tiap app.
5
+ //
6
+ // Beda dari App Launcher: Dashboard menampilkan SEMUA app katalog, termasuk yang tak dilisensikan
7
+ // (redup berlencana "Perlu Lisensi") — di sini katalog berfungsi sebagai etalase.
8
+ import { onMounted } from 'vue'
9
+ import { useI18n } from 'vue-i18n'
10
+ import { useApps } from '@initsolusidigital/worksuite-core/composables/useApps.js'
11
+ import { appUrl } from '@initsolusidigital/worksuite-core/utils/appUrl.js'
12
+ import AppBadge from '@initsolusidigital/worksuite-ui/AppBadge.vue'
13
+ import AppCarousel from '@initsolusidigital/worksuite-ui/AppCarousel.vue'
14
+
15
+ const { t } = useI18n()
16
+ const { apps, loading, fetchApps, appIcon, appColor, appName, appDesc, isCurrent, appAccess, appStatusLabel } = useApps()
17
+
18
+ onMounted(() => fetchApps())
19
+
20
+ // Alamat kartu diturunkan `appUrl()`, sama seperti App Launcher: `apps.url` selalu origin ber-port,
21
+ // jadi memakainya apa adanya melempar pengguna keluar dari origin tunggal saat halaman disajikan
22
+ // di belakang proxy. Yang menentukan boleh-tidaknya dibuka adalah `appAccess().openable`.
23
+ const cardHref = (app) => (appAccess(app).openable ? appUrl(app.slug, app.url) : null) ?? '#'
24
+
25
+ const STATUS_COLOR = { maintenance: 'amber', degraded: 'red' }
26
+
27
+ // Satu lencana per kartu. "Segera" didahulukan dari "Perlu Lisensi": app yang belum ada tak bisa
28
+ // dibuka walau dilisensikan. Lencana status tetap tampil bagi yang boleh membukanya (System Owner).
29
+ function badgeOf(app) {
30
+ const a = appAccess(app)
31
+ if (a.badge === 'coming_soon') return { color: 'gray', label: t('dashboard.subApps.badgeSoon') }
32
+ if (!a.entitled) return { color: 'amber', label: t('dashboard.subApps.badgeLocked') }
33
+ if (a.badge) return { color: STATUS_COLOR[a.badge], label: appStatusLabel(app) }
34
+ if (isCurrent(app)) return { color: 'green', label: t('dashboard.subApps.badgeCurrent') }
35
+ return null
36
+ }
37
+
38
+ function onCardClick(event, app) {
39
+ if (!appAccess(app).openable) event.preventDefault()
40
+ }
41
+ </script>
42
+
43
+ <template>
44
+ <!-- Katalog datang dari `GET /apps` dan `useApps` sengaja fail-soft (gagal muat = daftar kosong).
45
+ Tanpa dua keadaan ini, jeda maupun kegagalan sama-sama tampil sebagai kotak kosong tanpa satu
46
+ kata pun, sehingga pembaca menyimpulkan widgetnya rusak. -->
47
+ <p v-if="loading && !apps.length" class="text-sm text-gray-400 dark:text-gray-500 text-center py-4">{{ t('common.loading') }}</p>
48
+ <p v-else-if="!apps.length" class="text-sm text-gray-400 dark:text-gray-500 text-center py-4">{{ t('launcher.empty') }}</p>
49
+ <AppCarousel v-else>
50
+ <a
51
+ v-for="app in apps"
52
+ :key="app.id ?? app.slug"
53
+ :href="cardHref(app)"
54
+ target="_blank"
55
+ :aria-disabled="appAccess(app).openable ? undefined : 'true'"
56
+ :data-app="app.slug"
57
+ :data-app-status="appAccess(app).status"
58
+ :class="[
59
+ 'shrink-0 bg-gray-50 dark:bg-gray-900/40 rounded-xl border border-gray-200 dark:border-gray-700 transition-shadow group w-24 p-3 flex flex-col items-center justify-center gap-2 text-center sm:w-64 sm:p-4 sm:flex-row sm:items-center sm:justify-start sm:gap-3 sm:text-left',
60
+ appAccess(app).openable ? 'hover:shadow-md' : 'cursor-not-allowed',
61
+ ]"
62
+ @click="onCardClick($event, app)"
63
+ >
64
+ <div
65
+ class="w-10 h-10 rounded-lg flex items-center justify-center shrink-0"
66
+ :class="[appColor(app), !appAccess(app).openable && 'opacity-50 grayscale']"
67
+ >
68
+ <component :is="appIcon(app)" class="w-5 h-5" />
69
+ </div>
70
+ <div class="min-w-0">
71
+ <div class="flex items-center gap-2">
72
+ <p
73
+ class="text-sm font-medium truncate transition-colors"
74
+ :class="appAccess(app).openable
75
+ ? 'text-gray-900 dark:text-white group-hover:text-blue-600 dark:group-hover:text-blue-400'
76
+ : 'text-gray-400 dark:text-gray-500'"
77
+ >{{ appName(app) }}</p>
78
+ <span v-if="badgeOf(app)" data-app-badge class="hidden sm:inline-flex shrink-0">
79
+ <AppBadge :color="badgeOf(app).color">{{ badgeOf(app).label }}</AppBadge>
80
+ </span>
81
+ </div>
82
+ <p
83
+ class="hidden sm:block text-xs mt-0.5 line-clamp-2"
84
+ :class="appAccess(app).openable ? 'text-gray-500 dark:text-gray-400' : 'text-gray-400 dark:text-gray-500'"
85
+ >{{ appDesc(app) }}</p>
86
+ </div>
87
+ </a>
88
+ </AppCarousel>
89
+ </template>