@almadar/ui 5.128.0 → 5.129.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.
@@ -27314,12 +27314,12 @@ var init_MapView = __esm({
27314
27314
  shadowSize: [41, 41]
27315
27315
  });
27316
27316
  L.Marker.prototype.options.icon = defaultIcon;
27317
- const { useEffect: useEffect62, useRef: useRef59, useCallback: useCallback93, useState: useState91 } = React84__default;
27317
+ const { useEffect: useEffect62, useRef: useRef60, useCallback: useCallback93, useState: useState91 } = React84__default;
27318
27318
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
27319
27319
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
27320
27320
  function MapUpdater({ centerLat, centerLng, zoom }) {
27321
27321
  const map = useMap();
27322
- const prevRef = useRef59({ centerLat, centerLng, zoom });
27322
+ const prevRef = useRef60({ centerLat, centerLng, zoom });
27323
27323
  useEffect62(() => {
27324
27324
  const prev = prevRef.current;
27325
27325
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
@@ -36509,6 +36509,290 @@ var init_GraphCanvas = __esm({
36509
36509
  GraphCanvas.displayName = "GraphCanvas";
36510
36510
  }
36511
36511
  });
36512
+ var ImportSourcePicker;
36513
+ var init_ImportSourcePicker = __esm({
36514
+ "components/core/molecules/import/ImportSourcePicker.tsx"() {
36515
+ "use client";
36516
+ init_Box();
36517
+ init_Icon();
36518
+ init_Typography();
36519
+ init_cn();
36520
+ ImportSourcePicker = ({
36521
+ sources,
36522
+ onSelect,
36523
+ onFilesSelected,
36524
+ title,
36525
+ moreSources,
36526
+ className
36527
+ }) => {
36528
+ const fileInputRef = useRef(null);
36529
+ const handlePick = (source) => {
36530
+ if (source.disabled) return;
36531
+ if (source.kind === "file") {
36532
+ const input = fileInputRef.current;
36533
+ if (!input) return;
36534
+ input.accept = source.accept ?? "";
36535
+ input.multiple = source.multiple ?? false;
36536
+ input.click();
36537
+ return;
36538
+ }
36539
+ onSelect?.(source.id);
36540
+ };
36541
+ const handleFiles = (event) => {
36542
+ const files = event.target.files ? Array.from(event.target.files) : [];
36543
+ event.target.value = "";
36544
+ if (files.length > 0) onFilesSelected?.(files);
36545
+ };
36546
+ return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
36547
+ title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
36548
+ sources.map((source) => /* @__PURE__ */ jsxs(
36549
+ Box,
36550
+ {
36551
+ role: "button",
36552
+ tabIndex: source.disabled ? -1 : 0,
36553
+ "aria-disabled": source.disabled,
36554
+ onClick: () => handlePick(source),
36555
+ onKeyDown: (event) => {
36556
+ if (event.key === "Enter" || event.key === " ") {
36557
+ event.preventDefault();
36558
+ handlePick(source);
36559
+ }
36560
+ },
36561
+ className: cn(
36562
+ "flex items-center gap-3 rounded-md border border-border bg-card px-4 py-3 text-left",
36563
+ source.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-accent hover:text-accent-foreground"
36564
+ ),
36565
+ children: [
36566
+ source.icon ? /* @__PURE__ */ jsx(Icon, { icon: source.icon, size: "md" }) : null,
36567
+ /* @__PURE__ */ jsxs(Box, { className: "flex flex-col", children: [
36568
+ /* @__PURE__ */ jsx(Typography, { variant: "label", children: source.label }),
36569
+ source.description ? /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: source.description }) : null
36570
+ ] })
36571
+ ]
36572
+ },
36573
+ source.id
36574
+ )),
36575
+ moreSources,
36576
+ /* @__PURE__ */ jsx(
36577
+ "input",
36578
+ {
36579
+ ref: fileInputRef,
36580
+ type: "file",
36581
+ className: "hidden",
36582
+ onChange: handleFiles,
36583
+ "data-testid": "import-source-file-input"
36584
+ }
36585
+ )
36586
+ ] });
36587
+ };
36588
+ }
36589
+ });
36590
+ function formatFieldValue(value) {
36591
+ if (value === null) return "\u2014";
36592
+ if (value instanceof Date) return value.toISOString();
36593
+ if (Array.isArray(value)) return value.map(formatFieldValue).join(", ");
36594
+ if (typeof value === "object") return JSON.stringify(value);
36595
+ return String(value);
36596
+ }
36597
+ function unitTitle(unit) {
36598
+ for (const key of TITLE_KEYS) {
36599
+ const value = unit.fields[key];
36600
+ if (typeof value === "string" && value.length > 0) return value;
36601
+ }
36602
+ return unit.ref;
36603
+ }
36604
+ function fieldSummary(unit) {
36605
+ return Object.entries(unit.fields).filter(([key]) => !TITLE_KEYS.includes(key)).map(([key, value]) => `${key}: ${formatFieldValue(value)}`).join(" \xB7 ");
36606
+ }
36607
+ var TITLE_KEYS, ImportPreviewTree;
36608
+ var init_ImportPreviewTree = __esm({
36609
+ "components/core/molecules/import/ImportPreviewTree.tsx"() {
36610
+ "use client";
36611
+ init_Box();
36612
+ init_Badge();
36613
+ init_Button();
36614
+ init_Icon();
36615
+ init_Typography();
36616
+ init_cn();
36617
+ TITLE_KEYS = ["title", "name", "label"];
36618
+ ImportPreviewTree = ({
36619
+ units,
36620
+ skipped = [],
36621
+ entityDisplay,
36622
+ onConfirm,
36623
+ onCancel,
36624
+ confirmLabel = "Confirm import",
36625
+ cancelLabel = "Cancel",
36626
+ indent = 16,
36627
+ className
36628
+ }) => {
36629
+ const groups = /* @__PURE__ */ new Map();
36630
+ for (const unit of units) {
36631
+ const group = groups.get(unit.targetEntity);
36632
+ if (group) group.push(unit);
36633
+ else groups.set(unit.targetEntity, [unit]);
36634
+ }
36635
+ const renderUnit = (unit, childrenByParent, depth) => {
36636
+ const summary = fieldSummary(unit);
36637
+ const children = childrenByParent.get(unit.ref) ?? [];
36638
+ return /* @__PURE__ */ jsxs(React84__default.Fragment, { children: [
36639
+ /* @__PURE__ */ jsxs(
36640
+ Box,
36641
+ {
36642
+ className: "flex flex-col py-1",
36643
+ style: { paddingLeft: depth * indent },
36644
+ "data-testid": `import-preview-unit-${unit.ref}`,
36645
+ children: [
36646
+ /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-2", children: [
36647
+ /* @__PURE__ */ jsx(Icon, { icon: "file-text", size: "xs", className: "text-muted-foreground" }),
36648
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", children: unitTitle(unit) })
36649
+ ] }),
36650
+ summary ? /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: summary }) : null
36651
+ ]
36652
+ }
36653
+ ),
36654
+ children.map((child) => renderUnit(child, childrenByParent, depth + 1))
36655
+ ] }, unit.ref);
36656
+ };
36657
+ return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col gap-4", className), children: [
36658
+ units.length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: "No units staged." }) : null,
36659
+ Array.from(groups.entries()).map(([entity, groupUnits]) => {
36660
+ const refs = new Set(groupUnits.map((unit) => unit.ref));
36661
+ const childrenByParent = /* @__PURE__ */ new Map();
36662
+ const roots = [];
36663
+ for (const unit of groupUnits) {
36664
+ if (unit.parentRef && refs.has(unit.parentRef)) {
36665
+ const siblings = childrenByParent.get(unit.parentRef);
36666
+ if (siblings) siblings.push(unit);
36667
+ else childrenByParent.set(unit.parentRef, [unit]);
36668
+ } else {
36669
+ roots.push(unit);
36670
+ }
36671
+ }
36672
+ const label = entityDisplay[entity]?.plural ?? entity;
36673
+ return /* @__PURE__ */ jsxs(Box, { border: true, className: "rounded-md border-border bg-card p-3", children: [
36674
+ /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-2 pb-2", children: [
36675
+ /* @__PURE__ */ jsx(Typography, { variant: "label", children: label }),
36676
+ /* @__PURE__ */ jsx(Badge, { amount: groupUnits.length })
36677
+ ] }),
36678
+ roots.map((unit) => renderUnit(unit, childrenByParent, 0))
36679
+ ] }, entity);
36680
+ }),
36681
+ skipped.length > 0 ? /* @__PURE__ */ jsxs(Box, { border: true, className: "rounded-md border-border bg-card p-3", children: [
36682
+ /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-2 pb-2", children: [
36683
+ /* @__PURE__ */ jsx(Typography, { variant: "label", children: "Skipped" }),
36684
+ /* @__PURE__ */ jsx(Badge, { amount: skipped.length })
36685
+ ] }),
36686
+ skipped.map((element) => /* @__PURE__ */ jsxs(Box, { className: "flex items-baseline gap-2 py-1", children: [
36687
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", children: element.ref }),
36688
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: element.reason })
36689
+ ] }, element.ref))
36690
+ ] }) : null,
36691
+ onConfirm || onCancel ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-end gap-2", children: [
36692
+ onCancel ? /* @__PURE__ */ jsx(Button, { variant: "default", label: cancelLabel, onClick: onCancel }) : null,
36693
+ onConfirm ? /* @__PURE__ */ jsx(Button, { variant: "primary", label: confirmLabel, onClick: onConfirm }) : null
36694
+ ] }) : null
36695
+ ] });
36696
+ };
36697
+ }
36698
+ });
36699
+ var PIPELINE, DEFAULT_LABELS, ImportProgress;
36700
+ var init_ImportProgress = __esm({
36701
+ "components/core/molecules/import/ImportProgress.tsx"() {
36702
+ "use client";
36703
+ init_Box();
36704
+ init_Badge();
36705
+ init_Icon();
36706
+ init_Typography();
36707
+ init_cn();
36708
+ PIPELINE = [
36709
+ "fetching",
36710
+ "mapping",
36711
+ "reviewing",
36712
+ "committing"
36713
+ ];
36714
+ DEFAULT_LABELS = {
36715
+ fetching: "Fetching",
36716
+ mapping: "Mapping",
36717
+ reviewing: "Reviewing",
36718
+ committing: "Committing",
36719
+ done: "Done",
36720
+ failed: "Failed"
36721
+ };
36722
+ ImportProgress = ({
36723
+ step,
36724
+ counts,
36725
+ labels,
36726
+ className
36727
+ }) => {
36728
+ const label = (key) => labels?.[key] ?? DEFAULT_LABELS[key];
36729
+ const currentIndex = step === "done" || step === "failed" ? PIPELINE.length : PIPELINE.indexOf(step);
36730
+ return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col gap-3", className), children: [
36731
+ /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-2", children: [
36732
+ PIPELINE.map((key, index) => {
36733
+ const isComplete = index < currentIndex;
36734
+ const isActive = index === currentIndex;
36735
+ return /* @__PURE__ */ jsxs(React84__default.Fragment, { children: [
36736
+ index > 0 ? /* @__PURE__ */ jsx(Box, { className: "h-px w-4 bg-border" }) : null,
36737
+ /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1", "data-testid": `import-progress-step-${key}`, children: [
36738
+ /* @__PURE__ */ jsx(
36739
+ Icon,
36740
+ {
36741
+ icon: isComplete ? "check" : isActive ? "loader" : "circle",
36742
+ size: "sm",
36743
+ className: cn(
36744
+ isComplete ? "text-success" : isActive ? "text-primary" : "text-muted-foreground"
36745
+ )
36746
+ }
36747
+ ),
36748
+ /* @__PURE__ */ jsx(
36749
+ Typography,
36750
+ {
36751
+ variant: "caption",
36752
+ className: cn(isActive ? "text-foreground" : "text-muted-foreground"),
36753
+ children: label(key)
36754
+ }
36755
+ )
36756
+ ] })
36757
+ ] }, key);
36758
+ }),
36759
+ step === "done" || step === "failed" ? /* @__PURE__ */ jsxs(Fragment, { children: [
36760
+ /* @__PURE__ */ jsx(Box, { className: "h-px w-4 bg-border" }),
36761
+ /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1", "data-testid": `import-progress-step-${step}`, children: [
36762
+ /* @__PURE__ */ jsx(
36763
+ Icon,
36764
+ {
36765
+ icon: step === "done" ? "check" : "x",
36766
+ size: "sm",
36767
+ className: step === "done" ? "text-success" : "text-error"
36768
+ }
36769
+ ),
36770
+ /* @__PURE__ */ jsx(
36771
+ Typography,
36772
+ {
36773
+ variant: "caption",
36774
+ className: step === "done" ? "text-success" : "text-error",
36775
+ children: label(step)
36776
+ }
36777
+ )
36778
+ ] })
36779
+ ] }) : null
36780
+ ] }),
36781
+ counts ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-2", children: [
36782
+ counts.staged !== void 0 ? /* @__PURE__ */ jsx(Badge, { label: `Staged ${counts.staged}` }) : null,
36783
+ counts.committed !== void 0 ? /* @__PURE__ */ jsx(Badge, { variant: "success", label: `Committed ${counts.committed}` }) : null,
36784
+ counts.failed !== void 0 ? /* @__PURE__ */ jsx(Badge, { variant: "danger", label: `Failed ${counts.failed}` }) : null
36785
+ ] }) : null
36786
+ ] });
36787
+ };
36788
+ }
36789
+ });
36790
+
36791
+ // components/core/molecules/import/index.ts
36792
+ var init_import = __esm({
36793
+ "components/core/molecules/import/index.ts"() {
36794
+ }
36795
+ });
36512
36796
  var ReflectionBlock;
36513
36797
  var init_ReflectionBlock = __esm({
36514
36798
  "components/core/molecules/ReflectionBlock.tsx"() {
@@ -36583,6 +36867,7 @@ var init_molecules2 = __esm({
36583
36867
  init_EmptyState();
36584
36868
  init_Pagination();
36585
36869
  init_molecules();
36870
+ init_import();
36586
36871
  }
36587
36872
  });
36588
36873
 
@@ -37063,7 +37348,7 @@ function getBadgeVariant(fieldName, value) {
37063
37348
  function formatFieldLabel(fieldName) {
37064
37349
  return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
37065
37350
  }
37066
- function formatFieldValue(value, fieldName) {
37351
+ function formatFieldValue2(value, fieldName) {
37067
37352
  if (typeof value === "number") {
37068
37353
  if (fieldName.toLowerCase().includes("progress") || fieldName.toLowerCase().includes("percent")) {
37069
37354
  return `${value}%`;
@@ -37158,7 +37443,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
37158
37443
  return str;
37159
37444
  }
37160
37445
  default:
37161
- return formatFieldValue(value, fieldName);
37446
+ return formatFieldValue2(value, fieldName);
37162
37447
  }
37163
37448
  }
37164
37449
  function normalizeFieldDefs(fields) {
@@ -37269,7 +37554,7 @@ var init_DetailPanel = __esm({
37269
37554
  const value = getNestedValue(normalizedData, field);
37270
37555
  return {
37271
37556
  label: labelFor(field),
37272
- value: formatFieldValue(value, field),
37557
+ value: formatFieldValue2(value, field),
37273
37558
  icon: getFieldIcon(field)
37274
37559
  };
37275
37560
  }
@@ -43281,6 +43566,9 @@ var init_component_registry_generated = __esm({
43281
43566
  init_HeroOrganism();
43282
43567
  init_HeroSection();
43283
43568
  init_Icon();
43569
+ init_ImportPreviewTree();
43570
+ init_ImportProgress();
43571
+ init_ImportSourcePicker();
43284
43572
  init_InfiniteScrollSentinel();
43285
43573
  init_Input();
43286
43574
  init_InputGroup();
@@ -43544,6 +43832,9 @@ var init_component_registry_generated = __esm({
43544
43832
  "HeroOrganism": HeroOrganism,
43545
43833
  "HeroSection": HeroSection,
43546
43834
  "Icon": Icon,
43835
+ "ImportPreviewTree": ImportPreviewTree,
43836
+ "ImportProgress": ImportProgress,
43837
+ "ImportSourcePicker": ImportSourcePicker,
43547
43838
  "InfiniteScrollSentinel": InfiniteScrollSentinel,
43548
43839
  "Input": Input,
43549
43840
  "InputGroup": InputGroup,