@streamoid/catalogix-chat 0.2.5 → 0.2.7

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 (2) hide show
  1. package/dist/index.js +109 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2444,16 +2444,29 @@ import {
2444
2444
  Search as Search3,
2445
2445
  ArrowRight,
2446
2446
  ArrowLeft as ArrowLeft2,
2447
- Send
2447
+ Send,
2448
+ AlertTriangle
2448
2449
  } from "lucide-react";
2449
- import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
2450
+ import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
2450
2451
  function getAllAttributes(mpAttributes) {
2451
2452
  return Object.values(mpAttributes).flat();
2452
2453
  }
2454
+ function hasIncompleteLovValues(item, valuesOntologyAttributes, uniqueValues) {
2455
+ if (!item.isConfirmed || item.isIgnored) return false;
2456
+ for (const attr of item.mappedCols) {
2457
+ if (!valuesOntologyAttributes.includes(attr)) continue;
2458
+ const rawVals = uniqueValues[item.feedCol] || [];
2459
+ if (rawVals.length === 0) continue;
2460
+ const mapped = item.mappedValues[attr] || {};
2461
+ if (rawVals.some((v) => mapped[v] == null)) return true;
2462
+ }
2463
+ return false;
2464
+ }
2453
2465
  function AttributeRow({
2454
2466
  item,
2455
2467
  index,
2456
2468
  allAttributes,
2469
+ needsValueAttention,
2457
2470
  onMap,
2458
2471
  onConfirm,
2459
2472
  onIgnore,
@@ -2467,11 +2480,15 @@ function AttributeRow({
2467
2480
  return allAttributes.filter((a) => !mapped.has(a));
2468
2481
  }, [allAttributes, item.mappedCols, item.customCols]);
2469
2482
  if (item.isConfirmed) {
2470
- return /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 py-1.5 group", children: [
2471
- /* @__PURE__ */ jsx21(Check2, { className: "size-3 shrink-0 text-emerald-600 dark:text-emerald-400" }),
2483
+ return /* @__PURE__ */ jsxs10("div", { className: cn(
2484
+ "flex items-center gap-2 py-1.5 group",
2485
+ needsValueAttention && "border-l-2 border-amber-500/60 pl-2"
2486
+ ), children: [
2487
+ needsValueAttention ? /* @__PURE__ */ jsx21(AlertTriangle, { className: "size-3 shrink-0 text-amber-500" }) : /* @__PURE__ */ jsx21(Check2, { className: "size-3 shrink-0 text-emerald-600 dark:text-emerald-400" }),
2472
2488
  /* @__PURE__ */ jsx21("span", { className: "text-xs font-medium truncate", children: item.feedCol }),
2473
2489
  /* @__PURE__ */ jsx21(ChevronRight2, { className: "size-3 shrink-0 text-muted-foreground" }),
2474
- /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground truncate flex-1", children: [...item.mappedCols, ...item.customCols].join(", ") }),
2490
+ /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground truncate", children: [...item.mappedCols, ...item.customCols].join(", ") }),
2491
+ needsValueAttention && /* @__PURE__ */ jsx21(Badge, { variant: "outline", className: "text-[10px] h-4 px-1 border-amber-500/50 text-amber-600 dark:text-amber-400 shrink-0", children: "values needed" }),
2475
2492
  /* @__PURE__ */ jsx21(
2476
2493
  "button",
2477
2494
  {
@@ -2486,7 +2503,7 @@ function AttributeRow({
2486
2503
  if (item.isIgnored) {
2487
2504
  return /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 py-1.5 group", children: [
2488
2505
  /* @__PURE__ */ jsx21(X, { className: "size-3 shrink-0 text-destructive" }),
2489
- /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground line-through truncate flex-1", children: item.feedCol }),
2506
+ /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground line-through truncate", children: item.feedCol }),
2490
2507
  /* @__PURE__ */ jsx21(
2491
2508
  "button",
2492
2509
  {
@@ -2498,7 +2515,7 @@ function AttributeRow({
2498
2515
  )
2499
2516
  ] });
2500
2517
  }
2501
- return /* @__PURE__ */ jsxs10("div", { className: "py-2 space-y-1.5", children: [
2518
+ return /* @__PURE__ */ jsxs10("div", { className: "py-2 space-y-1.5 border-l-2 border-destructive/60 pl-2", children: [
2502
2519
  /* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
2503
2520
  /* @__PURE__ */ jsx21("p", { className: "text-xs font-medium", children: item.feedCol }),
2504
2521
  item.rows.length > 0 && /* @__PURE__ */ jsx21("p", { className: "text-[11px] text-muted-foreground truncate", children: item.rows.slice(0, 3).join(", ") })
@@ -2693,6 +2710,49 @@ function MapAttributesChat({
2693
2710
  ),
2694
2711
  [data, valuesOntologyAttributes]
2695
2712
  );
2713
+ const allValuesComplete = useMemo5(() => {
2714
+ for (const item of data) {
2715
+ if (item.isIgnored || !item.isConfirmed) continue;
2716
+ for (const attr of item.mappedCols) {
2717
+ if (!valuesOntologyAttributes.includes(attr)) continue;
2718
+ const rawVals = uniqueValues[item.feedCol] || [];
2719
+ const mapped = item.mappedValues[attr] || {};
2720
+ if (rawVals.some((v) => mapped[v] == null)) return false;
2721
+ }
2722
+ }
2723
+ return true;
2724
+ }, [data, valuesOntologyAttributes, uniqueValues]);
2725
+ const lovAttentionSet = useMemo5(() => {
2726
+ const set = /* @__PURE__ */ new Set();
2727
+ data.forEach((item, idx) => {
2728
+ if (hasIncompleteLovValues(item, valuesOntologyAttributes, uniqueValues)) {
2729
+ set.add(idx);
2730
+ }
2731
+ });
2732
+ return set;
2733
+ }, [data, valuesOntologyAttributes, uniqueValues]);
2734
+ const attentionSummary = useMemo5(() => {
2735
+ const unmappedCount = data.filter(
2736
+ (i) => !i.isConfirmed && !i.isIgnored
2737
+ ).length;
2738
+ const lovIncompleteCount = lovAttentionSet.size;
2739
+ return { unmappedCount, lovIncompleteCount };
2740
+ }, [data, lovAttentionSet]);
2741
+ const sortedIndices = useMemo5(() => {
2742
+ const indices = data.map((_, i) => i);
2743
+ indices.sort((a, b) => {
2744
+ const itemA = data[a];
2745
+ const itemB = data[b];
2746
+ const priorityOf = (item, idx) => {
2747
+ if (!item.isConfirmed && !item.isIgnored) return 0;
2748
+ if (lovAttentionSet.has(idx)) return 1;
2749
+ if (item.isConfirmed) return 2;
2750
+ return 3;
2751
+ };
2752
+ return priorityOf(itemA, a) - priorityOf(itemB, b);
2753
+ });
2754
+ return indices;
2755
+ }, [data, lovAttentionSet]);
2696
2756
  const handleMap = useCallback5((index, attribute) => {
2697
2757
  setData((prev) => {
2698
2758
  const next = [...prev];
@@ -2766,33 +2826,54 @@ function MapAttributesChat({
2766
2826
  ] })
2767
2827
  ] });
2768
2828
  }
2769
- return /* @__PURE__ */ jsxs10(Card, { className: "w-full max-h-[45vh] gap-0 flex flex-col shadow-sm", children: [
2829
+ return /* @__PURE__ */ jsxs10(Card, { className: "w-[60%] max-w-2xl max-h-[45vh] gap-0 flex flex-col shadow-sm", children: [
2770
2830
  /* @__PURE__ */ jsxs10("div", { className: "px-4 pt-3 pb-2 flex-shrink-0 space-y-2", children: [
2771
2831
  /* @__PURE__ */ jsxs10("div", { children: [
2772
2832
  /* @__PURE__ */ jsx21("h3", { className: "text-sm font-semibold tracking-tight", children: step === "attributes" ? "Map Attributes" : "Map Values" }),
2773
2833
  /* @__PURE__ */ jsx21("p", { className: "text-xs text-muted-foreground leading-snug", children: step === "attributes" ? "Match each feed column to a marketplace attribute" : "Normalize values for controlled-vocabulary attributes" })
2774
2834
  ] }),
2775
- step === "attributes" && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
2776
- /* @__PURE__ */ jsx21("div", { className: "h-1 flex-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx21(
2777
- "div",
2778
- {
2779
- className: "h-full rounded-full bg-primary transition-all",
2780
- style: { width: `${progress.percent}%` }
2781
- }
2782
- ) }),
2783
- /* @__PURE__ */ jsxs10("span", { className: "text-[11px] text-muted-foreground tabular-nums shrink-0", children: [
2784
- progress.done,
2785
- "/",
2786
- progress.total
2835
+ step === "attributes" && /* @__PURE__ */ jsxs10(Fragment4, { children: [
2836
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
2837
+ /* @__PURE__ */ jsx21("div", { className: "h-1 flex-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx21(
2838
+ "div",
2839
+ {
2840
+ className: "h-full rounded-full bg-primary transition-all",
2841
+ style: { width: `${progress.percent}%` }
2842
+ }
2843
+ ) }),
2844
+ /* @__PURE__ */ jsxs10("span", { className: "text-[11px] text-muted-foreground tabular-nums shrink-0", children: [
2845
+ progress.done,
2846
+ "/",
2847
+ progress.total
2848
+ ] })
2849
+ ] }),
2850
+ (attentionSummary.unmappedCount > 0 || attentionSummary.lovIncompleteCount > 0) && /* @__PURE__ */ jsxs10("div", { className: "flex items-start gap-1.5 rounded-md bg-amber-500/10 border border-amber-500/20 px-2.5 py-1.5", children: [
2851
+ /* @__PURE__ */ jsx21(AlertTriangle, { className: "size-3 mt-0.5 shrink-0 text-amber-500" }),
2852
+ /* @__PURE__ */ jsxs10("div", { className: "text-[11px] text-amber-700 dark:text-amber-400 leading-snug", children: [
2853
+ attentionSummary.unmappedCount > 0 && /* @__PURE__ */ jsxs10("span", { children: [
2854
+ attentionSummary.unmappedCount,
2855
+ " attribute",
2856
+ attentionSummary.unmappedCount > 1 ? "s" : "",
2857
+ " unmapped"
2858
+ ] }),
2859
+ attentionSummary.unmappedCount > 0 && attentionSummary.lovIncompleteCount > 0 && /* @__PURE__ */ jsx21("span", { children: " \xB7 " }),
2860
+ attentionSummary.lovIncompleteCount > 0 && /* @__PURE__ */ jsxs10("span", { children: [
2861
+ attentionSummary.lovIncompleteCount,
2862
+ " attribute",
2863
+ attentionSummary.lovIncompleteCount > 1 ? "s" : "",
2864
+ " need value mapping"
2865
+ ] })
2866
+ ] })
2787
2867
  ] })
2788
2868
  ] })
2789
2869
  ] }),
2790
- /* @__PURE__ */ jsx21("div", { className: "px-4 overflow-y-auto flex-1 min-h-0", children: step === "attributes" ? /* @__PURE__ */ jsx21("div", { className: "divide-y divide-border/50", children: data.map((item, idx) => /* @__PURE__ */ jsx21(
2870
+ /* @__PURE__ */ jsx21("div", { className: "px-4 overflow-y-auto flex-1 min-h-0", children: step === "attributes" ? /* @__PURE__ */ jsx21("div", { className: "divide-y divide-border/50", children: sortedIndices.map((idx) => /* @__PURE__ */ jsx21(
2791
2871
  AttributeRow,
2792
2872
  {
2793
- item,
2873
+ item: data[idx],
2794
2874
  index: idx,
2795
2875
  allAttributes,
2876
+ needsValueAttention: lovAttentionSet.has(idx),
2796
2877
  onMap: handleMap,
2797
2878
  onConfirm: handleConfirm,
2798
2879
  onIgnore: handleIgnore,
@@ -2842,7 +2923,7 @@ function MapAttributesChat({
2842
2923
  {
2843
2924
  size: "sm",
2844
2925
  onClick: handleSubmit,
2845
- disabled: progress.done < progress.total,
2926
+ disabled: progress.done < progress.total || hasLovAttributes && !allValuesComplete,
2846
2927
  className: "h-7 text-xs bg-primary text-primary-foreground shadow-none hover:bg-primary/90",
2847
2928
  children: [
2848
2929
  /* @__PURE__ */ jsx21(Send, { className: "mr-1 size-3" }),
@@ -3317,7 +3398,7 @@ function BooleanField({
3317
3398
  }
3318
3399
 
3319
3400
  // src/Automations/ProductAutomation.tsx
3320
- import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
3401
+ import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
3321
3402
  function ProductAutomation({
3322
3403
  storeId,
3323
3404
  workspaceId,
@@ -3597,10 +3678,10 @@ function ProductAutomation({
3597
3678
  onClick: handleRun,
3598
3679
  disabled: !isRunAllowed() || applying,
3599
3680
  className: "flex-1",
3600
- children: applying ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
3681
+ children: applying ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
3601
3682
  /* @__PURE__ */ jsx23(Loader26, { className: "size-4 animate-spin" }),
3602
3683
  "Applying..."
3603
- ] }) : /* @__PURE__ */ jsxs12(Fragment4, { children: [
3684
+ ] }) : /* @__PURE__ */ jsxs12(Fragment5, { children: [
3604
3685
  /* @__PURE__ */ jsx23(Play, { className: "size-4" }),
3605
3686
  "Run Automation"
3606
3687
  ] })
@@ -3644,7 +3725,7 @@ function formatTimeSaved(totalSeconds) {
3644
3725
  // src/Automations/StoreAutomation.tsx
3645
3726
  import { useState as useState10, useEffect as useEffect6, useCallback as useCallback8, useRef as useRef6 } from "react";
3646
3727
  import { ArrowLeft as ArrowLeft4, Settings } from "lucide-react";
3647
- import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
3728
+ import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
3648
3729
  function StoreAutomation({
3649
3730
  storeId,
3650
3731
  channelsWithVersion,
@@ -3892,7 +3973,7 @@ function AutomationConfigEditor({
3892
3973
  onConfigChange: handleConfigChange
3893
3974
  }
3894
3975
  ) : /* @__PURE__ */ jsx24("p", { className: "py-4 text-center text-sm text-muted-foreground", children: "Enable this automation to configure it." }) }),
3895
- automation.preview && /* @__PURE__ */ jsxs13(Fragment5, { children: [
3976
+ automation.preview && /* @__PURE__ */ jsxs13(Fragment6, { children: [
3896
3977
  /* @__PURE__ */ jsx24(Separator2, {}),
3897
3978
  /* @__PURE__ */ jsxs13("div", { className: "space-y-2 rounded-lg bg-muted/50 p-3 text-sm", children: [
3898
3979
  automation.preview.info_text.map((text, i) => /* @__PURE__ */ jsx24("p", { className: "text-muted-foreground", children: text }, i)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoid/catalogix-chat",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Catalogix chat components for the Streamoid chat host — store creation, product selection, automations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",