@saasicat/ui-vue 0.4.0 → 0.6.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.
- package/README.md +64 -4
- package/dist/chunk-A3W2N26K.js +714 -0
- package/dist/chunk-QZOSDCNP.js +98 -0
- package/dist/chunk-X5SQ5HMB.js +3231 -0
- package/dist/client/index.cjs +3988 -0
- package/dist/client/index.d.cts +321 -0
- package/dist/client/index.d.ts +321 -0
- package/dist/client/index.js +70 -0
- package/dist/index.cjs +4446 -1249
- package/dist/index.d.cts +297 -888
- package/dist/index.d.ts +297 -888
- package/dist/index.js +609 -1348
- package/dist/messages-7b0P8W75.d.cts +1652 -0
- package/dist/messages-7b0P8W75.d.ts +1652 -0
- package/dist/quasar/index.cjs +3340 -0
- package/dist/quasar/index.d.cts +95 -0
- package/dist/quasar/index.d.ts +95 -0
- package/dist/quasar/index.js +96 -0
- package/dist/testing-e2e/admin-pages-suite.cjs +14 -11
- package/dist/testing-e2e/admin-pages-suite.js +14 -11
- package/dist/use-super-admin-i18n-B3v3-SWZ.d.ts +210 -0
- package/dist/use-super-admin-i18n-DMktRVEt.d.cts +210 -0
- package/package.json +23 -3
- package/src/{action-registry.ts → client/action-registry.ts} +4 -4
- package/src/{batch-column-fetcher.ts → client/batch-column-fetcher.ts} +4 -4
- package/src/{boot-loader.ts → client/boot-loader.ts} +3 -3
- package/src/client/i18n/currency.ts +42 -0
- package/src/client/i18n/define.ts +59 -0
- package/src/client/i18n/format.ts +12 -0
- package/src/client/i18n/index.ts +14 -0
- package/src/client/i18n/locale.ts +15 -0
- package/src/client/i18n/messages/audit.ts +42 -0
- package/src/client/i18n/messages/bundles.ts +459 -0
- package/src/client/i18n/messages/common.ts +147 -0
- package/src/client/i18n/messages/dashboard.ts +16 -0
- package/src/client/i18n/messages/discovery.ts +229 -0
- package/src/client/i18n/messages/email.ts +125 -0
- package/src/client/i18n/messages/marketing.ts +270 -0
- package/src/client/i18n/messages/nav.ts +72 -0
- package/src/client/i18n/messages/pilots.ts +192 -0
- package/src/client/i18n/messages/plan-detail.ts +266 -0
- package/src/client/i18n/messages/plan-editor.ts +177 -0
- package/src/client/i18n/messages/plan-versions.ts +251 -0
- package/src/client/i18n/messages/plans.ts +503 -0
- package/src/client/i18n/messages/promos.ts +202 -0
- package/src/client/i18n/messages/shell.ts +145 -0
- package/src/client/i18n/messages/tenants.ts +104 -0
- package/src/client/i18n/messages/users.ts +78 -0
- package/src/client/i18n/messages.ts +84 -0
- package/src/client/index.ts +27 -0
- package/src/{manifest-loader.ts → client/manifest-loader.ts} +4 -4
- package/src/{nav-builder.ts → client/nav-builder.ts} +44 -51
- package/src/{plan-versions-catalog.ts → client/plan-versions-catalog.ts} +42 -30
- package/src/components/BundleVersionPublishDialog.vue +35 -24
- package/src/components/FeatureGate.vue +1 -1
- package/src/components/MarketingPromotionsTab.vue +112 -59
- package/src/components/MfaPromptDialog.vue +11 -11
- package/src/components/TenantActionConfirmDialog.vue +19 -17
- package/src/components/VersionDiffPreview.vue +72 -43
- package/src/components/bundle-editor/BundleCreatePanel.vue +76 -63
- package/src/components/bundle-editor/BundleFeaturesEditor.vue +13 -6
- package/src/components/bundle-editor/BundlePlanCompatPicker.vue +19 -14
- package/src/components/bundle-editor/BundleQuotasEditor.vue +7 -4
- package/src/components/bundle-editor/BundleStatusBanner.vue +36 -19
- package/src/components/bundle-editor/BundleVersionInlineEditor.vue +51 -35
- package/src/components/bundle-editor/BundleVersionStrip.vue +24 -12
- package/src/components/bundle-editor/bundle-version-status.ts +29 -29
- package/src/components/dialogs/PilotCreateDialog.vue +58 -63
- package/src/components/dialogs/PilotEditDialog.vue +40 -34
- package/src/components/dialogs/PromoCodeCreateDialog.vue +89 -63
- package/src/components/dialogs/PromoCodeEditDialog.vue +98 -66
- package/src/components/dialogs/types.ts +3 -13
- package/src/components/plan/PlanCycleToggle.vue +21 -10
- package/src/components/plan/PlanGrid.vue +2 -2
- package/src/components/plan/PriceSummary.vue +1 -1
- package/src/components/plan/PromoCodeInput.vue +1 -1
- package/src/components/plan/PublicBundleGrid.vue +1 -1
- package/src/components/plan-cockpit/PlanCockpit.vue +34 -15
- package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +13 -6
- package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +18 -9
- package/src/components/plan-cockpit/PlanCockpitHeader.vue +9 -6
- package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +24 -11
- package/src/components/plan-cockpit/PlanCockpitKpis.vue +28 -17
- package/src/components/plan-cockpit/PlanCockpitVersions.vue +50 -25
- package/src/components/plan-create-dialog/PlanCreateDialog.vue +45 -35
- package/src/components/plan-detail/PlanAuditLog.vue +11 -6
- package/src/components/plan-detail/PlanDetail.vue +21 -23
- package/src/components/plan-detail/PlanDetailHeader.vue +20 -11
- package/src/components/plan-detail/PlanDetailKpis.vue +30 -17
- package/src/components/plan-detail/PlanTerminateDialog.vue +22 -9
- package/src/components/plan-detail/PlanVersionDiffPanel.vue +61 -27
- package/src/components/plan-detail/PlanVersionsPanel.vue +71 -36
- package/src/components/plan-list/PlanList.vue +99 -57
- package/src/components/plan-matrix/PlanMatrix.vue +85 -38
- package/src/components/plan-review/PlanReview.vue +105 -80
- package/src/components/plan-version-editor/PlanCatalogPreview.vue +43 -20
- package/src/components/plan-version-editor/PlanComponentPool.vue +15 -7
- package/src/components/plan-version-editor/PlanVersionBasket.vue +45 -24
- package/src/components/plan-version-editor/PlanVersionDiffDialog.vue +8 -7
- package/src/components/plan-version-editor/PlanVersionEditor.vue +74 -40
- package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +24 -12
- package/src/index.ts +82 -79
- package/src/pages-standard/AdminLayout.vue +43 -18
- package/src/pages-standard/AdminManifestErrorPage.vue +10 -10
- package/src/pages-standard/AuditPage.vue +58 -19
- package/src/pages-standard/BundlesPage.vue +29 -18
- package/src/pages-standard/DashboardPage.vue +31 -17
- package/src/pages-standard/DiscoveryPage.vue +40 -28
- package/src/pages-standard/EmailHistoryPage.vue +98 -69
- package/src/pages-standard/MarketingCatalogPage.vue +40 -21
- package/src/pages-standard/PilotsPage.vue +64 -52
- package/src/pages-standard/PlanVersionsPage.vue +9 -5
- package/src/pages-standard/PlansPage.vue +91 -59
- package/src/pages-standard/PlatformEmailPage.vue +120 -53
- package/src/pages-standard/PromoCodeDetailPage.vue +66 -63
- package/src/pages-standard/PromoCodesPage.vue +51 -54
- package/src/pages-standard/SubscriptionsPage.vue +14 -9
- package/src/pages-standard/SuperAdminLoginPage.vue +19 -16
- package/src/pages-standard/SuperAdminSetupWizard.vue +53 -49
- package/src/pages-standard/TenantDetailPage.vue +54 -40
- package/src/pages-standard/TenantsPage.vue +57 -44
- package/src/pages-standard/UsersPage.vue +70 -52
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -8
- package/src/pages-standard/bundles-page/BundleDetailPanel.vue +28 -18
- package/src/pages-standard/bundles-page/BundlesFilterBar.vue +4 -1
- package/src/pages-standard/bundles-page/BundlesHeader.vue +9 -8
- package/src/pages-standard/bundles-page/BundlesKpis.vue +29 -11
- package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +20 -8
- package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -3
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +43 -24
- package/src/pages-standard/discovery-page/DiscoveryHeader.vue +7 -4
- package/src/pages-standard/discovery-page/DiscoveryKpis.vue +28 -15
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +20 -10
- package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +9 -6
- package/src/pages-standard/discovery-page/discovery-ui.ts +40 -52
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +81 -49
- package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +13 -10
- package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +24 -20
- package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +6 -3
- package/src/pages-standard/plan-versions/PlanDiffCard.vue +16 -6
- package/src/pages-standard/plan-versions/PlanVersionHeader.vue +42 -26
- package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +46 -27
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +8 -6
- package/src/pages-standard/plan-versions/PlanVersionsList.vue +40 -17
- package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +25 -13
- package/src/pages-standard/plan-versions/format.ts +33 -17
- package/src/pages-standard/plans-page/PlanArchiveDialog.vue +12 -8
- package/src/pages-standard/plans-page/PlanBundleOverview.vue +15 -6
- package/src/pages-standard/plans-page/PlanDiscardDraftDialog.vue +18 -7
- package/src/pages-standard/plans-page/PlanPublishDialog.vue +23 -12
- package/src/pages-standard/tenants/format.ts +3 -2
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +73 -38
- package/src/pages-tenant/OnboardingConfigurator.vue +3 -3
- package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
- package/src/pages-tenant/PlanChangeWizard.vue +10 -6
- package/src/pages-tenant/TenantPlanSection.vue +20 -16
- package/src/pages-tenant/default-i18n.ts +217 -1
- package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +9 -7
- package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +11 -12
- package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +4 -1
- package/src/pages-tenant/tenant-plan-section/TenantPlanCardHeader.vue +1 -1
- package/src/pages-tenant/tenant-plan-section/TenantUsageGrid.vue +1 -1
- package/src/quasar/create-super-admin-app.ts +192 -0
- package/src/quasar/index.ts +11 -0
- package/src/quasar/notify.ts +30 -0
- package/src/testing-e2e/admin-pages-suite.ts +14 -11
- package/src/{manifest-store-factory.ts → vue/manifest-store-factory.ts} +1 -1
- package/src/{platform-loaders.ts → vue/platform-loaders.ts} +4 -4
- package/src/{project-page-host.ts → vue/project-page-host.ts} +6 -4
- package/src/{create-super-admin-app.ts → vue/super-admin-context.ts} +20 -139
- package/src/vue/ui-notify.ts +30 -0
- package/src/{use-actions.ts → vue/use-actions.ts} +1 -1
- package/src/{use-api-list.ts → vue/use-api-list.ts} +1 -1
- package/src/{use-audit-entries.ts → vue/use-audit-entries.ts} +3 -3
- package/src/{use-batch-columns.ts → vue/use-batch-columns.ts} +1 -1
- package/src/{use-bulk-publish.ts → vue/use-bulk-publish.ts} +7 -5
- package/src/{use-bundle-versions-map.ts → vue/use-bundle-versions-map.ts} +7 -5
- package/src/{use-bundles.ts → vue/use-bundles.ts} +14 -14
- package/src/{use-catalog-entries.ts → vue/use-catalog-entries.ts} +14 -11
- package/src/{use-discovery.ts → vue/use-discovery.ts} +9 -6
- package/src/{use-entitlement.ts → vue/use-entitlement.ts} +4 -4
- package/src/{use-live-plan-versions.ts → vue/use-live-plan-versions.ts} +5 -5
- package/src/{use-manifest.ts → vue/use-manifest.ts} +1 -1
- package/src/{use-marketing-projections.ts → vue/use-marketing-projections.ts} +10 -7
- package/src/{use-nav.ts → vue/use-nav.ts} +9 -3
- package/src/{use-plan-editor.ts → vue/use-plan-editor.ts} +2 -2
- package/src/{use-plan-versions.ts → vue/use-plan-versions.ts} +3 -3
- package/src/{use-plans.ts → vue/use-plans.ts} +13 -13
- package/src/{use-platform-tenant-actions.ts → vue/use-platform-tenant-actions.ts} +9 -6
- package/src/{use-promotions.ts → vue/use-promotions.ts} +10 -11
- package/src/{use-public-boot.ts → vue/use-public-boot.ts} +1 -1
- package/src/{use-subscription-draft.ts → vue/use-subscription-draft.ts} +2 -3
- package/src/{use-super-admin-context.ts → vue/use-super-admin-context.ts} +5 -5
- package/src/vue/use-super-admin-i18n.ts +82 -0
- package/src/{use-tenant-action-flow.ts → vue/use-tenant-action-flow.ts} +12 -7
- package/src/{use-tenant-billing-catalog.ts → vue/use-tenant-billing-catalog.ts} +2 -2
- package/src/{use-tenant-billing.ts → vue/use-tenant-billing.ts} +2 -2
- package/src/{use-tenant-manifest.ts → vue/use-tenant-manifest.ts} +2 -4
- package/src/{use-tenant-subscription-bundles.ts → vue/use-tenant-subscription-bundles.ts} +5 -5
- package/src/{use-tenants.ts → vue/use-tenants.ts} +3 -3
- package/dist/testing-e2e/admin-pages-suite.d.cts +0 -37
- package/dist/testing-e2e/admin-pages-suite.d.ts +0 -37
- package/src/components/BusinessTypeVersionEditorDialog.vue +0 -417
- package/src/components/BusinessTypeVersionPublishDialog.vue +0 -258
- package/src/pages-standard/BusinessTypesPage.vue +0 -662
- package/src/pages-standard/plan-versions/VersionDiffPreview.vue +0 -167
- package/src/use-business-types.ts +0 -269
- /package/src/{http-json.ts → client/http-json.ts} +0 -0
- /package/src/{types.ts → client/types.ts} +0 -0
- /package/src/{version.ts → client/version.ts} +0 -0
- /package/src/{create-admin-routes.ts → vue/create-admin-routes.ts} +0 -0
- /package/src/{entitlement-provider.ts → vue/entitlement-provider.ts} +0 -0
- /package/src/{feature-router-guard.ts → vue/feature-router-guard.ts} +0 -0
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<div class="sa-setup-head">
|
|
5
5
|
<div class="sa-setup-badge">{{ iconText }}</div>
|
|
6
6
|
<div>
|
|
7
|
-
<div class="sa-setup-title">
|
|
8
|
-
<div class="sa-setup-sub">{{
|
|
7
|
+
<div class="sa-setup-title">{{ msg.setup.title }}</div>
|
|
8
|
+
<div class="sa-setup-sub">{{ subtitleText }}</div>
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
@@ -16,40 +16,44 @@
|
|
|
16
16
|
<!-- Step 1: create SuperAdmin -->
|
|
17
17
|
<q-form v-if="step === 'form'" @submit.prevent="submitCreate" class="sa-setup-form">
|
|
18
18
|
<p class="sa-setup-hint">
|
|
19
|
-
|
|
20
|
-
<code>SETUP_TOKEN</code>
|
|
19
|
+
{{ msg.setup.tokenHintBefore }}
|
|
20
|
+
<code>SETUP_TOKEN</code>
|
|
21
|
+
{{ msg.setup.tokenHintAfter }}
|
|
21
22
|
</p>
|
|
22
23
|
<q-input
|
|
23
24
|
v-model="form.token"
|
|
24
|
-
label="
|
|
25
|
+
:label="msg.setup.tokenLabel"
|
|
25
26
|
type="password"
|
|
26
27
|
outlined
|
|
27
28
|
dense
|
|
28
29
|
autofocus
|
|
29
30
|
:disable="loading"
|
|
30
31
|
class="q-mb-sm"
|
|
31
|
-
:rules="[(v: string) => v.length > 0 ||
|
|
32
|
+
:rules="[(v: string) => v.length > 0 || msg.setup.tokenRequired]"
|
|
32
33
|
/>
|
|
33
34
|
<q-input
|
|
34
35
|
v-model="form.email"
|
|
35
|
-
label="
|
|
36
|
+
:label="msg.emailLabel"
|
|
36
37
|
type="email"
|
|
37
38
|
outlined
|
|
38
39
|
dense
|
|
39
40
|
:disable="loading"
|
|
40
41
|
class="q-mb-sm"
|
|
41
|
-
:rules="[(v: string) => /\S+@\S+\.\S+/.test(v) ||
|
|
42
|
+
:rules="[(v: string) => /\S+@\S+\.\S+/.test(v) || msg.invalidEmail]"
|
|
42
43
|
/>
|
|
43
44
|
<q-input
|
|
44
45
|
v-model="form.password"
|
|
45
|
-
label="
|
|
46
|
+
:label="msg.setup.passwordLabel"
|
|
46
47
|
:type="showPw ? 'text' : 'password'"
|
|
47
48
|
outlined
|
|
48
49
|
dense
|
|
49
50
|
:disable="loading"
|
|
50
|
-
hint="
|
|
51
|
+
:hint="msg.setup.passwordHint"
|
|
51
52
|
class="q-mb-sm"
|
|
52
|
-
:rules="[
|
|
53
|
+
:rules="[
|
|
54
|
+
(v: string) =>
|
|
55
|
+
v.length === 0 || v.length >= 8 || msg.setup.passwordMinLength,
|
|
56
|
+
]"
|
|
53
57
|
>
|
|
54
58
|
<template #append>
|
|
55
59
|
<q-icon
|
|
@@ -63,7 +67,7 @@
|
|
|
63
67
|
unelevated
|
|
64
68
|
color="primary"
|
|
65
69
|
icon="person_add"
|
|
66
|
-
label="
|
|
70
|
+
:label="msg.setup.submit"
|
|
67
71
|
:loading="loading"
|
|
68
72
|
:disable="!canCreate"
|
|
69
73
|
class="full-width q-mt-sm"
|
|
@@ -74,48 +78,48 @@
|
|
|
74
78
|
<!-- Step 2: set up MFA -->
|
|
75
79
|
<div v-else-if="step === 'mfa' && result" class="sa-setup-mfa">
|
|
76
80
|
<p class="sa-setup-hint">
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
{{ msg.setup.mfaIntroBefore }} <strong>{{ result.email }}</strong>
|
|
82
|
+
{{ msg.setup.mfaIntroAfter }}
|
|
79
83
|
</p>
|
|
80
84
|
|
|
81
85
|
<div v-if="result.generatedPassword" class="sa-setup-secret">
|
|
82
|
-
<div class="sa-setup-secret__label">
|
|
86
|
+
<div class="sa-setup-secret__label">
|
|
87
|
+
{{ msg.setup.generatedPasswordLabel }}
|
|
88
|
+
</div>
|
|
83
89
|
<code class="sa-setup-secret__value">{{ result.generatedPassword }}</code>
|
|
84
90
|
</div>
|
|
85
91
|
|
|
86
92
|
<div v-if="result.qrDataUrl" class="sa-setup-qr">
|
|
87
|
-
<img :src="result.qrDataUrl" alt="
|
|
88
|
-
<div class="sa-setup-qr__hint">
|
|
93
|
+
<img :src="result.qrDataUrl" :alt="msg.setup.qrAlt" width="200" height="200" />
|
|
94
|
+
<div class="sa-setup-qr__hint">{{ msg.setup.qrHint }}</div>
|
|
89
95
|
</div>
|
|
90
96
|
|
|
91
97
|
<div class="sa-setup-secret">
|
|
92
|
-
<div class="sa-setup-secret__label">
|
|
93
|
-
In Authenticator-App als „Schlüssel manuell eingeben"
|
|
94
|
-
</div>
|
|
98
|
+
<div class="sa-setup-secret__label">{{ msg.setup.manualSecretLabel }}</div>
|
|
95
99
|
<code class="sa-setup-secret__value">{{ result.secret }}</code>
|
|
96
100
|
</div>
|
|
97
101
|
<details class="sa-setup-uri">
|
|
98
|
-
<summary>
|
|
102
|
+
<summary>{{ msg.setup.otpauthSummary }}</summary>
|
|
99
103
|
<code class="sa-setup-uri__value">{{ result.otpauthUri }}</code>
|
|
100
104
|
</details>
|
|
101
105
|
|
|
102
106
|
<q-form @submit.prevent="submitConfirm" class="sa-setup-form q-mt-md">
|
|
103
107
|
<q-input
|
|
104
108
|
v-model="mfaCode"
|
|
105
|
-
label="
|
|
109
|
+
:label="msg.setup.codeLabel"
|
|
106
110
|
outlined
|
|
107
111
|
dense
|
|
108
112
|
autofocus
|
|
109
113
|
inputmode="numeric"
|
|
110
114
|
maxlength="6"
|
|
111
115
|
:disable="loading"
|
|
112
|
-
:rules="[(v: string) => /^\d{6}$/.test(v) ||
|
|
116
|
+
:rules="[(v: string) => /^\d{6}$/.test(v) || msg.setup.codeInvalid]"
|
|
113
117
|
/>
|
|
114
118
|
<q-btn
|
|
115
119
|
unelevated
|
|
116
120
|
color="primary"
|
|
117
121
|
icon="verified_user"
|
|
118
|
-
label="
|
|
122
|
+
:label="msg.setup.confirmMfa"
|
|
119
123
|
:loading="loading"
|
|
120
124
|
:disable="!/^\d{6}$/.test(mfaCode) || loading"
|
|
121
125
|
class="full-width q-mt-sm"
|
|
@@ -123,21 +127,19 @@
|
|
|
123
127
|
/>
|
|
124
128
|
</q-form>
|
|
125
129
|
<button class="sa-setup-skip" type="button" @click="step = 'done'">
|
|
126
|
-
|
|
130
|
+
{{ msg.setup.skip }}
|
|
127
131
|
</button>
|
|
128
132
|
</div>
|
|
129
133
|
|
|
130
134
|
<!-- Step 3: done -->
|
|
131
135
|
<div v-else-if="step === 'done'" class="sa-setup-done">
|
|
132
136
|
<q-icon name="check_circle" color="positive" size="48px" />
|
|
133
|
-
<p class="sa-setup-hint">
|
|
134
|
-
Einrichtung abgeschlossen. Melde dich jetzt mit dem neuen SuperAdmin an.
|
|
135
|
-
</p>
|
|
137
|
+
<p class="sa-setup-hint">{{ msg.setup.doneHint }}</p>
|
|
136
138
|
<q-btn
|
|
137
139
|
unelevated
|
|
138
140
|
color="primary"
|
|
139
141
|
icon="login"
|
|
140
|
-
label="
|
|
142
|
+
:label="msg.setup.toLogin"
|
|
141
143
|
class="full-width"
|
|
142
144
|
@click="emit('done')"
|
|
143
145
|
/>
|
|
@@ -148,18 +150,16 @@
|
|
|
148
150
|
|
|
149
151
|
<script setup lang="ts">
|
|
150
152
|
import { computed, reactive, ref } from 'vue';
|
|
151
|
-
import {
|
|
152
|
-
SETUP_ERROR_CODES,
|
|
153
|
-
type SetupConfirmMfaResponse,
|
|
154
|
-
type SetupResult,
|
|
155
|
-
} from '@saasicat/types';
|
|
153
|
+
import { SETUP_ERROR_CODES, type SetupConfirmMfaResponse, type SetupResult } from '@saasicat/types';
|
|
156
154
|
|
|
157
155
|
import {
|
|
158
156
|
useSuperAdminBrand,
|
|
159
157
|
useSuperAdminEndpoints,
|
|
160
158
|
useSuperAdminHttp,
|
|
161
|
-
} from '../use-super-admin-context.js';
|
|
162
|
-
import { HttpJsonError, postJson as httpPostJson } from '../http-json.js';
|
|
159
|
+
} from '../vue/use-super-admin-context.js';
|
|
160
|
+
import { HttpJsonError, postJson as httpPostJson } from '../client/http-json.js';
|
|
161
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
162
|
+
import { useSaMessages } from '../vue/use-super-admin-i18n.js';
|
|
163
163
|
|
|
164
164
|
interface Props {
|
|
165
165
|
/** Display name + badge abbreviation (override the app branding, e.g. from PublicBoot). */
|
|
@@ -172,12 +172,16 @@ const props = defineProps<Props>();
|
|
|
172
172
|
// shown again — the freshly created SuperAdmin then signs in.
|
|
173
173
|
const emit = defineEmits<{ done: [] }>();
|
|
174
174
|
|
|
175
|
+
const msg = useSaMessages('shell');
|
|
175
176
|
const brand = useSuperAdminBrand();
|
|
176
177
|
const endpoints = useSuperAdminEndpoints();
|
|
177
178
|
const http = useSuperAdminHttp();
|
|
178
179
|
|
|
179
180
|
const brandName = computed(() => props.displayName ?? brand.name);
|
|
180
181
|
const iconText = computed(() => props.icon ?? brand.logoText);
|
|
182
|
+
const subtitleText = computed(() =>
|
|
183
|
+
formatMessage(msg.value.setup.subtitle, { brand: brandName.value }),
|
|
184
|
+
);
|
|
181
185
|
|
|
182
186
|
const step = ref<'form' | 'mfa' | 'done'>('form');
|
|
183
187
|
const form = reactive({ token: '', email: '', password: '' });
|
|
@@ -195,15 +199,13 @@ const canCreate = computed(
|
|
|
195
199
|
!loading.value,
|
|
196
200
|
);
|
|
197
201
|
|
|
198
|
-
const
|
|
199
|
-
[SETUP_ERROR_CODES.SETUP_DISABLED]:
|
|
200
|
-
[SETUP_ERROR_CODES.INVALID_SETUP_TOKEN]:
|
|
201
|
-
[SETUP_ERROR_CODES.SETUP_ALREADY_DONE]:
|
|
202
|
-
|
|
203
|
-
[SETUP_ERROR_CODES.
|
|
204
|
-
|
|
205
|
-
'Diese E-Mail ist bereits vergeben. Wähle eine andere oder hebe den bestehenden User per CLI/DB zum SUPER_ADMIN an.',
|
|
206
|
-
};
|
|
202
|
+
const errorByCode = computed<Record<string, string>>(() => ({
|
|
203
|
+
[SETUP_ERROR_CODES.SETUP_DISABLED]: msg.value.setup.errorSetupDisabled,
|
|
204
|
+
[SETUP_ERROR_CODES.INVALID_SETUP_TOKEN]: msg.value.setup.errorInvalidToken,
|
|
205
|
+
[SETUP_ERROR_CODES.SETUP_ALREADY_DONE]: msg.value.setup.errorAlreadyDone,
|
|
206
|
+
[SETUP_ERROR_CODES.INVALID_EMAIL]: msg.value.setup.errorInvalidEmail,
|
|
207
|
+
[SETUP_ERROR_CODES.EMAIL_EXISTS]: msg.value.setup.errorEmailExists,
|
|
208
|
+
}));
|
|
207
209
|
|
|
208
210
|
// Goes through the injected HttpClient (consumer's auth/baseURL apply);
|
|
209
211
|
// maps the error code from the body to a readable message.
|
|
@@ -213,7 +215,8 @@ async function postJson<T>(path: string, body: unknown): Promise<T> {
|
|
|
213
215
|
} catch (err) {
|
|
214
216
|
if (err instanceof HttpJsonError) {
|
|
215
217
|
throw new Error(
|
|
216
|
-
(err.code &&
|
|
218
|
+
(err.code && errorByCode.value[err.code]) ||
|
|
219
|
+
formatMessage(msg.value.setup.errorHttp, { status: err.status }),
|
|
217
220
|
);
|
|
218
221
|
}
|
|
219
222
|
throw err;
|
|
@@ -232,7 +235,7 @@ async function submitCreate(): Promise<void> {
|
|
|
232
235
|
});
|
|
233
236
|
step.value = 'mfa';
|
|
234
237
|
} catch (err) {
|
|
235
|
-
errorMessage.value = err instanceof Error ? err.message :
|
|
238
|
+
errorMessage.value = err instanceof Error ? err.message : msg.value.setup.errorFailed;
|
|
236
239
|
} finally {
|
|
237
240
|
loading.value = false;
|
|
238
241
|
}
|
|
@@ -251,10 +254,11 @@ async function submitConfirm(): Promise<void> {
|
|
|
251
254
|
if (res.ok) {
|
|
252
255
|
step.value = 'done';
|
|
253
256
|
} else {
|
|
254
|
-
errorMessage.value =
|
|
257
|
+
errorMessage.value = msg.value.setup.errorCodeInvalid;
|
|
255
258
|
}
|
|
256
259
|
} catch (err) {
|
|
257
|
-
errorMessage.value =
|
|
260
|
+
errorMessage.value =
|
|
261
|
+
err instanceof Error ? err.message : msg.value.setup.errorConfirmFailed;
|
|
258
262
|
} finally {
|
|
259
263
|
loading.value = false;
|
|
260
264
|
}
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
flat
|
|
7
7
|
dense
|
|
8
8
|
icon="arrow_back"
|
|
9
|
-
:label="
|
|
9
|
+
:label="labels.back"
|
|
10
10
|
:to="backRoute"
|
|
11
11
|
class="sa-tenant-detail__back"
|
|
12
12
|
/>
|
|
13
|
-
<h1 class="sa-page-head__title">{{ data?.name ??
|
|
13
|
+
<h1 class="sa-page-head__title">{{ data?.name ?? labels.title }}</h1>
|
|
14
14
|
<p v-if="data" class="sa-page-head__sub">
|
|
15
|
-
{{
|
|
15
|
+
{{ labels.slug }}: <code>{{ data.slug }}</code>
|
|
16
16
|
</p>
|
|
17
17
|
</div>
|
|
18
18
|
<slot name="header-actions" :data="data" :reload="load" />
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
<div class="sa-tenant-detail__body">
|
|
22
22
|
<div v-if="loading" class="sa-tenant-detail__state">
|
|
23
|
-
<q-spinner size="32px" />
|
|
23
|
+
<q-spinner size="32px" /> {{ common.loading }}
|
|
24
24
|
</div>
|
|
25
25
|
|
|
26
26
|
<template v-else-if="data">
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<div class="sa-card q-mb-md">
|
|
29
29
|
<header class="sa-tenant-detail__card-head">
|
|
30
30
|
<div>
|
|
31
|
-
<h2 class="sa-card__title">{{
|
|
31
|
+
<h2 class="sa-card__title">{{ labels.masterData }}</h2>
|
|
32
32
|
<p v-if="stammdatenSub" class="sa-tenant-detail__card-sub">
|
|
33
33
|
{{ stammdatenSub }}
|
|
34
34
|
</p>
|
|
@@ -49,24 +49,24 @@
|
|
|
49
49
|
</header>
|
|
50
50
|
<slot name="stammdaten" :data="data">
|
|
51
51
|
<div class="sa-tenant-detail__grid">
|
|
52
|
-
<KvBlock :label="
|
|
52
|
+
<KvBlock :label="labels.plan" :value="data.subscription?.plan ?? '—'" />
|
|
53
53
|
<KvBlock
|
|
54
|
-
:label="
|
|
54
|
+
:label="labels.status"
|
|
55
55
|
:value="data.subscription?.status ?? '—'"
|
|
56
56
|
/>
|
|
57
57
|
<KvBlock
|
|
58
|
-
:label="
|
|
59
|
-
:value="data.subscription?.isPilot ?
|
|
58
|
+
:label="labels.pilot"
|
|
59
|
+
:value="data.subscription?.isPilot ? common.yes : common.no"
|
|
60
60
|
/>
|
|
61
61
|
<KvBlock
|
|
62
|
-
:label="
|
|
62
|
+
:label="labels.trialEnd"
|
|
63
63
|
:value="formatDate(data.subscription?.trialEndsAt)"
|
|
64
64
|
/>
|
|
65
65
|
<KvBlock
|
|
66
|
-
:label="
|
|
66
|
+
:label="labels.pilotEnd"
|
|
67
67
|
:value="formatDate(data.subscription?.pilotEndsAt)"
|
|
68
68
|
/>
|
|
69
|
-
<KvBlock v-if="data.vatId" :label="
|
|
69
|
+
<KvBlock v-if="data.vatId" :label="labels.vatId" :value="data.vatId" />
|
|
70
70
|
<slot name="extra-stammdaten" :data="data" />
|
|
71
71
|
</div>
|
|
72
72
|
</slot>
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
|
|
75
75
|
<!-- Usage -->
|
|
76
76
|
<div v-if="verbrauchFields.length > 0" class="sa-card q-mb-md">
|
|
77
|
-
<h3 class="sa-card__title">{{
|
|
77
|
+
<h3 class="sa-card__title">{{ labels.usage }}</h3>
|
|
78
78
|
<div class="sa-tenant-detail__grid">
|
|
79
79
|
<KvBlock
|
|
80
80
|
v-for="(field, i) in verbrauchFields"
|
|
@@ -87,11 +87,11 @@
|
|
|
87
87
|
|
|
88
88
|
<!-- Users -->
|
|
89
89
|
<div v-if="showUsers && data.users" class="sa-card q-mb-md">
|
|
90
|
-
<h3 class="sa-card__title">{{
|
|
90
|
+
<h3 class="sa-card__title">{{ labels.users }}</h3>
|
|
91
91
|
<q-table
|
|
92
92
|
flat
|
|
93
93
|
:rows="data.users"
|
|
94
|
-
:columns="userColumns ??
|
|
94
|
+
:columns="userColumns ?? defaultUserColumns"
|
|
95
95
|
row-key="id"
|
|
96
96
|
:pagination="{ rowsPerPage: 0 }"
|
|
97
97
|
hide-pagination
|
|
@@ -125,12 +125,14 @@
|
|
|
125
125
|
import { computed, onMounted, ref, toRef } from 'vue';
|
|
126
126
|
import type { RouteLocationRaw } from 'vue-router';
|
|
127
127
|
import type { QTableColumn } from 'quasar';
|
|
128
|
-
import {
|
|
128
|
+
import { useSuperAdminNotify } from '../quasar/notify.js';
|
|
129
129
|
import type { AdminManifest, TenantActionDef, TenantDto } from '@saasicat/types';
|
|
130
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
130
131
|
import KvBlock from '../components/KvBlock.vue';
|
|
131
132
|
import MfaPromptDialog from '../components/MfaPromptDialog.vue';
|
|
132
133
|
import TenantActionConfirmDialog from '../components/TenantActionConfirmDialog.vue';
|
|
133
|
-
import {
|
|
134
|
+
import { useSaMessages } from '../vue/use-super-admin-i18n.js';
|
|
135
|
+
import { useTenantActionFlow } from '../vue/use-tenant-action-flow.js';
|
|
134
136
|
|
|
135
137
|
export interface TenantDetailData {
|
|
136
138
|
id: string;
|
|
@@ -185,22 +187,30 @@ const props = withDefaults(
|
|
|
185
187
|
{
|
|
186
188
|
verbrauchFields: () => [],
|
|
187
189
|
showUsers: true,
|
|
188
|
-
backLabel: 'Mandanten-Liste',
|
|
189
|
-
titleLabel: 'Mandant',
|
|
190
|
-
slugLabel: 'Slug',
|
|
191
|
-
stammdatenLabel: 'Stammdaten',
|
|
192
|
-
planLabel: 'Plan',
|
|
193
|
-
statusLabel: 'Status',
|
|
194
|
-
pilotLabel: 'Pilot',
|
|
195
|
-
trialEndLabel: 'Trial-Ende',
|
|
196
|
-
pilotEndLabel: 'Pilot-Ende',
|
|
197
|
-
vatIdLabel: 'USt-IdNr.',
|
|
198
|
-
verbrauchLabel: 'Verbrauch',
|
|
199
|
-
usersLabel: 'User',
|
|
200
190
|
},
|
|
201
191
|
);
|
|
202
192
|
|
|
203
|
-
const
|
|
193
|
+
const msg = useSaMessages('tenants');
|
|
194
|
+
const common = useSaMessages('common');
|
|
195
|
+
|
|
196
|
+
// Every label stays overridable via props — only the German literals moved
|
|
197
|
+
// into the catalog.
|
|
198
|
+
const labels = computed(() => ({
|
|
199
|
+
back: props.backLabel ?? msg.value.detail.backToList,
|
|
200
|
+
title: props.titleLabel ?? msg.value.tenant,
|
|
201
|
+
slug: props.slugLabel ?? msg.value.detail.slug,
|
|
202
|
+
masterData: props.stammdatenLabel ?? msg.value.detail.masterData,
|
|
203
|
+
plan: props.planLabel ?? msg.value.plan,
|
|
204
|
+
status: props.statusLabel ?? common.value.status,
|
|
205
|
+
pilot: props.pilotLabel ?? msg.value.detail.pilot,
|
|
206
|
+
trialEnd: props.trialEndLabel ?? msg.value.detail.trialEnd,
|
|
207
|
+
pilotEnd: props.pilotEndLabel ?? msg.value.detail.pilotEnd,
|
|
208
|
+
vatId: props.vatIdLabel ?? msg.value.detail.vatId,
|
|
209
|
+
usage: props.verbrauchLabel ?? msg.value.detail.usage,
|
|
210
|
+
users: props.usersLabel ?? msg.value.detail.users,
|
|
211
|
+
}));
|
|
212
|
+
|
|
213
|
+
const notify = useSuperAdminNotify();
|
|
204
214
|
const data = ref<TenantDetailData | null>(null);
|
|
205
215
|
const loading = ref(false);
|
|
206
216
|
|
|
@@ -250,7 +260,10 @@ function showMfaDialog(def: TenantActionDef, ctx: { row: TenantDto }): Promise<s
|
|
|
250
260
|
return new Promise((resolve) => {
|
|
251
261
|
mfaState.value = {
|
|
252
262
|
show: true,
|
|
253
|
-
description:
|
|
263
|
+
description: formatMessage(msg.value.actions.mfaDescription, {
|
|
264
|
+
action: def.label,
|
|
265
|
+
tenant: ctx.row.name,
|
|
266
|
+
}),
|
|
254
267
|
error: '',
|
|
255
268
|
};
|
|
256
269
|
pendingMfaResolve = (code) => {
|
|
@@ -317,7 +330,7 @@ const tenantRow = computed<TenantDto | null>(() => {
|
|
|
317
330
|
const flow = useTenantActionFlow<TenantDto>(manifestRef, {
|
|
318
331
|
confirm: showConfirmDialog,
|
|
319
332
|
mfa: showMfaDialog,
|
|
320
|
-
notify
|
|
333
|
+
notify,
|
|
321
334
|
onSuccess: () => void load(),
|
|
322
335
|
visibleForRow: (def, row) => {
|
|
323
336
|
if (def.actionKey === 'tenants.suspend') return row.isActive;
|
|
@@ -347,34 +360,35 @@ function toneColor(actionKey: string): string {
|
|
|
347
360
|
return 'primary';
|
|
348
361
|
}
|
|
349
362
|
|
|
350
|
-
const
|
|
351
|
-
{ name: 'email', label:
|
|
363
|
+
const defaultUserColumns = computed<QTableColumn[]>(() => [
|
|
364
|
+
{ name: 'email', label: msg.value.detail.userEmail, field: 'email', align: 'left' },
|
|
352
365
|
{
|
|
353
366
|
name: 'name',
|
|
354
|
-
label:
|
|
367
|
+
label: common.value.name,
|
|
355
368
|
field: (r: unknown) => {
|
|
356
369
|
const row = r as Record<string, unknown>;
|
|
357
370
|
return `${row.firstName ?? ''} ${row.lastName ?? ''}`.trim();
|
|
358
371
|
},
|
|
359
372
|
align: 'left',
|
|
360
373
|
},
|
|
361
|
-
{ name: 'role', label:
|
|
374
|
+
{ name: 'role', label: msg.value.detail.userRole, field: 'role', align: 'left' },
|
|
362
375
|
{
|
|
363
376
|
name: 'status',
|
|
364
|
-
label:
|
|
365
|
-
field: (r: unknown) =>
|
|
377
|
+
label: common.value.status,
|
|
378
|
+
field: (r: unknown) =>
|
|
379
|
+
(r as Record<string, unknown>).isActive ? common.value.active : common.value.inactive,
|
|
366
380
|
align: 'left',
|
|
367
381
|
},
|
|
368
382
|
{
|
|
369
383
|
name: 'lastLogin',
|
|
370
|
-
label:
|
|
384
|
+
label: msg.value.detail.userLastLogin,
|
|
371
385
|
field: (r: unknown) => {
|
|
372
386
|
const v = (r as Record<string, unknown>).lastLoginAt;
|
|
373
387
|
return v ? String(v).slice(0, 10) : '—';
|
|
374
388
|
},
|
|
375
389
|
align: 'left',
|
|
376
390
|
},
|
|
377
|
-
];
|
|
391
|
+
]);
|
|
378
392
|
</script>
|
|
379
393
|
|
|
380
394
|
<style scoped>
|