@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.
- package/dist/{catalog-JXdKdIqG.d.cts → catalog-DJcfm5N2.d.cts} +21 -7
- package/dist/{catalog-JXdKdIqG.d.ts → catalog-DJcfm5N2.d.ts} +21 -7
- package/dist/{chunk-DPTIOQXX.js → chunk-F7NRM6KI.js} +56 -28
- package/dist/{chunk-RVG6LQHL.js → chunk-LY52T4N4.js} +21 -2
- package/dist/{chunk-ORX3ZG47.js → chunk-XMMFN2WJ.js} +74 -3
- package/dist/client/index.cjs +134 -29
- package/dist/client/index.d.cts +53 -3
- package/dist/client/index.d.ts +53 -3
- package/dist/client/index.js +14 -2
- package/dist/index.cjs +321 -162
- package/dist/index.d.cts +30 -8
- package/dist/index.d.ts +30 -8
- package/dist/index.js +176 -133
- package/dist/quasar/index.cjs +78 -29
- package/dist/quasar/index.d.cts +2 -2
- package/dist/quasar/index.d.ts +2 -2
- package/dist/quasar/index.js +6 -2
- package/dist/testing-e2e/admin-pages-suite.d.cts +37 -0
- package/dist/testing-e2e/admin-pages-suite.d.ts +37 -0
- package/dist/{use-super-admin-i18n-BlqcD0N7.d.ts → use-super-admin-i18n-CHNdsSlm.d.ts} +34 -7
- package/dist/{use-super-admin-i18n-1nCOkvgi.d.cts → use-super-admin-i18n-CgTuNi8h.d.cts} +34 -7
- package/package.json +18 -8
- package/src/client/i18n/messages/bundles.ts +0 -2
- package/src/client/i18n/messages/common.ts +24 -0
- package/src/client/i18n/messages/discovery.ts +2 -2
- package/src/client/i18n/messages/marketing.ts +2 -4
- package/src/client/i18n/messages/plan-detail.ts +0 -4
- package/src/client/i18n/messages/plans.ts +20 -8
- package/src/client/i18n/messages/tenants.ts +0 -2
- package/src/client/index.ts +1 -0
- package/src/client/manifest-loader.ts +1 -1
- package/src/client/resolve-plans.ts +144 -0
- package/src/components/BundleVersionPublishDialog.vue +6 -6
- package/src/components/KvBlock.vue +4 -4
- package/src/components/MarketingPromotionsTab.vue +34 -48
- package/src/components/MfaPromptDialog.vue +8 -2
- package/src/components/TenantActionConfirmDialog.vue +4 -4
- package/src/components/VersionDiffPreview.vue +7 -7
- package/src/components/admin-page/AdminBody.vue +40 -0
- package/src/components/admin-page/AdminFilters.vue +12 -0
- package/src/components/admin-page/AdminHero.vue +49 -0
- package/src/components/admin-page/AdminKpi.vue +84 -0
- package/src/components/admin-page/AdminPage.vue +16 -0
- package/src/components/admin-page/AdminPaginator.vue +195 -0
- package/src/components/admin-page/AdminRefreshBtn.vue +39 -0
- package/src/components/admin-page/AdminSection.vue +53 -0
- package/src/components/admin-page/AdminStatistics.vue +40 -0
- package/src/components/admin-page/AdminTable.vue +175 -0
- package/src/components/bundle-editor/BundleCreatePanel.vue +23 -23
- package/src/components/bundle-editor/BundleFeaturesEditor.vue +7 -7
- package/src/components/bundle-editor/BundlePlanCompatPicker.vue +9 -9
- package/src/components/bundle-editor/BundleQuotasEditor.vue +11 -11
- package/src/components/bundle-editor/BundleStatusBanner.vue +6 -6
- package/src/components/bundle-editor/BundleVersionInlineEditor.vue +18 -18
- package/src/components/bundle-editor/BundleVersionStrip.vue +12 -12
- package/src/components/dialogs/PilotCreateDialog.vue +12 -12
- package/src/components/dialogs/PilotEditDialog.vue +7 -7
- package/src/components/dialogs/PromoCodeCreateDialog.vue +8 -8
- package/src/components/dialogs/PromoCodeDialogFields.vue +33 -19
- package/src/components/dialogs/PromoCodeEditDialog.vue +10 -10
- package/src/components/plan/PlanGrid.vue +1 -1
- package/src/components/plan-create-dialog/PlanCreateDialog.vue +34 -46
- package/src/components/plan-detail/PlanAuditLog.vue +7 -8
- package/src/components/plan-detail/PlanDetail.vue +95 -292
- package/src/components/plan-detail/PlanDetailKpis.vue +22 -27
- package/src/components/plan-detail/PlanTitleEdit.vue +133 -0
- package/src/components/plan-detail/PlanVersionDiffPanel.vue +5 -8
- package/src/components/plan-detail/PlanVersionsPanel.vue +9 -11
- package/src/components/plan-list/PlanList.vue +206 -457
- package/src/components/plan-matrix/PlanMatrix.vue +66 -183
- package/src/components/plan-review/PlanReview.vue +191 -275
- package/src/components/plan-version-editor/PlanCatalogPreview.vue +7 -5
- package/src/components/plan-version-editor/PlanVersionEditor.vue +200 -295
- package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +23 -55
- package/src/index.ts +1 -0
- package/src/pages-standard/AdminLayout.vue +38 -12
- package/src/pages-standard/AdminManifestErrorPage.vue +79 -9
- package/src/pages-standard/AuditPage.vue +65 -109
- package/src/pages-standard/BundlesPage.vue +146 -179
- package/src/pages-standard/DashboardPage.vue +59 -154
- package/src/pages-standard/DiscoveryPage.vue +172 -227
- package/src/pages-standard/EmailHistoryPage.vue +118 -159
- package/src/pages-standard/MarketingCatalogPage.vue +399 -440
- package/src/pages-standard/PilotsPage.vue +69 -117
- package/src/pages-standard/PlansPage.vue +240 -112
- package/src/pages-standard/PlatformEmailPage.vue +56 -91
- package/src/pages-standard/PromoCodeDetailPage.vue +49 -74
- package/src/pages-standard/PromoCodesPage.vue +95 -128
- package/src/pages-standard/SubscriptionsPage.vue +19 -52
- package/src/pages-standard/SuperAdminLoginPage.vue +12 -12
- package/src/pages-standard/SuperAdminSetupWizard.vue +22 -18
- package/src/pages-standard/TenantDetailPage.vue +100 -191
- package/src/pages-standard/TenantsPage.vue +190 -295
- package/src/pages-standard/UsersPage.vue +89 -157
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -17
- package/src/pages-standard/bundles-page/BundlesKpis.vue +13 -22
- package/src/pages-standard/bundles-page/BundlesToolbar.vue +63 -0
- package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +10 -10
- package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -5
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +16 -16
- package/src/pages-standard/discovery-page/DiscoveryKpis.vue +31 -27
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +7 -7
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +111 -73
- package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +43 -62
- package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +53 -35
- package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +7 -7
- package/src/pages-standard/plan-versions/PlanDiffCard.vue +6 -6
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +6 -6
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +16 -16
- package/src/pages-standard/plans-page/PlanBundleOverview.vue +14 -29
- package/src/pages-standard/plans-page/PlanPublishDialog.vue +1 -1
- package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
- package/src/pages-standard/sa-theme.css +552 -86
- package/src/pages-standard/tenant-detail/TenantMasterData.vue +28 -0
- package/src/pages-standard/tenant-detail/TenantUsage.vue +31 -0
- package/src/pages-standard/tenant-detail/TenantUsers.vue +15 -0
- package/src/pages-standard/tenant-detail/types.ts +38 -0
- package/src/pages-standard/tenants/StatusPill.vue +2 -2
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +25 -25
- package/src/pages-tenant/OnboardingConfigurator.vue +1 -5
- package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
- package/src/pages-tenant/TenantPlanSection.vue +12 -20
- package/src/quasar/create-super-admin-app.ts +4 -0
- package/src/vue/entitlement-provider.ts +0 -1
- package/src/vue/feature-router-guard.ts +0 -1
- package/src/vue/super-admin-context.ts +106 -1
- package/src/vue/use-api-list.ts +2 -1
- package/src/vue/use-mfa-prompt.ts +72 -0
- package/src/vue/use-pagination.ts +63 -0
- package/src/vue/use-plans.ts +1 -2
- package/src/vue/use-sign-out.ts +90 -0
- package/src/vue/use-tenant-billing.ts +1 -1
- package/src/vue/use-tenant-manifest.ts +0 -1
- package/src/components/KpiCard.vue +0 -53
- package/src/components/plan-cockpit/PlanCockpit.vue +0 -1012
- package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +0 -72
- package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +0 -100
- package/src/components/plan-cockpit/PlanCockpitHeader.vue +0 -101
- package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +0 -112
- package/src/components/plan-cockpit/PlanCockpitKpis.vue +0 -68
- package/src/components/plan-cockpit/PlanCockpitVersions.vue +0 -251
- package/src/components/plan-cockpit/types.ts +0 -72
- package/src/components/plan-detail/PlanDetailHeader.vue +0 -194
- package/src/pages-standard/bundles-page/BundlesHeader.vue +0 -68
- package/src/pages-standard/discovery-page/DiscoveryHeader.vue +0 -34
|
@@ -1,145 +1,136 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
</div>
|
|
66
|
-
<div>
|
|
67
|
-
<div class="sa-tenants__name">{{ row.name }}</div>
|
|
68
|
-
<div class="sa-tenants__slug">{{ row.slug }}</div>
|
|
69
|
-
</div>
|
|
2
|
+
<AdminPage class="sa-tenants">
|
|
3
|
+
<AdminHero :title="msg.list.title" :subtitle="subtitle" />
|
|
4
|
+
|
|
5
|
+
<AdminBody>
|
|
6
|
+
<q-banner v-if="error" class="bg-red-1 text-red-9 q-mb-md" rounded>
|
|
7
|
+
<strong>{{ common.error }}:</strong> {{ error.message }}
|
|
8
|
+
</q-banner>
|
|
9
|
+
|
|
10
|
+
<AdminSection class="sa-tenants__card">
|
|
11
|
+
<AdminFilters class="q-mb-lg">
|
|
12
|
+
<q-input
|
|
13
|
+
v-model="searchInput"
|
|
14
|
+
outlined
|
|
15
|
+
dense
|
|
16
|
+
clearable
|
|
17
|
+
:label="msg.list.searchPlaceholder"
|
|
18
|
+
debounce="250"
|
|
19
|
+
@update:model-value="applyFilter"
|
|
20
|
+
>
|
|
21
|
+
<template #prepend><q-icon name="search" size="18px" /></template>
|
|
22
|
+
</q-input>
|
|
23
|
+
<q-select
|
|
24
|
+
v-model="statusFilter"
|
|
25
|
+
outlined
|
|
26
|
+
dense
|
|
27
|
+
clearable
|
|
28
|
+
emit-value
|
|
29
|
+
map-options
|
|
30
|
+
:options="statusSelectOptions"
|
|
31
|
+
:label="msg.list.allStatuses"
|
|
32
|
+
@update:model-value="applyFilter"
|
|
33
|
+
/>
|
|
34
|
+
<q-select
|
|
35
|
+
v-if="planOptions && planOptions.length > 0"
|
|
36
|
+
v-model="planFilter"
|
|
37
|
+
outlined
|
|
38
|
+
dense
|
|
39
|
+
clearable
|
|
40
|
+
:options="planOptions"
|
|
41
|
+
:label="resolvedPlanFilterLabel"
|
|
42
|
+
@update:model-value="applyFilter"
|
|
43
|
+
/>
|
|
44
|
+
<slot name="filters-extra" />
|
|
45
|
+
</AdminFilters>
|
|
46
|
+
|
|
47
|
+
<AdminTable
|
|
48
|
+
server-side
|
|
49
|
+
:rows="items"
|
|
50
|
+
:columns="tenantColumns"
|
|
51
|
+
:loading="loading"
|
|
52
|
+
:page="page"
|
|
53
|
+
:rows-per-page="rowsPerPage"
|
|
54
|
+
:total="total"
|
|
55
|
+
:empty-text="msg.list.empty"
|
|
56
|
+
storage-key="tenants"
|
|
57
|
+
@update:page="goToPage"
|
|
58
|
+
@update:rows-per-page="setPageSize"
|
|
59
|
+
>
|
|
60
|
+
<template #body-cell-tenant="{ row }">
|
|
61
|
+
<q-td>
|
|
62
|
+
<div class="sa-tenants__tenant">
|
|
63
|
+
<div class="sa-tenants__avatar" :style="avatarStyle(row)">
|
|
64
|
+
{{ tenantInitials(row.name) }}
|
|
70
65
|
</div>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<span
|
|
75
|
-
class="sa-tenants__plan-dot"
|
|
76
|
-
:style="{ background: planAccentFor(row) }"
|
|
77
|
-
/>
|
|
78
|
-
{{ planLabel(row) }}
|
|
79
|
-
</span>
|
|
80
|
-
</td>
|
|
81
|
-
<td>
|
|
82
|
-
<div class="sa-tenants__pills">
|
|
83
|
-
<slot name="status-pills" :row="row">
|
|
84
|
-
<StatusPill
|
|
85
|
-
v-for="(p, i) in resolvedPills(row)"
|
|
86
|
-
:key="i"
|
|
87
|
-
:label="p.label"
|
|
88
|
-
:icon="p.icon"
|
|
89
|
-
:tone="p.tone"
|
|
90
|
-
/>
|
|
91
|
-
</slot>
|
|
92
|
-
</div>
|
|
93
|
-
</td>
|
|
94
|
-
<td v-if="usageFields.length > 0" class="num">
|
|
95
|
-
<div
|
|
96
|
-
v-for="(uf, i) in usageFields"
|
|
97
|
-
:key="i"
|
|
98
|
-
class="sa-tenants__usage"
|
|
99
|
-
>
|
|
100
|
-
<q-icon :name="uf.icon" size="11px" />
|
|
101
|
-
{{ usageValue(row, uf) }}
|
|
66
|
+
<div>
|
|
67
|
+
<div class="sa-tenants__name">{{ row.name }}</div>
|
|
68
|
+
<div class="sa-tenants__slug">{{ row.slug }}</div>
|
|
102
69
|
</div>
|
|
103
|
-
</
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
70
|
+
</div>
|
|
71
|
+
</q-td>
|
|
72
|
+
</template>
|
|
73
|
+
|
|
74
|
+
<template #body-cell-plan="{ row }">
|
|
75
|
+
<q-td>
|
|
76
|
+
<span class="sa-tenants__plan">
|
|
77
|
+
<span
|
|
78
|
+
class="sa-tenants__plan-dot"
|
|
79
|
+
:style="{ background: planAccentFor(row) }"
|
|
80
|
+
/>
|
|
81
|
+
{{ planLabel(row) }}
|
|
82
|
+
</span>
|
|
83
|
+
</q-td>
|
|
84
|
+
</template>
|
|
85
|
+
|
|
86
|
+
<template #body-cell-status="{ row }">
|
|
87
|
+
<q-td>
|
|
88
|
+
<div class="sa-tenants__pills">
|
|
89
|
+
<slot name="status-pills" :row="row">
|
|
90
|
+
<StatusPill
|
|
91
|
+
v-for="(p, i) in resolvedPills(row)"
|
|
92
|
+
:key="i"
|
|
93
|
+
:label="p.label"
|
|
94
|
+
:icon="p.icon"
|
|
95
|
+
:tone="p.tone"
|
|
96
|
+
/>
|
|
125
97
|
</slot>
|
|
126
|
-
</
|
|
127
|
-
</
|
|
128
|
-
</
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
98
|
+
</div>
|
|
99
|
+
</q-td>
|
|
100
|
+
</template>
|
|
101
|
+
|
|
102
|
+
<template #body-cell-usage="{ row }">
|
|
103
|
+
<q-td class="text-right">
|
|
104
|
+
<div v-for="(uf, i) in usageFields" :key="i" class="sa-tenants__usage">
|
|
105
|
+
<q-icon :name="uf.icon" size="11px" />
|
|
106
|
+
{{ usageValue(row, uf) }}
|
|
107
|
+
</div>
|
|
108
|
+
</q-td>
|
|
109
|
+
</template>
|
|
110
|
+
|
|
111
|
+
<template #body-cell-createdAt="{ row }">
|
|
112
|
+
<q-td class="text-right sa-tenants__mono">{{ formatCreatedAt(row) }}</q-td>
|
|
113
|
+
</template>
|
|
114
|
+
|
|
115
|
+
<template v-if="hasActions" #row-actions="{ row }">
|
|
116
|
+
<slot name="row-actions" :row="row" :actions="visibleActions(row)">
|
|
117
|
+
<component
|
|
118
|
+
:is="action.to ? 'a' : 'button'"
|
|
119
|
+
v-for="action in visibleActions(row)"
|
|
120
|
+
:key="action.id"
|
|
121
|
+
:href="action.to ? action.to(row) : undefined"
|
|
122
|
+
class="sa-tenants__icon-btn"
|
|
123
|
+
:class="action.tone ? `sa-tenants__icon-btn--${action.tone}` : ''"
|
|
124
|
+
:title="action.label"
|
|
125
|
+
@click="action.handler ? action.handler(row) : undefined"
|
|
126
|
+
>
|
|
127
|
+
<q-icon :name="action.icon" size="15px" />
|
|
128
|
+
</component>
|
|
129
|
+
</slot>
|
|
130
|
+
</template>
|
|
131
|
+
</AdminTable>
|
|
132
|
+
</AdminSection>
|
|
133
|
+
</AdminBody>
|
|
143
134
|
|
|
144
135
|
<!-- Manifest-Driven Action Flow: only mounted when the `manifest` prop
|
|
145
136
|
is set AND `manifestActionsEnabled` is true (default when manifest
|
|
@@ -162,14 +153,20 @@
|
|
|
162
153
|
@cancel="manifestFlow.onConfirmCancel"
|
|
163
154
|
/>
|
|
164
155
|
</template>
|
|
165
|
-
</
|
|
156
|
+
</AdminPage>
|
|
166
157
|
</template>
|
|
167
158
|
|
|
168
159
|
<script setup lang="ts">
|
|
160
|
+
import AdminTable from '../components/admin-page/AdminTable.vue';
|
|
169
161
|
import { computed, ref, watch } from 'vue';
|
|
162
|
+
import type { QTableColumn } from 'quasar';
|
|
163
|
+
import AdminBody from '../components/admin-page/AdminBody.vue';
|
|
164
|
+
import AdminFilters from '../components/admin-page/AdminFilters.vue';
|
|
165
|
+
import AdminHero from '../components/admin-page/AdminHero.vue';
|
|
166
|
+
import AdminSection from '../components/admin-page/AdminSection.vue';
|
|
167
|
+
import AdminPage from '../components/admin-page/AdminPage.vue';
|
|
170
168
|
import type { AdminManifest, TenantActionDef, TenantDto, TenantListFilter } from '@saasicat/types';
|
|
171
169
|
import type { HttpClient } from '../client/types.js';
|
|
172
|
-
import { formatMessage } from '../client/i18n/format.js';
|
|
173
170
|
import { useSaMessages, useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
|
|
174
171
|
import { useTenants } from '../vue/use-tenants.js';
|
|
175
172
|
import {
|
|
@@ -336,6 +333,9 @@ const msg = useSaMessages('tenants');
|
|
|
336
333
|
const common = useSaMessages('common');
|
|
337
334
|
const { intlLocale } = useSuperAdminI18n();
|
|
338
335
|
|
|
336
|
+
const statusSelectOptions = computed(() =>
|
|
337
|
+
resolvedStatusOptions.value.map((o) => ({ label: o.label, value: o.value })),
|
|
338
|
+
);
|
|
339
339
|
const resolvedStatusOptions = computed<ReadonlyArray<{ value: string; label: string }>>(
|
|
340
340
|
() =>
|
|
341
341
|
props.statusOptions ?? [
|
|
@@ -357,28 +357,42 @@ const list = useTenants<TenantRow>({
|
|
|
357
357
|
http: props.http,
|
|
358
358
|
getAuthToken: props.getAuthToken,
|
|
359
359
|
});
|
|
360
|
-
|
|
360
|
+
// Aliased: the `pageSize` prop is the INITIAL size, `list.pageSize` is the
|
|
361
|
+
// current one. Sharing one name makes the template ambiguous about which of
|
|
362
|
+
// the two it reads.
|
|
363
|
+
const { items, page, pageSize: rowsPerPage, total, loading, error, goToPage, setPageSize } = list;
|
|
361
364
|
|
|
362
365
|
setPageSize(props.pageSize);
|
|
363
366
|
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
367
|
+
const tenantColumns = computed<QTableColumn[]>(() => {
|
|
368
|
+
const cols: QTableColumn[] = [
|
|
369
|
+
{ name: 'tenant', label: msg.value.tenant, field: 'name', align: 'left' },
|
|
370
|
+
];
|
|
371
|
+
if (props.showPlanColumn) {
|
|
372
|
+
cols.push({
|
|
373
|
+
name: 'plan',
|
|
374
|
+
label: resolvedPlanColumnLabel.value,
|
|
375
|
+
field: 'plan',
|
|
376
|
+
align: 'left',
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
cols.push({ name: 'status', label: common.value.status, field: 'status', align: 'left' });
|
|
380
|
+
if (props.usageFields.length > 0) {
|
|
381
|
+
cols.push({
|
|
382
|
+
name: 'usage',
|
|
383
|
+
label: msg.value.list.columnUsage,
|
|
384
|
+
field: 'id',
|
|
385
|
+
align: 'right',
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
cols.push({
|
|
389
|
+
name: 'createdAt',
|
|
390
|
+
label: msg.value.list.columnCreatedAt,
|
|
391
|
+
field: 'createdAt',
|
|
392
|
+
align: 'right',
|
|
393
|
+
});
|
|
394
|
+
return cols;
|
|
395
|
+
});
|
|
382
396
|
|
|
383
397
|
function applyFilter(): void {
|
|
384
398
|
// The status value is passed through unchanged. Apps configure the values
|
|
@@ -434,7 +448,6 @@ if (manifestFlow && typeof window !== 'undefined') {
|
|
|
434
448
|
manifestFlow.realOrphans,
|
|
435
449
|
(orphans) => {
|
|
436
450
|
if (orphans.length > 0) {
|
|
437
|
-
// eslint-disable-next-line no-console
|
|
438
451
|
console.warn(
|
|
439
452
|
'[PlatformTenantsPage] Manifest actions without a handler in createSuperAdminApp({ actions }):',
|
|
440
453
|
orphans,
|
|
@@ -456,7 +469,6 @@ const combinedActions = computed<TenantRowAction[]>(() => {
|
|
|
456
469
|
const filteredCustom = custom.filter((a) => {
|
|
457
470
|
if (a.actionKey && manifestKeys.has(a.actionKey)) {
|
|
458
471
|
if (typeof window !== 'undefined') {
|
|
459
|
-
// eslint-disable-next-line no-console
|
|
460
472
|
console.warn(
|
|
461
473
|
`[PlatformTenantsPage] Custom action "${a.id}" (actionKey="${a.actionKey}") ` +
|
|
462
474
|
`collides with a manifest action — the manifest wins.`,
|
|
@@ -518,111 +530,17 @@ function visibleActions(row: TenantRow): TenantRowAction[] {
|
|
|
518
530
|
</script>
|
|
519
531
|
|
|
520
532
|
<style scoped>
|
|
521
|
-
.
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
font-size: 22px;
|
|
533
|
-
color: var(--sa-heading, #0f172a);
|
|
534
|
-
letter-spacing: -0.01em;
|
|
535
|
-
}
|
|
536
|
-
.sa-tenants__sub {
|
|
537
|
-
margin: 4px 0 0;
|
|
538
|
-
color: var(--sa-muted-dark, #475569);
|
|
539
|
-
font-size: 13.5px;
|
|
540
|
-
line-height: 1.5;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
.sa-tenants__filter {
|
|
544
|
-
padding: 12px 28px;
|
|
545
|
-
display: flex;
|
|
546
|
-
gap: 10px;
|
|
547
|
-
flex-wrap: wrap;
|
|
548
|
-
}
|
|
549
|
-
.sa-tenants__search {
|
|
550
|
-
flex: 1;
|
|
551
|
-
min-width: 240px;
|
|
552
|
-
display: flex;
|
|
553
|
-
align-items: center;
|
|
554
|
-
gap: 6px;
|
|
555
|
-
background: #fff;
|
|
556
|
-
border: 1px solid var(--sa-border, #e2e8f0);
|
|
557
|
-
border-radius: 8px;
|
|
558
|
-
padding: 6px 10px;
|
|
559
|
-
}
|
|
560
|
-
.sa-tenants__search :deep(.q-icon) {
|
|
561
|
-
color: var(--sa-muted, #64748b);
|
|
562
|
-
}
|
|
563
|
-
.sa-tenants__search input {
|
|
564
|
-
flex: 1;
|
|
565
|
-
border: none;
|
|
566
|
-
outline: none;
|
|
567
|
-
background: transparent;
|
|
568
|
-
font-size: 13px;
|
|
569
|
-
font-family: inherit;
|
|
570
|
-
color: var(--sa-body, #1e293b);
|
|
571
|
-
min-width: 0;
|
|
572
|
-
}
|
|
573
|
-
.sa-tenants__clear {
|
|
574
|
-
background: transparent;
|
|
575
|
-
border: none;
|
|
576
|
-
cursor: pointer;
|
|
577
|
-
padding: 2px;
|
|
578
|
-
}
|
|
579
|
-
.sa-tenants__select {
|
|
580
|
-
padding: 7px 10px;
|
|
581
|
-
font-size: 12.5px;
|
|
582
|
-
font-family: inherit;
|
|
583
|
-
border: 1px solid var(--sa-border, #e2e8f0);
|
|
584
|
-
border-radius: 8px;
|
|
585
|
-
background: #fff;
|
|
586
|
-
cursor: pointer;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
.sa-tenants__card {
|
|
590
|
-
margin: 0 28px 28px;
|
|
591
|
-
background: #fff;
|
|
592
|
-
border: 1px solid var(--sa-border, #e2e8f0);
|
|
593
|
-
border-radius: 12px;
|
|
594
|
-
overflow: hidden;
|
|
595
|
-
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
|
596
|
-
}
|
|
597
|
-
.sa-tenants__wrap {
|
|
598
|
-
overflow-x: auto;
|
|
599
|
-
}
|
|
600
|
-
table {
|
|
601
|
-
width: 100%;
|
|
602
|
-
border-collapse: collapse;
|
|
603
|
-
font-size: 13px;
|
|
604
|
-
min-width: 800px;
|
|
605
|
-
}
|
|
606
|
-
thead tr {
|
|
607
|
-
background: #fafbfc;
|
|
608
|
-
}
|
|
609
|
-
th {
|
|
610
|
-
padding: 10px 14px;
|
|
611
|
-
font-size: 10.5px;
|
|
612
|
-
font-weight: 700;
|
|
613
|
-
letter-spacing: 0.08em;
|
|
614
|
-
color: var(--sa-muted, #64748b);
|
|
615
|
-
text-transform: uppercase;
|
|
616
|
-
text-align: left;
|
|
617
|
-
}
|
|
618
|
-
td {
|
|
619
|
-
padding: 11px 14px;
|
|
620
|
-
vertical-align: middle;
|
|
621
|
-
border-top: 1px solid var(--sa-border-soft, #f1f5f9);
|
|
622
|
-
}
|
|
623
|
-
.num {
|
|
624
|
-
text-align: right;
|
|
625
|
-
}
|
|
533
|
+
/* No table rules here on purpose — and not because they would be inert.
|
|
534
|
+
Content passed into a child component's slot keeps THIS component's scope
|
|
535
|
+
id, so the `table`, `thead`, `th`, `td` and `.num` rules that used to sit
|
|
536
|
+
here did reach `AdminTable`'s cells. That was the bug: they drew a second
|
|
537
|
+
border on top of the one AdminTable already draws, and the tenant list was
|
|
538
|
+
the only list in the package with doubled row separators. Removing them
|
|
539
|
+
took `border-top-width` from 1px back to 0px.
|
|
540
|
+
|
|
541
|
+
The rule to carry forward: styling a table here means overriding AdminTable
|
|
542
|
+
for one page. If a table needs to look different, that belongs in
|
|
543
|
+
AdminTable, behind a prop. */
|
|
626
544
|
.sa-tenants__mono {
|
|
627
545
|
font-family: var(--sa-font-mono, ui-monospace, monospace);
|
|
628
546
|
font-size: 12px;
|
|
@@ -648,11 +566,11 @@ td {
|
|
|
648
566
|
.sa-tenants__name {
|
|
649
567
|
font-size: 13px;
|
|
650
568
|
font-weight: 600;
|
|
651
|
-
color: var(--sa-heading,
|
|
569
|
+
color: var(--sa-heading, var(--sa-heading));
|
|
652
570
|
}
|
|
653
571
|
.sa-tenants__slug {
|
|
654
572
|
font-size: 11px;
|
|
655
|
-
color: var(--sa-muted,
|
|
573
|
+
color: var(--sa-muted, var(--sa-muted));
|
|
656
574
|
font-family: var(--sa-font-mono, ui-monospace, monospace);
|
|
657
575
|
}
|
|
658
576
|
|
|
@@ -678,16 +596,13 @@ td {
|
|
|
678
596
|
align-items: center;
|
|
679
597
|
gap: 4px;
|
|
680
598
|
font-size: 12px;
|
|
681
|
-
color: var(--sa-muted-dark,
|
|
599
|
+
color: var(--sa-muted-dark, var(--sa-muted-dark));
|
|
682
600
|
margin-left: 8px;
|
|
683
601
|
}
|
|
684
602
|
.sa-tenants__usage :deep(.q-icon) {
|
|
685
|
-
color: var(--sa-muted,
|
|
603
|
+
color: var(--sa-muted, var(--sa-muted));
|
|
686
604
|
}
|
|
687
605
|
|
|
688
|
-
.sa-tenants__actions {
|
|
689
|
-
white-space: nowrap;
|
|
690
|
-
}
|
|
691
606
|
.sa-tenants__icon-btn {
|
|
692
607
|
background: transparent;
|
|
693
608
|
border: none;
|
|
@@ -699,10 +614,10 @@ td {
|
|
|
699
614
|
align-items: center;
|
|
700
615
|
justify-content: center;
|
|
701
616
|
text-decoration: none;
|
|
702
|
-
color: var(--sa-muted,
|
|
617
|
+
color: var(--sa-muted, var(--sa-muted));
|
|
703
618
|
}
|
|
704
619
|
.sa-tenants__icon-btn:hover {
|
|
705
|
-
background:
|
|
620
|
+
background: var(--sa-border-soft);
|
|
706
621
|
}
|
|
707
622
|
.sa-tenants__icon-btn :deep(.q-icon) {
|
|
708
623
|
color: inherit;
|
|
@@ -722,24 +637,4 @@ td {
|
|
|
722
637
|
.sa-tenants__icon-btn--accent {
|
|
723
638
|
color: var(--sa-accent, #7c3aed);
|
|
724
639
|
}
|
|
725
|
-
|
|
726
|
-
.sa-tenants__empty {
|
|
727
|
-
padding: 40px 16px;
|
|
728
|
-
text-align: center;
|
|
729
|
-
color: var(--sa-muted, #64748b);
|
|
730
|
-
}
|
|
731
|
-
.sa-tenants__loading {
|
|
732
|
-
padding: 24px;
|
|
733
|
-
display: flex;
|
|
734
|
-
align-items: center;
|
|
735
|
-
gap: 12px;
|
|
736
|
-
color: var(--sa-muted, #64748b);
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
.sa-tenants__foot {
|
|
740
|
-
padding: 0 28px 28px;
|
|
741
|
-
text-align: right;
|
|
742
|
-
font-size: 12px;
|
|
743
|
-
color: var(--sa-muted, #64748b);
|
|
744
|
-
}
|
|
745
640
|
</style>
|