@saasicat/ui-vue 0.7.0 → 0.9.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/{chunk-A3W2N26K.js → chunk-66BUSVC5.js} +68 -217
- package/dist/{chunk-X5SQ5HMB.js → chunk-TBLXKSTR.js} +0 -137
- package/dist/{chunk-QZOSDCNP.js → chunk-TY2WYKME.js} +1 -1
- package/dist/client/index.cjs +180 -463
- package/dist/client/index.d.cts +32 -57
- package/dist/client/index.d.ts +32 -57
- package/dist/client/index.js +4 -6
- package/dist/index.cjs +273 -580
- package/dist/index.d.cts +10 -55
- package/dist/index.d.ts +10 -55
- package/dist/index.js +76 -101
- package/dist/{messages-7b0P8W75.d.ts → messages-BIYw32u1.d.cts} +0 -67
- package/dist/{messages-7b0P8W75.d.cts → messages-BIYw32u1.d.ts} +0 -67
- package/dist/quasar/index.cjs +0 -136
- package/dist/quasar/index.d.cts +2 -2
- package/dist/quasar/index.d.ts +2 -2
- package/dist/quasar/index.js +2 -2
- package/dist/{use-super-admin-i18n-B3v3-SWZ.d.ts → use-super-admin-i18n-CWNu_W3u.d.ts} +1 -1
- package/dist/{use-super-admin-i18n-DMktRVEt.d.cts → use-super-admin-i18n-DL_qI1BY.d.cts} +1 -1
- package/package.json +5 -5
- package/src/client/admin-resource-client.ts +112 -0
- package/src/client/i18n/messages/nav.ts +0 -2
- package/src/client/i18n/messages/plan-versions.ts +0 -143
- package/src/client/index.ts +1 -2
- package/src/client/nav-builder.ts +9 -4
- package/src/index.ts +0 -1
- package/src/pages-standard/AdminLayout.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +1 -1
- package/src/pages-standard/plan-versions/catalog-history.types.ts +37 -0
- package/src/pages-standard/plan-versions/format.ts +2 -38
- package/src/client/plan-versions-catalog.ts +0 -380
- package/src/pages-standard/PlanVersionsPage.vue +0 -220
- package/src/pages-standard/plan-versions/PlanVersionHeader.vue +0 -309
- package/src/pages-standard/plan-versions/PlanVersionStatusBadge.vue +0 -48
- package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +0 -326
- package/src/pages-standard/plan-versions/PlanVersionsKpi.vue +0 -65
- package/src/pages-standard/plan-versions/PlanVersionsList.vue +0 -315
- package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +0 -261
- package/src/pages-standard/plan-versions/types.ts +0 -33
- package/src/vue/use-plan-versions.ts +0 -83
package/dist/client/index.cjs
CHANGED
|
@@ -38,7 +38,7 @@ __export(client_exports, {
|
|
|
38
38
|
SA_MESSAGES: () => SA_MESSAGES,
|
|
39
39
|
buildRoutes: () => buildRoutes,
|
|
40
40
|
buildSidebar: () => buildSidebar,
|
|
41
|
-
|
|
41
|
+
createAdminResourceClient: () => createAdminResourceClient,
|
|
42
42
|
defaultHttpClient: () => defaultHttpClient,
|
|
43
43
|
defaultKvStore: () => defaultKvStore,
|
|
44
44
|
defaultSectionOrder: () => defaultSectionOrder,
|
|
@@ -46,7 +46,6 @@ __export(client_exports, {
|
|
|
46
46
|
formatCurrency: () => formatCurrency,
|
|
47
47
|
formatMessage: () => formatMessage,
|
|
48
48
|
getJson: () => getJson,
|
|
49
|
-
listOpenDrafts: () => listOpenDrafts,
|
|
50
49
|
mergeMessages: () => mergeMessages,
|
|
51
50
|
postJson: () => postJson,
|
|
52
51
|
resolveExtension: () => resolveExtension,
|
|
@@ -274,7 +273,6 @@ var navMessages = defineMessages(
|
|
|
274
273
|
subscriptions: "Abonnements",
|
|
275
274
|
promoCodes: "Promo-Codes",
|
|
276
275
|
plans: "Pl\xE4ne & Versionen",
|
|
277
|
-
planVersions: "Plan-Versionen",
|
|
278
276
|
audit: "Audit-Log",
|
|
279
277
|
users: "Benutzer",
|
|
280
278
|
pilots: "Piloten",
|
|
@@ -298,7 +296,6 @@ var navMessages = defineMessages(
|
|
|
298
296
|
subscriptions: "Subscriptions",
|
|
299
297
|
promoCodes: "Promo codes",
|
|
300
298
|
plans: "Plans & versions",
|
|
301
|
-
planVersions: "Plan versions",
|
|
302
299
|
audit: "Audit log",
|
|
303
300
|
users: "Users",
|
|
304
301
|
pilots: "Pilots",
|
|
@@ -324,7 +321,6 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
|
|
|
324
321
|
subscriptions: "/admin/subscriptions",
|
|
325
322
|
promoCodes: "/admin/promo-codes",
|
|
326
323
|
plans: "/admin/plans",
|
|
327
|
-
planVersions: "/admin/plan-versions",
|
|
328
324
|
audit: "/admin/audit",
|
|
329
325
|
users: "/admin/users",
|
|
330
326
|
pilots: "/admin/pilots",
|
|
@@ -334,13 +330,15 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
|
|
|
334
330
|
platformEmail: "/admin/platform-email",
|
|
335
331
|
platformEmailHistory: "/admin/platform-email-history"
|
|
336
332
|
};
|
|
333
|
+
function isSupportedStandardPageKey(key) {
|
|
334
|
+
return Object.hasOwn(DEFAULT_STANDARD_PAGE_ROUTES, key);
|
|
335
|
+
}
|
|
337
336
|
var DEFAULT_ICONS = {
|
|
338
337
|
dashboard: "dashboard",
|
|
339
338
|
tenants: "business",
|
|
340
339
|
subscriptions: "card_membership",
|
|
341
340
|
promoCodes: "local_activity",
|
|
342
341
|
plans: "workspace_premium",
|
|
343
|
-
planVersions: "history_edu",
|
|
344
342
|
audit: "history",
|
|
345
343
|
users: "people",
|
|
346
344
|
pilots: "flight_takeoff",
|
|
@@ -355,7 +353,6 @@ var PAGE_SECTIONS = {
|
|
|
355
353
|
discovery: "catalog",
|
|
356
354
|
bundles: "catalog",
|
|
357
355
|
plans: "catalog",
|
|
358
|
-
planVersions: "catalog",
|
|
359
356
|
marketingCatalog: "catalog",
|
|
360
357
|
promoCodes: "catalog",
|
|
361
358
|
tenants: "customers",
|
|
@@ -383,6 +380,7 @@ function buildRoutes(manifest, options = {}) {
|
|
|
383
380
|
const overrideIcons = { ...DEFAULT_ICONS, ...options.standardPageIcons };
|
|
384
381
|
const overrideNavSection = { ...defaultNavSections, ...options.standardPageNavSection };
|
|
385
382
|
for (const key of Object.keys(standard)) {
|
|
383
|
+
if (!isSupportedStandardPageKey(key)) continue;
|
|
386
384
|
const def = standard[key];
|
|
387
385
|
if (!def?.enabled) continue;
|
|
388
386
|
const cap = def.requiredCapability ?? null;
|
|
@@ -623,471 +621,83 @@ var BatchColumnFetcher = class {
|
|
|
623
621
|
}
|
|
624
622
|
};
|
|
625
623
|
|
|
626
|
-
// src/client/
|
|
627
|
-
function
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
// src/client/i18n/messages/plan-versions.ts
|
|
635
|
-
var planVersionsMessages = defineMessages(
|
|
636
|
-
{
|
|
637
|
-
compareEnd: "Vergleich beenden",
|
|
638
|
-
page: {
|
|
639
|
-
loadingCatalog: "Catalog wird geladen\u2026",
|
|
640
|
-
noAuditLoader: "Kein Audit-Loader konfiguriert."
|
|
641
|
-
},
|
|
642
|
-
header: {
|
|
643
|
-
modeList: "Plan-Liste",
|
|
644
|
-
modeMatrix: "Feature-Matrix",
|
|
645
|
-
modeAudit: "Aktivit\xE4t",
|
|
646
|
-
publishedOn: "Publiziert {date}",
|
|
647
|
-
openDrafts: "offene Drafts",
|
|
648
|
-
regressionOne: "Regression",
|
|
649
|
-
regressionMany: "Regressionen",
|
|
650
|
-
startPublishFlow: "Publish-Flow starten",
|
|
651
|
-
compareModeHint: "Vergleichsmodus aktiv \u2014 andere Ansichten deaktiviert"
|
|
652
|
-
},
|
|
653
|
-
status: {
|
|
654
|
-
draft: "DRAFT",
|
|
655
|
-
active: "AKTIV",
|
|
656
|
-
archived: "ARCHIV"
|
|
657
|
-
},
|
|
658
|
-
timeline: {
|
|
659
|
-
title: "Plan-Catalog",
|
|
660
|
-
snapshotCount: "{count} Snapshots",
|
|
661
|
-
noOpenDrafts: "keine offenen Drafts",
|
|
662
|
-
openCount: "{count} offen",
|
|
663
|
-
unknown: "unbekannt",
|
|
664
|
-
compareHint: "Rechtsklick auf Snapshot \u2192 vergleichen"
|
|
665
|
-
},
|
|
666
|
-
list: {
|
|
667
|
-
kpiPlans: "Pakete",
|
|
668
|
-
kpiSelfService: "Self-Service",
|
|
669
|
-
kpiOfTotal: "von {count}",
|
|
670
|
-
kpiFeaturesTotal: "Features gesamt",
|
|
671
|
-
missingPlansLabel: "Fehlende Pakete:",
|
|
672
|
-
missingPlansHint: "\u2014 keine Live-Version in diesem Snapshot.",
|
|
673
|
-
createDraftFor: "Draft f\xFCr {planId}",
|
|
674
|
-
colPlan: "Paket",
|
|
675
|
-
colPriceNet: "Preis (netto)",
|
|
676
|
-
colFeatures: "Features",
|
|
677
|
-
draftHintLabel: "Arbeitsstand:",
|
|
678
|
-
draftHintBefore: "Drafts oben in der Liste. Limits, Preise und Features per Klick auf",
|
|
679
|
-
draftHintEditButton: '\u201EBearbeiten"',
|
|
680
|
-
draftHintMiddle: "\xE4ndern (ohne MFA). Erst",
|
|
681
|
-
draftHintPublishFlow: "Publish-Flow",
|
|
682
|
-
draftHintAfter: "(Validate \u2192 Diff-Review \u2192 MFA \u2192 Apply) macht sie f\xFCr k\xFCnftige Renewals wirksam."
|
|
683
|
-
},
|
|
684
|
-
matrix: {
|
|
685
|
-
colFeature: "Feature",
|
|
686
|
-
perMonthShort: "/Mo",
|
|
687
|
-
fallbackGroup: "Sonstige"
|
|
688
|
-
},
|
|
689
|
-
diff: {
|
|
690
|
-
legend: "Vergleich",
|
|
691
|
-
plansChanged: "Pakete ge\xE4ndert",
|
|
692
|
-
regressions: "Regressionen",
|
|
693
|
-
sectionPlans: "Pakete",
|
|
694
|
-
changeCountOne: "{count} \xC4nderung",
|
|
695
|
-
changeCountMany: "{count} \xC4nderungen"
|
|
696
|
-
},
|
|
697
|
-
diffPreview: {
|
|
698
|
-
empty: "Keine \xC4nderungen gegen\xFCber der Vorg\xE4ngerversion.",
|
|
699
|
-
improvement: "Verbesserung",
|
|
700
|
-
regression: "Verschlechterung",
|
|
701
|
-
neutral: "Neutral"
|
|
702
|
-
},
|
|
703
|
-
diffFields: {
|
|
704
|
-
featuresAdded: "Hinzugef\xFCgte Features",
|
|
705
|
-
featuresRemoved: "Entfernte Features",
|
|
706
|
-
maxUsers: "Max. Benutzer",
|
|
707
|
-
maxStorageGb: "Speicher (GB)",
|
|
708
|
-
monthlyNet: "Preis monatlich (netto)",
|
|
709
|
-
yearlyNet: "Preis j\xE4hrlich (netto)",
|
|
710
|
-
unitSize: "Einheitsgr\xF6\xDFe"
|
|
711
|
-
},
|
|
712
|
-
audit: {
|
|
713
|
-
title: "Aktivit\xE4t",
|
|
714
|
-
eventCount: "{count} Events",
|
|
715
|
-
loading: "Audit-Trail wird geladen\u2026",
|
|
716
|
-
empty: "Keine Plan-/Add-on-Events im Audit-Log gefunden.",
|
|
717
|
-
actionPlanPublished: "Plan publiziert",
|
|
718
|
-
actionPlanDraftCreated: "Plan-Draft angelegt",
|
|
719
|
-
actionPlanDraftUpdated: "Plan-Draft ge\xE4ndert",
|
|
720
|
-
actionPlanDraftDeleted: "Plan-Draft gel\xF6scht",
|
|
721
|
-
actionCatalogPublished: "Catalog publiziert",
|
|
722
|
-
detailRegression: "Mit mindestens einer Verschlechterung publiziert.",
|
|
723
|
-
detailFieldsChanged: "{count} Felder ge\xE4ndert."
|
|
724
|
-
},
|
|
725
|
-
bulkPublish: {
|
|
726
|
-
changeNoteRequired: "changeNote ist Pflicht beim Publish."
|
|
727
|
-
},
|
|
728
|
-
format: {
|
|
729
|
-
priceIndividual: "individuell",
|
|
730
|
-
today: "heute",
|
|
731
|
-
yesterday: "gestern",
|
|
732
|
-
daysAgo: "vor {count} Tagen",
|
|
733
|
-
weeksAgoOne: "vor {count} Woche",
|
|
734
|
-
weeksAgoMany: "vor {count} Wochen",
|
|
735
|
-
monthsAgo: "vor {count} Monaten",
|
|
736
|
-
yearsAgoOne: "vor {count} Jahr",
|
|
737
|
-
yearsAgoMany: "vor {count} Jahren"
|
|
738
|
-
},
|
|
739
|
-
catalog: {
|
|
740
|
-
draftsLabel: "Arbeitsstand",
|
|
741
|
-
draftsTitleEmpty: "Keine offenen Drafts",
|
|
742
|
-
draftsTitleOne: "{count} offener Draft bereit f\xFCr Publish",
|
|
743
|
-
draftsTitleMany: "{count} offene Drafts bereit f\xFCr Publish",
|
|
744
|
-
draftsDescriptionEmpty: "Lege einen Draft an, um Limits, Preise oder Features zu \xE4ndern. Drafts sind ohne MFA editierbar und werden erst beim Publish wirksam.",
|
|
745
|
-
draftsDescription: "Diese Tabelle zeigt, wie der Catalog nach Publish aller Drafts aussehen w\xFCrde. Bestehende Mandanten bleiben auf der vorherigen Version, bis sie aktiv migriert werden.",
|
|
746
|
-
activeLabel: "Aktuell",
|
|
747
|
-
activeTitle: "Live-Catalog",
|
|
748
|
-
activeDescription: "Diese Plan-Versionen sind aktuell f\xFCr neue Onboardings und f\xFCr Renewals nach Stichtag aktiv.",
|
|
749
|
-
publishEvent: "Publish-Event",
|
|
750
|
-
publishEventSingle: "{planId} v{version} publiziert",
|
|
751
|
-
publishEventMultiple: "{count} Versionen publiziert",
|
|
752
|
-
reconstructedSnapshot: "Snapshot rekonstruiert aus per-Entity-Versionen."
|
|
753
|
-
}
|
|
754
|
-
},
|
|
755
|
-
{
|
|
756
|
-
compareEnd: "End comparison",
|
|
757
|
-
page: {
|
|
758
|
-
loadingCatalog: "Loading catalog\u2026",
|
|
759
|
-
noAuditLoader: "No audit loader configured."
|
|
760
|
-
},
|
|
761
|
-
header: {
|
|
762
|
-
modeList: "Plan list",
|
|
763
|
-
modeMatrix: "Feature matrix",
|
|
764
|
-
modeAudit: "Activity",
|
|
765
|
-
publishedOn: "Published {date}",
|
|
766
|
-
openDrafts: "open drafts",
|
|
767
|
-
regressionOne: "regression",
|
|
768
|
-
regressionMany: "regressions",
|
|
769
|
-
startPublishFlow: "Start publish flow",
|
|
770
|
-
compareModeHint: "Comparison mode active \u2014 other views disabled"
|
|
771
|
-
},
|
|
772
|
-
status: {
|
|
773
|
-
draft: "DRAFT",
|
|
774
|
-
active: "ACTIVE",
|
|
775
|
-
archived: "ARCHIVED"
|
|
776
|
-
},
|
|
777
|
-
timeline: {
|
|
778
|
-
title: "Plan catalog",
|
|
779
|
-
snapshotCount: "{count} snapshots",
|
|
780
|
-
noOpenDrafts: "no open drafts",
|
|
781
|
-
openCount: "{count} open",
|
|
782
|
-
unknown: "unknown",
|
|
783
|
-
compareHint: "Right-click a snapshot \u2192 compare"
|
|
784
|
-
},
|
|
785
|
-
list: {
|
|
786
|
-
kpiPlans: "Plans",
|
|
787
|
-
kpiSelfService: "Self-service",
|
|
788
|
-
kpiOfTotal: "of {count}",
|
|
789
|
-
kpiFeaturesTotal: "Features total",
|
|
790
|
-
missingPlansLabel: "Missing plans:",
|
|
791
|
-
missingPlansHint: "\u2014 no live version in this snapshot.",
|
|
792
|
-
createDraftFor: "Draft for {planId}",
|
|
793
|
-
colPlan: "Plan",
|
|
794
|
-
colPriceNet: "Price (net)",
|
|
795
|
-
colFeatures: "Features",
|
|
796
|
-
draftHintLabel: "Working state:",
|
|
797
|
-
draftHintBefore: "Drafts at the top of the list. Change limits, prices and features by clicking",
|
|
798
|
-
draftHintEditButton: '"Edit"',
|
|
799
|
-
draftHintMiddle: "(without MFA). Only the",
|
|
800
|
-
draftHintPublishFlow: "publish flow",
|
|
801
|
-
draftHintAfter: "(validate \u2192 diff review \u2192 MFA \u2192 apply) makes them effective for future renewals."
|
|
802
|
-
},
|
|
803
|
-
matrix: {
|
|
804
|
-
colFeature: "Feature",
|
|
805
|
-
perMonthShort: "/mo",
|
|
806
|
-
fallbackGroup: "Other"
|
|
807
|
-
},
|
|
808
|
-
diff: {
|
|
809
|
-
legend: "Comparison",
|
|
810
|
-
plansChanged: "Plans changed",
|
|
811
|
-
regressions: "Regressions",
|
|
812
|
-
sectionPlans: "Plans",
|
|
813
|
-
changeCountOne: "{count} change",
|
|
814
|
-
changeCountMany: "{count} changes"
|
|
815
|
-
},
|
|
816
|
-
diffPreview: {
|
|
817
|
-
empty: "No changes compared to the previous version.",
|
|
818
|
-
improvement: "Improvement",
|
|
819
|
-
regression: "Regression",
|
|
820
|
-
neutral: "Neutral"
|
|
821
|
-
},
|
|
822
|
-
diffFields: {
|
|
823
|
-
featuresAdded: "Added features",
|
|
824
|
-
featuresRemoved: "Removed features",
|
|
825
|
-
maxUsers: "Max. users",
|
|
826
|
-
maxStorageGb: "Storage (GB)",
|
|
827
|
-
monthlyNet: "Price monthly (net)",
|
|
828
|
-
yearlyNet: "Price yearly (net)",
|
|
829
|
-
unitSize: "Unit size"
|
|
830
|
-
},
|
|
831
|
-
audit: {
|
|
832
|
-
title: "Activity",
|
|
833
|
-
eventCount: "{count} events",
|
|
834
|
-
loading: "Loading audit trail\u2026",
|
|
835
|
-
empty: "No plan/add-on events found in the audit log.",
|
|
836
|
-
actionPlanPublished: "Plan published",
|
|
837
|
-
actionPlanDraftCreated: "Plan draft created",
|
|
838
|
-
actionPlanDraftUpdated: "Plan draft changed",
|
|
839
|
-
actionPlanDraftDeleted: "Plan draft deleted",
|
|
840
|
-
actionCatalogPublished: "Catalog published",
|
|
841
|
-
detailRegression: "Published with at least one regression.",
|
|
842
|
-
detailFieldsChanged: "{count} fields changed."
|
|
843
|
-
},
|
|
844
|
-
bulkPublish: {
|
|
845
|
-
changeNoteRequired: "changeNote is required when publishing."
|
|
846
|
-
},
|
|
847
|
-
format: {
|
|
848
|
-
priceIndividual: "custom",
|
|
849
|
-
today: "today",
|
|
850
|
-
yesterday: "yesterday",
|
|
851
|
-
daysAgo: "{count} days ago",
|
|
852
|
-
weeksAgoOne: "{count} week ago",
|
|
853
|
-
weeksAgoMany: "{count} weeks ago",
|
|
854
|
-
monthsAgo: "{count} months ago",
|
|
855
|
-
yearsAgoOne: "{count} year ago",
|
|
856
|
-
yearsAgoMany: "{count} years ago"
|
|
857
|
-
},
|
|
858
|
-
catalog: {
|
|
859
|
-
draftsLabel: "Working state",
|
|
860
|
-
draftsTitleEmpty: "No open drafts",
|
|
861
|
-
draftsTitleOne: "{count} open draft ready to publish",
|
|
862
|
-
draftsTitleMany: "{count} open drafts ready to publish",
|
|
863
|
-
draftsDescriptionEmpty: "Create a draft to change limits, prices or features. Drafts are editable without MFA and only take effect when published.",
|
|
864
|
-
draftsDescription: "This table shows what the catalog would look like after publishing all drafts. Existing tenants stay on the previous version until they are actively migrated.",
|
|
865
|
-
activeLabel: "Current",
|
|
866
|
-
activeTitle: "Live catalog",
|
|
867
|
-
activeDescription: "These plan versions are currently active for new onboardings and for renewals after the effective date.",
|
|
868
|
-
publishEvent: "Publish event",
|
|
869
|
-
publishEventSingle: "{planId} v{version} published",
|
|
870
|
-
publishEventMultiple: "{count} versions published",
|
|
871
|
-
reconstructedSnapshot: "Snapshot reconstructed from per-entity versions."
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
);
|
|
875
|
-
|
|
876
|
-
// src/client/plan-versions-catalog.ts
|
|
877
|
-
var dec = (s) => Number(s);
|
|
878
|
-
function extractQuotas(p) {
|
|
879
|
-
if (p.quotas && Object.keys(p.quotas).length > 0) {
|
|
880
|
-
return { ...p.quotas };
|
|
881
|
-
}
|
|
882
|
-
const out = {};
|
|
883
|
-
if (typeof p.maxUsers === "number") out.users = p.maxUsers;
|
|
884
|
-
if (typeof p.maxVehicles === "number") out.vehicles = p.maxVehicles;
|
|
885
|
-
if (typeof p.maxStorageGb === "number") out.storageGb = p.maxStorageGb;
|
|
886
|
-
return out;
|
|
887
|
-
}
|
|
888
|
-
var sortByPublishedDesc = (rows) => [...rows].sort((a, b) => {
|
|
889
|
-
const at = a.publishedAt ? Date.parse(a.publishedAt) : Number.POSITIVE_INFINITY;
|
|
890
|
-
const bt = b.publishedAt ? Date.parse(b.publishedAt) : Number.POSITIVE_INFINITY;
|
|
891
|
-
if (at !== bt) return bt - at;
|
|
892
|
-
return b.version - a.version;
|
|
893
|
-
});
|
|
894
|
-
function findLiveAt(rows, asOfMs) {
|
|
895
|
-
const candidates = rows.filter((r) => {
|
|
896
|
-
if (r.publishedAt === null) return false;
|
|
897
|
-
if (Date.parse(r.publishedAt) > asOfMs) return false;
|
|
898
|
-
if (r.supersededAt !== null && Date.parse(r.supersededAt) <= asOfMs) return false;
|
|
899
|
-
return true;
|
|
900
|
-
});
|
|
901
|
-
if (candidates.length === 0) return null;
|
|
902
|
-
return [...candidates].sort((a, b) => b.version - a.version)[0] ?? null;
|
|
903
|
-
}
|
|
904
|
-
function findCurrentLive(rows) {
|
|
905
|
-
return rows.find((r) => r.publishedAt !== null && r.supersededAt === null) ?? null;
|
|
906
|
-
}
|
|
907
|
-
function findDraft(rows) {
|
|
908
|
-
return rows.find((r) => r.publishedAt === null) ?? null;
|
|
909
|
-
}
|
|
910
|
-
function groupBy(rows, keyOf) {
|
|
911
|
-
const out = /* @__PURE__ */ new Map();
|
|
912
|
-
for (const r of rows) {
|
|
913
|
-
const k = keyOf(r);
|
|
914
|
-
const list = out.get(k) ?? [];
|
|
915
|
-
list.push(r);
|
|
916
|
-
out.set(k, list);
|
|
917
|
-
}
|
|
918
|
-
return out;
|
|
919
|
-
}
|
|
920
|
-
function resolvePlan(source, liveBase) {
|
|
921
|
-
const quotas = extractQuotas(source);
|
|
922
|
-
return {
|
|
923
|
-
source,
|
|
924
|
-
liveBase,
|
|
925
|
-
isDraft: source.publishedAt === null,
|
|
926
|
-
planId: source.planId,
|
|
927
|
-
features: source.features,
|
|
928
|
-
quotas,
|
|
929
|
-
monthlyNet: dec(source.monthlyNet),
|
|
930
|
-
yearlyNet: dec(source.yearlyNet),
|
|
931
|
-
marketed: source.marketed,
|
|
932
|
-
version: source.version,
|
|
933
|
-
maxUsers: quotas.users,
|
|
934
|
-
maxVehicles: quotas.vehicles,
|
|
935
|
-
maxStorageGb: quotas.storageGb
|
|
624
|
+
// src/client/admin-resource-client.ts
|
|
625
|
+
function createAdminResourceClient(options) {
|
|
626
|
+
const base = options.adminBase ?? "/api/v1/admin";
|
|
627
|
+
const tenantsEndpoint = `${base}/tenants`;
|
|
628
|
+
const getJson2 = async (url) => {
|
|
629
|
+
const response = await options.http(url, { method: "GET" });
|
|
630
|
+
assertSuccess(response.status, "GET", url);
|
|
631
|
+
return await response.json();
|
|
936
632
|
};
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
day: "2-digit",
|
|
946
|
-
month: "short",
|
|
947
|
-
year: "numeric"
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
function buildDraftsSnapshot(data, sortPlansFn, locale) {
|
|
951
|
-
const msg = planVersionsMessages[locale].catalog;
|
|
952
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
953
|
-
const plans = [];
|
|
954
|
-
for (const [, rows] of planByKey) {
|
|
955
|
-
const draft = findDraft(rows);
|
|
956
|
-
const live = findCurrentLive(rows);
|
|
957
|
-
if (draft) plans.push(resolvePlan(draft, live));
|
|
958
|
-
else if (live) plans.push(resolvePlan(live, null));
|
|
959
|
-
}
|
|
960
|
-
const draftCount = plans.filter((p) => p.isDraft).length;
|
|
961
|
-
return {
|
|
962
|
-
id: "drafts",
|
|
963
|
-
kind: "drafts",
|
|
964
|
-
status: "DRAFT",
|
|
965
|
-
label: msg.draftsLabel,
|
|
966
|
-
title: draftsTitle(draftCount, msg),
|
|
967
|
-
description: draftCount === 0 ? msg.draftsDescriptionEmpty : msg.draftsDescription,
|
|
968
|
-
asOf: null,
|
|
969
|
-
createdAt: null,
|
|
970
|
-
publishedAt: null,
|
|
971
|
-
authorEmail: null,
|
|
972
|
-
plans: sortPlansFn(plans),
|
|
973
|
-
draftCount,
|
|
974
|
-
regressionCount: 0
|
|
633
|
+
const sendJson = async (method, url, body) => {
|
|
634
|
+
const response = await options.http(url, {
|
|
635
|
+
method,
|
|
636
|
+
headers: { "content-type": "application/json" },
|
|
637
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
638
|
+
});
|
|
639
|
+
assertSuccess(response.status, method, url);
|
|
640
|
+
return await response.json();
|
|
975
641
|
};
|
|
976
|
-
}
|
|
977
|
-
function buildActiveSnapshot(data, sortPlansFn, locale) {
|
|
978
|
-
const msg = planVersionsMessages[locale].catalog;
|
|
979
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
980
|
-
const plans = [];
|
|
981
|
-
for (const [, rows] of planByKey) {
|
|
982
|
-
const live = findCurrentLive(rows);
|
|
983
|
-
if (live) plans.push(resolvePlan(live, null));
|
|
984
|
-
}
|
|
985
|
-
if (plans.length === 0) return null;
|
|
986
|
-
const publishedDates = plans.map((p) => p.source.publishedAt).filter((t) => t !== null).sort();
|
|
987
|
-
const latestPublished = publishedDates[publishedDates.length - 1];
|
|
988
642
|
return {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
643
|
+
tenantsEndpoint,
|
|
644
|
+
loadTenantDetail: (slug) => getJson2(`${tenantsEndpoint}/${encodeURIComponent(slug)}`),
|
|
645
|
+
loadUsers: (filter) => getJson2(
|
|
646
|
+
`${base}/users${queryString({ q: filter.q, tenant: filter.tenant })}`
|
|
647
|
+
),
|
|
648
|
+
loadAudit: (filter) => getJson2(
|
|
649
|
+
`${base}/audit${queryString({
|
|
650
|
+
actor: filter.actor,
|
|
651
|
+
action: filter.action,
|
|
652
|
+
entity: filter.entity,
|
|
653
|
+
since: filter.since,
|
|
654
|
+
limit: filter.limit
|
|
655
|
+
})}`
|
|
656
|
+
),
|
|
657
|
+
loadSubscriptions: () => getJson2(`${base}/subscriptions`),
|
|
658
|
+
loadPromos: (filter) => getJson2(
|
|
659
|
+
`${base}/promo-codes${queryString({
|
|
660
|
+
search: filter.search,
|
|
661
|
+
status: filter.status
|
|
662
|
+
})}`
|
|
663
|
+
),
|
|
664
|
+
createPromo: async (payload) => {
|
|
665
|
+
await sendJson("POST", `${base}/promo-codes`, payload);
|
|
666
|
+
},
|
|
667
|
+
updatePromo: async (id, payload) => {
|
|
668
|
+
await sendJson("PATCH", `${base}/promo-codes/${encodeURIComponent(id)}`, payload);
|
|
669
|
+
},
|
|
670
|
+
deletePromo: async (id) => {
|
|
671
|
+
await sendJson("DELETE", `${base}/promo-codes/${encodeURIComponent(id)}`);
|
|
672
|
+
},
|
|
673
|
+
suspendTenant: (slug, reason) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/suspend`, {
|
|
674
|
+
reason
|
|
675
|
+
}),
|
|
676
|
+
reactivateTenant: (slug) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/reactivate`)
|
|
1002
677
|
};
|
|
1003
678
|
}
|
|
1004
|
-
function
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
for (const r of data.planVersions) if (r.publishedAt) allPublishedAt.add(r.publishedAt);
|
|
1008
|
-
if (allPublishedAt.size === 0) return [];
|
|
1009
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
1010
|
-
const liveTimestamps = /* @__PURE__ */ new Set();
|
|
1011
|
-
for (const rows of planByKey.values()) {
|
|
1012
|
-
const live = findCurrentLive(rows);
|
|
1013
|
-
if (live?.publishedAt) liveTimestamps.add(live.publishedAt);
|
|
679
|
+
function assertSuccess(status, method, url) {
|
|
680
|
+
if (status < 200 || status >= 300) {
|
|
681
|
+
throw new Error(`${method} ${url} \u2192 HTTP ${status}`);
|
|
1014
682
|
}
|
|
1015
|
-
const liveSorted = [...liveTimestamps].sort();
|
|
1016
|
-
const latestLive = liveSorted[liveSorted.length - 1];
|
|
1017
|
-
const sortedDesc = [...allPublishedAt].sort((a, b) => Date.parse(b) - Date.parse(a));
|
|
1018
|
-
const out = [];
|
|
1019
|
-
for (const ts of sortedDesc) {
|
|
1020
|
-
if (latestLive && Date.parse(ts) >= Date.parse(latestLive)) continue;
|
|
1021
|
-
const tMs = Date.parse(ts) + 1;
|
|
1022
|
-
const plans = [];
|
|
1023
|
-
for (const [, rows] of planByKey) {
|
|
1024
|
-
const live = findLiveAt(rows, tMs);
|
|
1025
|
-
if (live) plans.push(resolvePlan(live, null));
|
|
1026
|
-
}
|
|
1027
|
-
if (plans.length === 0) continue;
|
|
1028
|
-
const publishedAtThisEvent = data.planVersions.filter((r) => r.publishedAt === ts);
|
|
1029
|
-
const regressionCount = publishedAtThisEvent.filter((r) => !r.nonRegressive).length;
|
|
1030
|
-
const author = publishedAtThisEvent[0]?.publishedByUserId ?? null;
|
|
1031
|
-
out.push({
|
|
1032
|
-
id: `hist-${ts}`,
|
|
1033
|
-
kind: "historical",
|
|
1034
|
-
status: "ARCHIVED",
|
|
1035
|
-
label: dateLabel(ts, locale),
|
|
1036
|
-
title: summarizeEvent(publishedAtThisEvent, msg),
|
|
1037
|
-
description: detailEvent(publishedAtThisEvent, msg),
|
|
1038
|
-
asOf: ts,
|
|
1039
|
-
createdAt: ts,
|
|
1040
|
-
publishedAt: ts,
|
|
1041
|
-
authorEmail: author,
|
|
1042
|
-
plans: sortPlansFn(plans),
|
|
1043
|
-
draftCount: 0,
|
|
1044
|
-
regressionCount
|
|
1045
|
-
});
|
|
1046
|
-
}
|
|
1047
|
-
return out;
|
|
1048
683
|
}
|
|
1049
|
-
function
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
684
|
+
function queryString(params) {
|
|
685
|
+
const search = new URLSearchParams();
|
|
686
|
+
for (const [key, value2] of Object.entries(params)) {
|
|
687
|
+
if (value2 === void 0 || value2 === null || value2 === "") continue;
|
|
688
|
+
search.set(key, String(value2));
|
|
1054
689
|
}
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1057
|
-
function detailEvent(rows, msg) {
|
|
1058
|
-
if (rows.length === 0) return "";
|
|
1059
|
-
const note = rows[0]?.changeNote ?? "";
|
|
1060
|
-
return note.length > 0 ? note : msg.reconstructedSnapshot;
|
|
690
|
+
const value = search.toString();
|
|
691
|
+
return value ? `?${value}` : "";
|
|
1061
692
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
return (rows) => [...rows].sort((a, b) => {
|
|
1069
|
-
const ai = idx[a.planId] ?? Number.POSITIVE_INFINITY;
|
|
1070
|
-
const bi = idx[b.planId] ?? Number.POSITIVE_INFINITY;
|
|
1071
|
-
if (ai !== bi) return ai - bi;
|
|
1072
|
-
return a.planId.localeCompare(b.planId);
|
|
693
|
+
|
|
694
|
+
// src/client/i18n/format.ts
|
|
695
|
+
function formatMessage(template, params) {
|
|
696
|
+
return template.replace(/\{(\w+)\}/g, (match, name) => {
|
|
697
|
+
const value = params[name];
|
|
698
|
+
return value === void 0 ? match : String(value);
|
|
1073
699
|
});
|
|
1074
700
|
}
|
|
1075
|
-
function buildSnapshots(data, options = {}) {
|
|
1076
|
-
const locale = options.locale ?? DEFAULT_SA_LOCALE;
|
|
1077
|
-
const sortPlansFn = sortPlansBy(options.planSortOrder);
|
|
1078
|
-
const drafts = buildDraftsSnapshot(data, sortPlansFn, locale);
|
|
1079
|
-
const active = buildActiveSnapshot(data, sortPlansFn, locale);
|
|
1080
|
-
const historical = buildHistoricalSnapshots(data, sortPlansFn, locale);
|
|
1081
|
-
const out = [drafts];
|
|
1082
|
-
if (active) out.push(active);
|
|
1083
|
-
out.push(...historical);
|
|
1084
|
-
return out;
|
|
1085
|
-
}
|
|
1086
|
-
function listOpenDrafts(data) {
|
|
1087
|
-
return {
|
|
1088
|
-
plans: sortByPublishedDesc(data.planVersions).filter((r) => r.publishedAt === null)
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
701
|
|
|
1092
702
|
// src/client/i18n/currency.ts
|
|
1093
703
|
var DEFAULT_CURRENCY = "EUR";
|
|
@@ -2955,6 +2565,114 @@ var planEditorMessages = defineMessages(
|
|
|
2955
2565
|
}
|
|
2956
2566
|
);
|
|
2957
2567
|
|
|
2568
|
+
// src/client/i18n/messages/plan-versions.ts
|
|
2569
|
+
var planVersionsMessages = defineMessages(
|
|
2570
|
+
{
|
|
2571
|
+
compareEnd: "Vergleich beenden",
|
|
2572
|
+
status: {
|
|
2573
|
+
draft: "DRAFT",
|
|
2574
|
+
active: "AKTIV",
|
|
2575
|
+
archived: "ARCHIV"
|
|
2576
|
+
},
|
|
2577
|
+
timeline: {
|
|
2578
|
+
title: "Plan-Catalog",
|
|
2579
|
+
snapshotCount: "{count} Snapshots",
|
|
2580
|
+
noOpenDrafts: "keine offenen Drafts",
|
|
2581
|
+
openCount: "{count} offen",
|
|
2582
|
+
unknown: "unbekannt",
|
|
2583
|
+
compareHint: "Rechtsklick auf Snapshot \u2192 vergleichen"
|
|
2584
|
+
},
|
|
2585
|
+
diff: {
|
|
2586
|
+
legend: "Vergleich",
|
|
2587
|
+
plansChanged: "Pakete ge\xE4ndert",
|
|
2588
|
+
regressions: "Regressionen",
|
|
2589
|
+
sectionPlans: "Pakete",
|
|
2590
|
+
changeCountOne: "{count} \xC4nderung",
|
|
2591
|
+
changeCountMany: "{count} \xC4nderungen"
|
|
2592
|
+
},
|
|
2593
|
+
diffPreview: {
|
|
2594
|
+
empty: "Keine \xC4nderungen gegen\xFCber der Vorg\xE4ngerversion.",
|
|
2595
|
+
improvement: "Verbesserung",
|
|
2596
|
+
regression: "Verschlechterung",
|
|
2597
|
+
neutral: "Neutral"
|
|
2598
|
+
},
|
|
2599
|
+
diffFields: {
|
|
2600
|
+
featuresAdded: "Hinzugef\xFCgte Features",
|
|
2601
|
+
featuresRemoved: "Entfernte Features",
|
|
2602
|
+
maxUsers: "Max. Benutzer",
|
|
2603
|
+
maxStorageGb: "Speicher (GB)",
|
|
2604
|
+
monthlyNet: "Preis monatlich (netto)",
|
|
2605
|
+
yearlyNet: "Preis j\xE4hrlich (netto)",
|
|
2606
|
+
unitSize: "Einheitsgr\xF6\xDFe"
|
|
2607
|
+
},
|
|
2608
|
+
bulkPublish: {
|
|
2609
|
+
changeNoteRequired: "changeNote ist Pflicht beim Publish."
|
|
2610
|
+
},
|
|
2611
|
+
format: {
|
|
2612
|
+
today: "heute",
|
|
2613
|
+
yesterday: "gestern",
|
|
2614
|
+
daysAgo: "vor {count} Tagen",
|
|
2615
|
+
weeksAgoOne: "vor {count} Woche",
|
|
2616
|
+
weeksAgoMany: "vor {count} Wochen",
|
|
2617
|
+
monthsAgo: "vor {count} Monaten",
|
|
2618
|
+
yearsAgoOne: "vor {count} Jahr",
|
|
2619
|
+
yearsAgoMany: "vor {count} Jahren"
|
|
2620
|
+
}
|
|
2621
|
+
},
|
|
2622
|
+
{
|
|
2623
|
+
compareEnd: "End comparison",
|
|
2624
|
+
status: {
|
|
2625
|
+
draft: "DRAFT",
|
|
2626
|
+
active: "ACTIVE",
|
|
2627
|
+
archived: "ARCHIVED"
|
|
2628
|
+
},
|
|
2629
|
+
timeline: {
|
|
2630
|
+
title: "Plan catalog",
|
|
2631
|
+
snapshotCount: "{count} snapshots",
|
|
2632
|
+
noOpenDrafts: "no open drafts",
|
|
2633
|
+
openCount: "{count} open",
|
|
2634
|
+
unknown: "unknown",
|
|
2635
|
+
compareHint: "Right-click a snapshot \u2192 compare"
|
|
2636
|
+
},
|
|
2637
|
+
diff: {
|
|
2638
|
+
legend: "Comparison",
|
|
2639
|
+
plansChanged: "Plans changed",
|
|
2640
|
+
regressions: "Regressions",
|
|
2641
|
+
sectionPlans: "Plans",
|
|
2642
|
+
changeCountOne: "{count} change",
|
|
2643
|
+
changeCountMany: "{count} changes"
|
|
2644
|
+
},
|
|
2645
|
+
diffPreview: {
|
|
2646
|
+
empty: "No changes compared to the previous version.",
|
|
2647
|
+
improvement: "Improvement",
|
|
2648
|
+
regression: "Regression",
|
|
2649
|
+
neutral: "Neutral"
|
|
2650
|
+
},
|
|
2651
|
+
diffFields: {
|
|
2652
|
+
featuresAdded: "Added features",
|
|
2653
|
+
featuresRemoved: "Removed features",
|
|
2654
|
+
maxUsers: "Max. users",
|
|
2655
|
+
maxStorageGb: "Storage (GB)",
|
|
2656
|
+
monthlyNet: "Price monthly (net)",
|
|
2657
|
+
yearlyNet: "Price yearly (net)",
|
|
2658
|
+
unitSize: "Unit size"
|
|
2659
|
+
},
|
|
2660
|
+
bulkPublish: {
|
|
2661
|
+
changeNoteRequired: "changeNote is required when publishing."
|
|
2662
|
+
},
|
|
2663
|
+
format: {
|
|
2664
|
+
today: "today",
|
|
2665
|
+
yesterday: "yesterday",
|
|
2666
|
+
daysAgo: "{count} days ago",
|
|
2667
|
+
weeksAgoOne: "{count} week ago",
|
|
2668
|
+
weeksAgoMany: "{count} weeks ago",
|
|
2669
|
+
monthsAgo: "{count} months ago",
|
|
2670
|
+
yearsAgoOne: "{count} year ago",
|
|
2671
|
+
yearsAgoMany: "{count} years ago"
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
);
|
|
2675
|
+
|
|
2958
2676
|
// src/client/i18n/messages/plans.ts
|
|
2959
2677
|
var plansMessages = defineMessages(
|
|
2960
2678
|
{
|
|
@@ -3971,7 +3689,7 @@ function resolveMessages(locale, overrides) {
|
|
|
3971
3689
|
SA_MESSAGES,
|
|
3972
3690
|
buildRoutes,
|
|
3973
3691
|
buildSidebar,
|
|
3974
|
-
|
|
3692
|
+
createAdminResourceClient,
|
|
3975
3693
|
defaultHttpClient,
|
|
3976
3694
|
defaultKvStore,
|
|
3977
3695
|
defaultSectionOrder,
|
|
@@ -3979,7 +3697,6 @@ function resolveMessages(locale, overrides) {
|
|
|
3979
3697
|
formatCurrency,
|
|
3980
3698
|
formatMessage,
|
|
3981
3699
|
getJson,
|
|
3982
|
-
listOpenDrafts,
|
|
3983
3700
|
mergeMessages,
|
|
3984
3701
|
postJson,
|
|
3985
3702
|
resolveExtension,
|