@saasicat/ui-vue 0.19.0 → 0.22.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 (145) hide show
  1. package/dist/{catalog-JXdKdIqG.d.cts → catalog-DJcfm5N2.d.cts} +21 -7
  2. package/dist/{catalog-JXdKdIqG.d.ts → catalog-DJcfm5N2.d.ts} +21 -7
  3. package/dist/{chunk-DPTIOQXX.js → chunk-F7NRM6KI.js} +56 -28
  4. package/dist/{chunk-RVG6LQHL.js → chunk-LY52T4N4.js} +21 -2
  5. package/dist/{chunk-ORX3ZG47.js → chunk-XMMFN2WJ.js} +74 -3
  6. package/dist/client/index.cjs +134 -29
  7. package/dist/client/index.d.cts +53 -3
  8. package/dist/client/index.d.ts +53 -3
  9. package/dist/client/index.js +14 -2
  10. package/dist/index.cjs +321 -162
  11. package/dist/index.d.cts +30 -8
  12. package/dist/index.d.ts +30 -8
  13. package/dist/index.js +176 -133
  14. package/dist/quasar/index.cjs +78 -29
  15. package/dist/quasar/index.d.cts +2 -2
  16. package/dist/quasar/index.d.ts +2 -2
  17. package/dist/quasar/index.js +6 -2
  18. package/dist/testing-e2e/admin-pages-suite.d.cts +37 -0
  19. package/dist/testing-e2e/admin-pages-suite.d.ts +37 -0
  20. package/dist/{use-super-admin-i18n-BlqcD0N7.d.ts → use-super-admin-i18n-CHNdsSlm.d.ts} +34 -7
  21. package/dist/{use-super-admin-i18n-1nCOkvgi.d.cts → use-super-admin-i18n-CgTuNi8h.d.cts} +34 -7
  22. package/package.json +18 -8
  23. package/src/client/i18n/messages/bundles.ts +0 -2
  24. package/src/client/i18n/messages/common.ts +24 -0
  25. package/src/client/i18n/messages/discovery.ts +2 -2
  26. package/src/client/i18n/messages/marketing.ts +2 -4
  27. package/src/client/i18n/messages/plan-detail.ts +0 -4
  28. package/src/client/i18n/messages/plans.ts +20 -8
  29. package/src/client/i18n/messages/tenants.ts +0 -2
  30. package/src/client/index.ts +1 -0
  31. package/src/client/manifest-loader.ts +1 -1
  32. package/src/client/resolve-plans.ts +144 -0
  33. package/src/components/BundleVersionPublishDialog.vue +6 -6
  34. package/src/components/KvBlock.vue +4 -4
  35. package/src/components/MarketingPromotionsTab.vue +34 -48
  36. package/src/components/MfaPromptDialog.vue +8 -2
  37. package/src/components/TenantActionConfirmDialog.vue +4 -4
  38. package/src/components/VersionDiffPreview.vue +7 -7
  39. package/src/components/admin-page/AdminBody.vue +40 -0
  40. package/src/components/admin-page/AdminFilters.vue +12 -0
  41. package/src/components/admin-page/AdminHero.vue +49 -0
  42. package/src/components/admin-page/AdminKpi.vue +84 -0
  43. package/src/components/admin-page/AdminPage.vue +16 -0
  44. package/src/components/admin-page/AdminPaginator.vue +195 -0
  45. package/src/components/admin-page/AdminRefreshBtn.vue +39 -0
  46. package/src/components/admin-page/AdminSection.vue +53 -0
  47. package/src/components/admin-page/AdminStatistics.vue +40 -0
  48. package/src/components/admin-page/AdminTable.vue +175 -0
  49. package/src/components/bundle-editor/BundleCreatePanel.vue +23 -23
  50. package/src/components/bundle-editor/BundleFeaturesEditor.vue +7 -7
  51. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +9 -9
  52. package/src/components/bundle-editor/BundleQuotasEditor.vue +11 -11
  53. package/src/components/bundle-editor/BundleStatusBanner.vue +6 -6
  54. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +18 -18
  55. package/src/components/bundle-editor/BundleVersionStrip.vue +12 -12
  56. package/src/components/dialogs/PilotCreateDialog.vue +12 -12
  57. package/src/components/dialogs/PilotEditDialog.vue +7 -7
  58. package/src/components/dialogs/PromoCodeCreateDialog.vue +8 -8
  59. package/src/components/dialogs/PromoCodeDialogFields.vue +33 -19
  60. package/src/components/dialogs/PromoCodeEditDialog.vue +10 -10
  61. package/src/components/plan/PlanGrid.vue +1 -1
  62. package/src/components/plan-create-dialog/PlanCreateDialog.vue +34 -46
  63. package/src/components/plan-detail/PlanAuditLog.vue +7 -8
  64. package/src/components/plan-detail/PlanDetail.vue +95 -292
  65. package/src/components/plan-detail/PlanDetailKpis.vue +22 -27
  66. package/src/components/plan-detail/PlanTitleEdit.vue +133 -0
  67. package/src/components/plan-detail/PlanVersionDiffPanel.vue +5 -8
  68. package/src/components/plan-detail/PlanVersionsPanel.vue +9 -11
  69. package/src/components/plan-list/PlanList.vue +206 -457
  70. package/src/components/plan-matrix/PlanMatrix.vue +66 -183
  71. package/src/components/plan-review/PlanReview.vue +191 -275
  72. package/src/components/plan-version-editor/PlanCatalogPreview.vue +7 -5
  73. package/src/components/plan-version-editor/PlanVersionEditor.vue +200 -295
  74. package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +23 -55
  75. package/src/index.ts +1 -0
  76. package/src/pages-standard/AdminLayout.vue +38 -12
  77. package/src/pages-standard/AdminManifestErrorPage.vue +79 -9
  78. package/src/pages-standard/AuditPage.vue +65 -109
  79. package/src/pages-standard/BundlesPage.vue +146 -179
  80. package/src/pages-standard/DashboardPage.vue +59 -154
  81. package/src/pages-standard/DiscoveryPage.vue +172 -227
  82. package/src/pages-standard/EmailHistoryPage.vue +118 -159
  83. package/src/pages-standard/MarketingCatalogPage.vue +399 -440
  84. package/src/pages-standard/PilotsPage.vue +69 -117
  85. package/src/pages-standard/PlansPage.vue +240 -112
  86. package/src/pages-standard/PlatformEmailPage.vue +56 -91
  87. package/src/pages-standard/PromoCodeDetailPage.vue +49 -74
  88. package/src/pages-standard/PromoCodesPage.vue +95 -128
  89. package/src/pages-standard/SubscriptionsPage.vue +19 -52
  90. package/src/pages-standard/SuperAdminLoginPage.vue +12 -12
  91. package/src/pages-standard/SuperAdminSetupWizard.vue +22 -18
  92. package/src/pages-standard/TenantDetailPage.vue +100 -191
  93. package/src/pages-standard/TenantsPage.vue +190 -295
  94. package/src/pages-standard/UsersPage.vue +89 -157
  95. package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -17
  96. package/src/pages-standard/bundles-page/BundlesKpis.vue +13 -22
  97. package/src/pages-standard/bundles-page/BundlesToolbar.vue +63 -0
  98. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +10 -10
  99. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -5
  100. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +16 -16
  101. package/src/pages-standard/discovery-page/DiscoveryKpis.vue +31 -27
  102. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +7 -7
  103. package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +111 -73
  104. package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +43 -62
  105. package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +53 -35
  106. package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +7 -7
  107. package/src/pages-standard/plan-versions/PlanDiffCard.vue +6 -6
  108. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +6 -6
  109. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +16 -16
  110. package/src/pages-standard/plans-page/PlanBundleOverview.vue +14 -29
  111. package/src/pages-standard/plans-page/PlanPublishDialog.vue +1 -1
  112. package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
  113. package/src/pages-standard/sa-theme.css +552 -86
  114. package/src/pages-standard/tenant-detail/TenantMasterData.vue +28 -0
  115. package/src/pages-standard/tenant-detail/TenantUsage.vue +31 -0
  116. package/src/pages-standard/tenant-detail/TenantUsers.vue +15 -0
  117. package/src/pages-standard/tenant-detail/types.ts +38 -0
  118. package/src/pages-standard/tenants/StatusPill.vue +2 -2
  119. package/src/pages-tenant/MySubscriptionBundlesPage.vue +25 -25
  120. package/src/pages-tenant/OnboardingConfigurator.vue +1 -5
  121. package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
  122. package/src/pages-tenant/TenantPlanSection.vue +12 -20
  123. package/src/quasar/create-super-admin-app.ts +4 -0
  124. package/src/vue/entitlement-provider.ts +0 -1
  125. package/src/vue/feature-router-guard.ts +0 -1
  126. package/src/vue/super-admin-context.ts +106 -1
  127. package/src/vue/use-api-list.ts +2 -1
  128. package/src/vue/use-mfa-prompt.ts +72 -0
  129. package/src/vue/use-pagination.ts +63 -0
  130. package/src/vue/use-plans.ts +1 -2
  131. package/src/vue/use-sign-out.ts +90 -0
  132. package/src/vue/use-tenant-billing.ts +1 -1
  133. package/src/vue/use-tenant-manifest.ts +0 -1
  134. package/src/components/KpiCard.vue +0 -53
  135. package/src/components/plan-cockpit/PlanCockpit.vue +0 -1012
  136. package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +0 -72
  137. package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +0 -100
  138. package/src/components/plan-cockpit/PlanCockpitHeader.vue +0 -101
  139. package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +0 -112
  140. package/src/components/plan-cockpit/PlanCockpitKpis.vue +0 -68
  141. package/src/components/plan-cockpit/PlanCockpitVersions.vue +0 -251
  142. package/src/components/plan-cockpit/types.ts +0 -72
  143. package/src/components/plan-detail/PlanDetailHeader.vue +0 -194
  144. package/src/pages-standard/bundles-page/BundlesHeader.vue +0 -68
  145. package/src/pages-standard/discovery-page/DiscoveryHeader.vue +0 -34
@@ -1,60 +1,51 @@
1
1
  <template>
2
- <div class="sa-pilots">
3
- <header class="sa-page-head">
4
- <div>
5
- <h1 class="sa-page-head__title">{{ msg.title }}</h1>
6
- <p class="sa-page-head__sub">
7
- {{ formatMessage(msg.subtitleCount, { count: rows.length }) }}
8
- </p>
9
- </div>
10
- <div class="sa-page-head__actions">
2
+ <AdminPage class="sa-pilots">
3
+ <AdminHero
4
+ :title="msg.title"
5
+ :subtitle="formatMessage(msg.subtitleCount, { count: rows.length })"
6
+ >
7
+ <template #actions>
11
8
  <slot name="head-actions">
12
- <q-btn
9
+ <button
13
10
  v-if="enableCreate"
14
- unelevated
15
- color="primary"
16
- icon="add"
17
- :label="resolvedCreateLabel"
11
+ class="sa-btn sa-btn--primary"
12
+ type="button"
18
13
  @click="showCreate = true"
19
- />
14
+ >
15
+ <q-icon name="add" size="16px" />
16
+ <span>{{ resolvedCreateLabel }}</span>
17
+ </button>
20
18
  </slot>
21
- </div>
22
- </header>
23
-
24
- <div class="sa-stats">
25
- <button
26
- v-for="tile in statTiles"
27
- :key="tile.id"
28
- class="sa-stat"
29
- :class="[
30
- tile.tone ? `sa-stat--${tile.tone}` : null,
31
- filter === tile.id ? 'sa-stat--active' : null,
32
- ]"
33
- @click="filter = tile.id"
34
- >
35
- <span class="sa-stat__num">{{ tile.count }}</span>
36
- <span class="sa-stat__label">{{ tile.label }}</span>
37
- <span v-if="tile.hint" class="sa-stat__hint">{{ tile.hint }}</span>
38
- </button>
39
- </div>
40
-
41
- <q-banner v-if="reviewSoon.length" class="bg-amber-2 text-grey-9 q-mb-md" rounded>
42
- <template #avatar><q-icon name="event" color="amber-9" /></template>
43
- {{ formatMessage(msg.list.reviewSoonBanner, { count: reviewSoon.length }) }}
44
- </q-banner>
45
-
46
- <div class="sa-pilots__card">
47
- <q-table
48
- flat
49
- :rows="filteredRows"
50
- :columns="effectiveColumns"
51
- row-key="id"
52
- :pagination="{ rowsPerPage: 0 }"
53
- :loading="loading"
54
- hide-pagination
55
- >
56
- <template #body-cell-actions="{ row }">
57
- <q-td>
19
+ </template>
20
+ </AdminHero>
21
+
22
+ <AdminBody>
23
+ <AdminStatistics :label="msg.title">
24
+ <AdminKpi
25
+ v-for="tile in statTiles"
26
+ :key="tile.id"
27
+ :label="tile.label"
28
+ :value="tile.count"
29
+ :sub="tile.hint"
30
+ :tone="tile.tone"
31
+ :selected="filter === tile.id"
32
+ :action="() => (filter = tile.id)"
33
+ />
34
+ </AdminStatistics>
35
+
36
+ <q-banner v-if="reviewSoon.length" class="bg-amber-2 text-grey-9 q-mb-md" rounded>
37
+ <template #avatar><q-icon name="event" color="amber-9" /></template>
38
+ {{ formatMessage(msg.list.reviewSoonBanner, { count: reviewSoon.length }) }}
39
+ </q-banner>
40
+
41
+ <AdminSection class="sa-pilots__card">
42
+ <AdminTable
43
+ :rows="filteredRows"
44
+ :columns="effectiveColumns"
45
+ :loading="loading"
46
+ storage-key="pilots"
47
+ >
48
+ <template #row-actions="{ row }">
58
49
  <slot name="row-actions" :row="row">
59
50
  <q-btn
60
51
  v-for="action in visibleActions(row)"
@@ -67,10 +58,10 @@
67
58
  @click="action.handler(row)"
68
59
  />
69
60
  </slot>
70
- </q-td>
71
- </template>
72
- </q-table>
73
- </div>
61
+ </template>
62
+ </AdminTable>
63
+ </AdminSection>
64
+ </AdminBody>
74
65
 
75
66
  <PilotCreateDialog
76
67
  v-if="enableCreate && submitCreate"
@@ -98,22 +89,30 @@
98
89
 
99
90
  <MfaPromptDialog
100
91
  v-if="needsMfaDialog"
101
- :model-value="showMfa"
102
- :description="mfaDescription"
103
- :error="mfaError"
92
+ :model-value="mfa.show.value"
93
+ :description="mfa.description.value"
94
+ :error="mfa.error.value"
104
95
  :setup-hint="mfaSetupHint"
105
- @update:model-value="onMfaDialogVisibility"
106
- @confirm="onMfaConfirm"
96
+ @update:model-value="mfa.onVisibility"
97
+ @confirm="mfa.onConfirm"
107
98
  />
108
- </div>
99
+ </AdminPage>
109
100
  </template>
110
101
 
111
102
  <script setup lang="ts">
103
+ import AdminTable from '../components/admin-page/AdminTable.vue';
112
104
  import { computed, onMounted, ref } from 'vue';
105
+ import { useMfaPrompt } from '../vue/use-mfa-prompt.js';
113
106
  import { useQuasar } from 'quasar';
114
107
  import { formatMessage } from '../client/i18n/format.js';
115
108
  import { useSaMessages, useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
116
109
  import { useSuperAdminNotify } from '../quasar/notify.js';
110
+ import AdminBody from '../components/admin-page/AdminBody.vue';
111
+ import AdminHero from '../components/admin-page/AdminHero.vue';
112
+ import AdminSection from '../components/admin-page/AdminSection.vue';
113
+ import AdminKpi from '../components/admin-page/AdminKpi.vue';
114
+ import AdminPage from '../components/admin-page/AdminPage.vue';
115
+ import AdminStatistics from '../components/admin-page/AdminStatistics.vue';
117
116
  import PilotCreateDialog from '../components/dialogs/PilotCreateDialog.vue';
118
117
  import PilotEditDialog from '../components/dialogs/PilotEditDialog.vue';
119
118
  import MfaPromptDialog from '../components/MfaPromptDialog.vue';
@@ -219,38 +218,11 @@ const showEdit = ref(false);
219
218
  const editRow = ref<PilotRow | null>(null);
220
219
  const bakedPlanOptions = ref<PilotPlanOption[]>([]);
221
220
 
222
- // MFA dialog state for per-flow MFA (extend/revoke). Promise-resolver pattern
223
- // analogous to use-platform-tenant-actions.ts: `onExtendClick`/`onRevokeClick`
224
- // calls `runWithMfa(...)`, which opens the dialog and waits for `onMfaConfirm`
225
- // (or cancellation via `update:modelValue=false`).
226
- const showMfa = ref(false);
227
- const mfaError = ref('');
228
- const mfaDescription = ref('');
229
- let pendingMfaResolve: ((code: string | null) => void) | null = null;
221
+ // Per-flow MFA for extend/revoke: `runWithMfa` awaits `mfa.prompt`, which
222
+ // resolves with the code or with null when the user closes the dialog.
223
+ const mfa = useMfaPrompt();
230
224
  const needsMfaDialog = computed(() => props.requireMfaForExtend || props.requireMfaForRevoke);
231
225
 
232
- function promptMfa(description: string): Promise<string | null> {
233
- return new Promise((resolve) => {
234
- mfaDescription.value = description;
235
- mfaError.value = '';
236
- showMfa.value = true;
237
- pendingMfaResolve = (code) => {
238
- pendingMfaResolve = null;
239
- resolve(code);
240
- };
241
- });
242
- }
243
-
244
- function onMfaConfirm(code: string): void {
245
- pendingMfaResolve?.(code);
246
- }
247
-
248
- function onMfaDialogVisibility(open: boolean): void {
249
- showMfa.value = open;
250
- if (!open && pendingMfaResolve) {
251
- pendingMfaResolve(null);
252
- }
253
- }
254
226
  // Consumers can set `createPlanOptions` instead of `loadPlanOptions`
255
227
  // (e.g. apps with a hard-coded plan list).
256
228
  const effectiveCreatePlanOptions = computed<readonly (string | PilotPlanOption)[]>(() => {
@@ -388,14 +360,6 @@ const mergedActions = computed<readonly PilotRowAction[]>(() => [
388
360
 
389
361
  const effectiveColumns = computed(() => {
390
362
  const cols = [...baseColumns.value];
391
- if (mergedActions.value.length > 0) {
392
- cols.push({
393
- name: 'actions',
394
- label: '',
395
- field: ((r: PilotRow) => r.id) as never,
396
- align: 'right' as 'left',
397
- });
398
- }
399
363
  return cols;
400
364
  });
401
365
 
@@ -498,21 +462,21 @@ async function runAction(
498
462
  // MFA loop: as long as the server returns 401, keep the dialog open and
499
463
  // wait again for a code. Cancelling (resolver === null) ends it.
500
464
  while (true) {
501
- const code = await promptMfa(actionLabel);
465
+ const code = await mfa.prompt(actionLabel);
502
466
  if (code === null) return;
503
467
  try {
504
468
  await invoke(code);
505
- showMfa.value = false;
469
+ mfa.show.value = false;
506
470
  notify('positive', successMessage);
507
471
  await reload();
508
472
  return;
509
473
  } catch (err) {
510
474
  const status = (err as { response?: { status?: number } })?.response?.status;
511
475
  if (status === 401) {
512
- mfaError.value = msg.value.mfa.invalidOrNotSetUp;
476
+ mfa.error.value = msg.value.mfa.invalidOrNotSetUp;
513
477
  continue;
514
478
  }
515
- showMfa.value = false;
479
+ mfa.show.value = false;
516
480
  notify('negative', errMsg(err));
517
481
  return;
518
482
  }
@@ -574,16 +538,4 @@ function formatDate(iso: string | null | undefined): string | null {
574
538
  }
575
539
  </script>
576
540
 
577
- <style scoped>
578
- .sa-pilots {
579
- min-height: calc(100vh - 56px);
580
- background: var(--sa-bg-app, #f1f5f9);
581
- padding: 20px 28px 28px;
582
- }
583
- .sa-pilots__card {
584
- background: #fff;
585
- border: 1px solid var(--sa-border, #e2e8f0);
586
- border-radius: 12px;
587
- overflow: hidden;
588
- }
589
- </style>
541
+ <style scoped></style>