@saasicat/ui-vue 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{chunk-A3W2N26K.js → chunk-7N3CJTOA.js} +7 -227
  2. package/dist/{chunk-X5SQ5HMB.js → chunk-TBLXKSTR.js} +0 -137
  3. package/dist/{chunk-QZOSDCNP.js → chunk-TY2WYKME.js} +1 -1
  4. package/dist/client/index.cjs +112 -467
  5. package/dist/client/index.d.cts +4 -62
  6. package/dist/client/index.d.ts +4 -62
  7. package/dist/client/index.js +2 -6
  8. package/dist/index.cjs +204 -583
  9. package/dist/index.d.cts +10 -55
  10. package/dist/index.d.ts +10 -55
  11. package/dist/index.js +74 -101
  12. package/dist/{messages-7b0P8W75.d.ts → messages-BIYw32u1.d.cts} +0 -67
  13. package/dist/{messages-7b0P8W75.d.cts → messages-BIYw32u1.d.ts} +0 -67
  14. package/dist/quasar/index.cjs +0 -136
  15. package/dist/quasar/index.d.cts +2 -2
  16. package/dist/quasar/index.d.ts +2 -2
  17. package/dist/quasar/index.js +2 -2
  18. package/dist/{use-super-admin-i18n-B3v3-SWZ.d.ts → use-super-admin-i18n-CWNu_W3u.d.ts} +1 -1
  19. package/dist/{use-super-admin-i18n-DMktRVEt.d.cts → use-super-admin-i18n-DL_qI1BY.d.cts} +1 -1
  20. package/package.json +2 -2
  21. package/src/client/i18n/messages/nav.ts +0 -2
  22. package/src/client/i18n/messages/plan-versions.ts +0 -143
  23. package/src/client/index.ts +0 -2
  24. package/src/client/nav-builder.ts +9 -4
  25. package/src/index.ts +0 -1
  26. package/src/pages-standard/AdminLayout.vue +1 -1
  27. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +1 -1
  28. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +1 -1
  29. package/src/pages-standard/plan-versions/catalog-history.types.ts +37 -0
  30. package/src/pages-standard/plan-versions/format.ts +2 -38
  31. package/src/client/plan-versions-catalog.ts +0 -380
  32. package/src/pages-standard/PlanVersionsPage.vue +0 -220
  33. package/src/pages-standard/plan-versions/PlanVersionHeader.vue +0 -309
  34. package/src/pages-standard/plan-versions/PlanVersionStatusBadge.vue +0 -48
  35. package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +0 -326
  36. package/src/pages-standard/plan-versions/PlanVersionsKpi.vue +0 -65
  37. package/src/pages-standard/plan-versions/PlanVersionsList.vue +0 -315
  38. package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +0 -261
  39. package/src/pages-standard/plan-versions/types.ts +0 -33
  40. package/src/vue/use-plan-versions.ts +0 -83
@@ -38,7 +38,6 @@ __export(client_exports, {
38
38
  SA_MESSAGES: () => SA_MESSAGES,
39
39
  buildRoutes: () => buildRoutes,
40
40
  buildSidebar: () => buildSidebar,
41
- buildSnapshots: () => buildSnapshots,
42
41
  defaultHttpClient: () => defaultHttpClient,
43
42
  defaultKvStore: () => defaultKvStore,
44
43
  defaultSectionOrder: () => defaultSectionOrder,
@@ -46,7 +45,6 @@ __export(client_exports, {
46
45
  formatCurrency: () => formatCurrency,
47
46
  formatMessage: () => formatMessage,
48
47
  getJson: () => getJson,
49
- listOpenDrafts: () => listOpenDrafts,
50
48
  mergeMessages: () => mergeMessages,
51
49
  postJson: () => postJson,
52
50
  resolveExtension: () => resolveExtension,
@@ -274,7 +272,6 @@ var navMessages = defineMessages(
274
272
  subscriptions: "Abonnements",
275
273
  promoCodes: "Promo-Codes",
276
274
  plans: "Pl\xE4ne & Versionen",
277
- planVersions: "Plan-Versionen",
278
275
  audit: "Audit-Log",
279
276
  users: "Benutzer",
280
277
  pilots: "Piloten",
@@ -298,7 +295,6 @@ var navMessages = defineMessages(
298
295
  subscriptions: "Subscriptions",
299
296
  promoCodes: "Promo codes",
300
297
  plans: "Plans & versions",
301
- planVersions: "Plan versions",
302
298
  audit: "Audit log",
303
299
  users: "Users",
304
300
  pilots: "Pilots",
@@ -324,7 +320,6 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
324
320
  subscriptions: "/admin/subscriptions",
325
321
  promoCodes: "/admin/promo-codes",
326
322
  plans: "/admin/plans",
327
- planVersions: "/admin/plan-versions",
328
323
  audit: "/admin/audit",
329
324
  users: "/admin/users",
330
325
  pilots: "/admin/pilots",
@@ -334,13 +329,15 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
334
329
  platformEmail: "/admin/platform-email",
335
330
  platformEmailHistory: "/admin/platform-email-history"
336
331
  };
332
+ function isSupportedStandardPageKey(key) {
333
+ return Object.hasOwn(DEFAULT_STANDARD_PAGE_ROUTES, key);
334
+ }
337
335
  var DEFAULT_ICONS = {
338
336
  dashboard: "dashboard",
339
337
  tenants: "business",
340
338
  subscriptions: "card_membership",
341
339
  promoCodes: "local_activity",
342
340
  plans: "workspace_premium",
343
- planVersions: "history_edu",
344
341
  audit: "history",
345
342
  users: "people",
346
343
  pilots: "flight_takeoff",
@@ -355,7 +352,6 @@ var PAGE_SECTIONS = {
355
352
  discovery: "catalog",
356
353
  bundles: "catalog",
357
354
  plans: "catalog",
358
- planVersions: "catalog",
359
355
  marketingCatalog: "catalog",
360
356
  promoCodes: "catalog",
361
357
  tenants: "customers",
@@ -383,6 +379,7 @@ function buildRoutes(manifest, options = {}) {
383
379
  const overrideIcons = { ...DEFAULT_ICONS, ...options.standardPageIcons };
384
380
  const overrideNavSection = { ...defaultNavSections, ...options.standardPageNavSection };
385
381
  for (const key of Object.keys(standard)) {
382
+ if (!isSupportedStandardPageKey(key)) continue;
386
383
  const def = standard[key];
387
384
  if (!def?.enabled) continue;
388
385
  const cap = def.requiredCapability ?? null;
@@ -631,464 +628,6 @@ function formatMessage(template, params) {
631
628
  });
632
629
  }
633
630
 
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
936
- };
937
- }
938
- function draftsTitle(draftCount, msg) {
939
- if (draftCount === 0) return msg.draftsTitleEmpty;
940
- const template = draftCount === 1 ? msg.draftsTitleOne : msg.draftsTitleMany;
941
- return formatMessage(template, { count: draftCount });
942
- }
943
- function dateLabel(iso, locale) {
944
- return new Date(iso).toLocaleDateString(SA_INTL_LOCALES[locale], {
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
975
- };
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
- return {
989
- id: "active",
990
- kind: "active",
991
- status: "ACTIVE",
992
- label: msg.activeLabel,
993
- title: msg.activeTitle,
994
- description: msg.activeDescription,
995
- asOf: latestPublished ?? null,
996
- createdAt: null,
997
- publishedAt: latestPublished ?? null,
998
- authorEmail: null,
999
- plans: sortPlansFn(plans),
1000
- draftCount: 0,
1001
- regressionCount: 0
1002
- };
1003
- }
1004
- function buildHistoricalSnapshots(data, sortPlansFn, locale) {
1005
- const msg = planVersionsMessages[locale].catalog;
1006
- const allPublishedAt = /* @__PURE__ */ new Set();
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);
1014
- }
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
- }
1049
- function summarizeEvent(rows, msg) {
1050
- if (rows.length === 0) return msg.publishEvent;
1051
- if (rows.length === 1) {
1052
- const r = rows[0];
1053
- return formatMessage(msg.publishEventSingle, { planId: r.planId, version: r.version });
1054
- }
1055
- return formatMessage(msg.publishEventMultiple, { count: rows.length });
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;
1061
- }
1062
- function sortPlansBy(order) {
1063
- if (!order || order.length === 0) {
1064
- return (rows) => [...rows].sort((a, b) => a.planId.localeCompare(b.planId));
1065
- }
1066
- const idx = {};
1067
- for (let i = 0; i < order.length; i++) idx[order[i]] = i;
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);
1073
- });
1074
- }
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
-
1092
631
  // src/client/i18n/currency.ts
1093
632
  var DEFAULT_CURRENCY = "EUR";
1094
633
  var formatters = /* @__PURE__ */ new Map();
@@ -2955,6 +2494,114 @@ var planEditorMessages = defineMessages(
2955
2494
  }
2956
2495
  );
2957
2496
 
2497
+ // src/client/i18n/messages/plan-versions.ts
2498
+ var planVersionsMessages = defineMessages(
2499
+ {
2500
+ compareEnd: "Vergleich beenden",
2501
+ status: {
2502
+ draft: "DRAFT",
2503
+ active: "AKTIV",
2504
+ archived: "ARCHIV"
2505
+ },
2506
+ timeline: {
2507
+ title: "Plan-Catalog",
2508
+ snapshotCount: "{count} Snapshots",
2509
+ noOpenDrafts: "keine offenen Drafts",
2510
+ openCount: "{count} offen",
2511
+ unknown: "unbekannt",
2512
+ compareHint: "Rechtsklick auf Snapshot \u2192 vergleichen"
2513
+ },
2514
+ diff: {
2515
+ legend: "Vergleich",
2516
+ plansChanged: "Pakete ge\xE4ndert",
2517
+ regressions: "Regressionen",
2518
+ sectionPlans: "Pakete",
2519
+ changeCountOne: "{count} \xC4nderung",
2520
+ changeCountMany: "{count} \xC4nderungen"
2521
+ },
2522
+ diffPreview: {
2523
+ empty: "Keine \xC4nderungen gegen\xFCber der Vorg\xE4ngerversion.",
2524
+ improvement: "Verbesserung",
2525
+ regression: "Verschlechterung",
2526
+ neutral: "Neutral"
2527
+ },
2528
+ diffFields: {
2529
+ featuresAdded: "Hinzugef\xFCgte Features",
2530
+ featuresRemoved: "Entfernte Features",
2531
+ maxUsers: "Max. Benutzer",
2532
+ maxStorageGb: "Speicher (GB)",
2533
+ monthlyNet: "Preis monatlich (netto)",
2534
+ yearlyNet: "Preis j\xE4hrlich (netto)",
2535
+ unitSize: "Einheitsgr\xF6\xDFe"
2536
+ },
2537
+ bulkPublish: {
2538
+ changeNoteRequired: "changeNote ist Pflicht beim Publish."
2539
+ },
2540
+ format: {
2541
+ today: "heute",
2542
+ yesterday: "gestern",
2543
+ daysAgo: "vor {count} Tagen",
2544
+ weeksAgoOne: "vor {count} Woche",
2545
+ weeksAgoMany: "vor {count} Wochen",
2546
+ monthsAgo: "vor {count} Monaten",
2547
+ yearsAgoOne: "vor {count} Jahr",
2548
+ yearsAgoMany: "vor {count} Jahren"
2549
+ }
2550
+ },
2551
+ {
2552
+ compareEnd: "End comparison",
2553
+ status: {
2554
+ draft: "DRAFT",
2555
+ active: "ACTIVE",
2556
+ archived: "ARCHIVED"
2557
+ },
2558
+ timeline: {
2559
+ title: "Plan catalog",
2560
+ snapshotCount: "{count} snapshots",
2561
+ noOpenDrafts: "no open drafts",
2562
+ openCount: "{count} open",
2563
+ unknown: "unknown",
2564
+ compareHint: "Right-click a snapshot \u2192 compare"
2565
+ },
2566
+ diff: {
2567
+ legend: "Comparison",
2568
+ plansChanged: "Plans changed",
2569
+ regressions: "Regressions",
2570
+ sectionPlans: "Plans",
2571
+ changeCountOne: "{count} change",
2572
+ changeCountMany: "{count} changes"
2573
+ },
2574
+ diffPreview: {
2575
+ empty: "No changes compared to the previous version.",
2576
+ improvement: "Improvement",
2577
+ regression: "Regression",
2578
+ neutral: "Neutral"
2579
+ },
2580
+ diffFields: {
2581
+ featuresAdded: "Added features",
2582
+ featuresRemoved: "Removed features",
2583
+ maxUsers: "Max. users",
2584
+ maxStorageGb: "Storage (GB)",
2585
+ monthlyNet: "Price monthly (net)",
2586
+ yearlyNet: "Price yearly (net)",
2587
+ unitSize: "Unit size"
2588
+ },
2589
+ bulkPublish: {
2590
+ changeNoteRequired: "changeNote is required when publishing."
2591
+ },
2592
+ format: {
2593
+ today: "today",
2594
+ yesterday: "yesterday",
2595
+ daysAgo: "{count} days ago",
2596
+ weeksAgoOne: "{count} week ago",
2597
+ weeksAgoMany: "{count} weeks ago",
2598
+ monthsAgo: "{count} months ago",
2599
+ yearsAgoOne: "{count} year ago",
2600
+ yearsAgoMany: "{count} years ago"
2601
+ }
2602
+ }
2603
+ );
2604
+
2958
2605
  // src/client/i18n/messages/plans.ts
2959
2606
  var plansMessages = defineMessages(
2960
2607
  {
@@ -3971,7 +3618,6 @@ function resolveMessages(locale, overrides) {
3971
3618
  SA_MESSAGES,
3972
3619
  buildRoutes,
3973
3620
  buildSidebar,
3974
- buildSnapshots,
3975
3621
  defaultHttpClient,
3976
3622
  defaultKvStore,
3977
3623
  defaultSectionOrder,
@@ -3979,7 +3625,6 @@ function resolveMessages(locale, overrides) {
3979
3625
  formatCurrency,
3980
3626
  formatMessage,
3981
3627
  getJson,
3982
- listOpenDrafts,
3983
3628
  mergeMessages,
3984
3629
  postJson,
3985
3630
  resolveExtension,