@campfire-interactive/volume-intelligence-ui 0.10.0 → 0.11.1

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/index.d.ts CHANGED
@@ -90,8 +90,12 @@ declare function VolumeImport(props: VolumeImportProps): react.JSX.Element;
90
90
 
91
91
  type SourceLayout = 'wide' | 'tall';
92
92
  /** `base` = IHS/AFS historical training signal (one active per tenant);
93
- * `overlay` = EDI-style additive customer-stated demand. */
94
- type VolumeSourceKind = 'base' | 'overlay';
93
+ * `overlay` = EDI-style additive customer-stated demand;
94
+ * `reference` = a second market vendor's curve, drawn beside the active base
95
+ * rather than summed into it. A reference source never drives prediction,
96
+ * never supplies level labels, and is never what an overlay links against —
97
+ * which is why it is a kind of its own rather than a second `base`. */
98
+ type VolumeSourceKind = 'base' | 'overlay' | 'reference';
95
99
  interface VolumeSource {
96
100
  id: string;
97
101
  code: string;
package/dist/index.js CHANGED
@@ -901,7 +901,8 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
901
901
  /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-card-title", children: [
902
902
  /* @__PURE__ */ jsx4("button", { type: "button", className: "cfi-vi-link", onClick: () => onOpenSource(src.id), children: src.name }),
903
903
  isActive && /* @__PURE__ */ jsx4(Badge, { variant: "success", children: "Active" }),
904
- src.kind === "overlay" && /* @__PURE__ */ jsx4(Badge, { variant: "purple", title: "Overlay sources are active whenever data is uploaded \u2014 no Set Active step.", children: "Overlay" })
904
+ src.kind === "overlay" && /* @__PURE__ */ jsx4(Badge, { variant: "purple", title: "Overlay sources are active whenever data is uploaded \u2014 no Set Active step.", children: "Overlay" }),
905
+ src.kind === "reference" && /* @__PURE__ */ jsx4(Badge, { variant: "outline", title: "A second vendor's curve, drawn beside the active base rather than summed into it. Never drives prediction and has no Set Active step.", children: "Reference" })
905
906
  ] }),
906
907
  /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-row", children: [
907
908
  /* @__PURE__ */ jsx4(Badge, { variant: "outline", children: src.code }),
@@ -1664,6 +1665,7 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, readOnl
1664
1665
  const [savingLayout, setSavingLayout] = useState7(false);
1665
1666
  const [editLayout, setEditLayout] = useState7("wide");
1666
1667
  const [editValueDateFormat, setEditValueDateFormat] = useState7("yyyy-MM-dd");
1668
+ const [editKind, setEditKind] = useState7("base");
1667
1669
  const [newSegmentLabel, setNewSegmentLabel] = useState7("");
1668
1670
  const [newSegmentDataType, setNewSegmentDataType] = useState7("string");
1669
1671
  const [addingSegment, setAddingSegment] = useState7(false);
@@ -1701,6 +1703,7 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, readOnl
1701
1703
  setSource(src);
1702
1704
  setSelectedKeyId(src.uniqueKeySegmentId ?? "__none__");
1703
1705
  setEditLayout(src.layout);
1706
+ setEditKind(src.kind);
1704
1707
  setEditValueDateFormat(src.valueDateFormat);
1705
1708
  setHasData(uploads.items.some((u) => u.status === "done" || u.status === "done_with_errors"));
1706
1709
  setMappingKeys(keys);
@@ -1832,12 +1835,17 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, readOnl
1832
1835
  setSavingKey(false);
1833
1836
  }
1834
1837
  }
1838
+ const crossesMeasure = !!source && editKind !== source.kind && (editKind === "overlay" || source.kind === "overlay");
1835
1839
  async function saveLayoutAndRouting() {
1836
1840
  if (!id) return;
1837
1841
  setSavingLayout(true);
1838
1842
  setError(null);
1839
1843
  try {
1840
- await transport.updateSource(id, { layout: editLayout, valueDateFormat: editValueDateFormat });
1844
+ await transport.updateSource(id, {
1845
+ layout: editLayout,
1846
+ valueDateFormat: editValueDateFormat,
1847
+ kind: editKind
1848
+ });
1841
1849
  await load();
1842
1850
  } catch (e) {
1843
1851
  setError(e instanceof Error ? e.message : "Failed to save layout");
@@ -1969,9 +1977,41 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, readOnl
1969
1977
  onChange: (e) => setEditValueDateFormat(e.target.value)
1970
1978
  }
1971
1979
  )
1980
+ ] }),
1981
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1982
+ /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Role" }),
1983
+ /* @__PURE__ */ jsxs8(
1984
+ "select",
1985
+ {
1986
+ className: "cfi-vi-input",
1987
+ value: editKind,
1988
+ disabled: savingLayout || readOnly,
1989
+ onChange: (e) => setEditKind(e.target.value),
1990
+ children: [
1991
+ /* @__PURE__ */ jsx8("option", { value: "base", children: "base \u2014 the tenant's own volume" }),
1992
+ /* @__PURE__ */ jsx8("option", { value: "overlay", children: "overlay \u2014 customer-stated demand" }),
1993
+ /* @__PURE__ */ jsx8("option", { value: "reference", children: "reference \u2014 another vendor's curve" })
1994
+ ]
1995
+ }
1996
+ )
1972
1997
  ] })
1973
1998
  ] }),
1974
- /* @__PURE__ */ jsx8(Btn, { size: "sm", onClick: () => void saveLayoutAndRouting(), disabled: hasData || savingLayout || readOnly, children: savingLayout ? "Saving\u2026" : "Save layout" })
1999
+ hasData && crossesMeasure && /* @__PURE__ */ jsxs8("p", { className: "cfi-vi-hint", style: { color: "#b45309" }, children: [
2000
+ "This source has data. Changing between ",
2001
+ source.kind,
2002
+ " and ",
2003
+ editKind,
2004
+ " would reinterpret parts as vehicles or the reverse \u2014 clear its data first."
2005
+ ] }),
2006
+ /* @__PURE__ */ jsx8(
2007
+ Btn,
2008
+ {
2009
+ size: "sm",
2010
+ onClick: () => void saveLayoutAndRouting(),
2011
+ disabled: savingLayout || readOnly || hasData && crossesMeasure || hasData && editKind === source.kind,
2012
+ children: savingLayout ? "Saving\u2026" : "Save"
2013
+ }
2014
+ )
1975
2015
  ] }),
1976
2016
  /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-panel", children: [
1977
2017
  /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", children: [
package/package.json CHANGED
@@ -1,43 +1,43 @@
1
- {
2
- "name": "@campfire-interactive/volume-intelligence-ui",
3
- "version": "0.10.0",
4
- "description": "Shared Volume Intelligence UI components (volume import) for the Campfire Suite — embedded by the VI webapp and by consuming apps (OMSF) so there is one import surface, not two that drift.",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- }
13
- },
14
- "files": [
15
- "dist"
16
- ],
17
- "scripts": {
18
- "build": "tsup",
19
- "dev": "tsup --watch"
20
- },
21
- "peerDependencies": {
22
- "react": "^18.0.0 || ^19.0.0",
23
- "react-dom": "^18.0.0 || ^19.0.0"
24
- },
25
- "dependencies": {
26
- "@campfire-interactive/design-tokens": "*",
27
- "lucide-react": "^0.487.0"
28
- },
29
- "devDependencies": {
30
- "@types/react": "^18.2.0",
31
- "react": "^18.2.0",
32
- "react-dom": "^18.2.0",
33
- "tsup": "^8.0.0",
34
- "typescript": "^5.3.3"
35
- },
36
- "publishConfig": {
37
- "registry": "https://registry.npmjs.org",
38
- "access": "public"
39
- },
40
- "engines": {
41
- "node": ">=18.0.0"
42
- }
43
- }
1
+ {
2
+ "name": "@campfire-interactive/volume-intelligence-ui",
3
+ "version": "0.11.1",
4
+ "description": "Shared Volume Intelligence UI components (volume import) for the Campfire Suite — embedded by the VI webapp and by consuming apps (OMSF) so there is one import surface, not two that drift.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch"
20
+ },
21
+ "peerDependencies": {
22
+ "react": "^18.0.0 || ^19.0.0",
23
+ "react-dom": "^18.0.0 || ^19.0.0"
24
+ },
25
+ "dependencies": {
26
+ "@campfire-interactive/design-tokens": "*",
27
+ "lucide-react": "^0.487.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/react": "^18.2.0",
31
+ "react": "^18.2.0",
32
+ "react-dom": "^18.2.0",
33
+ "tsup": "^8.0.0",
34
+ "typescript": "^5.3.3"
35
+ },
36
+ "publishConfig": {
37
+ "registry": "https://registry.npmjs.org",
38
+ "access": "public"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ }
43
+ }