@uniformdev/context-ui 19.92.3 → 19.94.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/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import * as _emotion_react_types_jsx_namespace from '@emotion/react/types/jsx-na
2
2
  import { DimensionMatch, EnrichmentData, VariantMatchCriteria } from '@uniformdev/context';
3
3
  import { InputComboBoxProps, InputComboBoxOption } from '@uniformdev/design-system';
4
4
  export * from '@uniformdev/design-system';
5
- import { DimensionDefinition, ManifestGetResponse } from '@uniformdev/context/api';
5
+ import { DimensionDefinition, ManifestGetResponse, Test } from '@uniformdev/context/api';
6
6
  import React, { ComponentType, ReactElement } from 'react';
7
7
  import * as _emotion_react from '@emotion/react';
8
8
  import * as yup from 'yup';
@@ -136,6 +136,21 @@ type UIVersionProps = {
136
136
  };
137
137
  declare function ProjectUIVersion({ children, versionMap, contextConfig }: UIVersionProps): ReactElement;
138
138
 
139
+ declare const addAbTestLink: _emotion_react.SerializedStyles;
140
+ interface AbTestListProps {
141
+ contextConfig: ContextConfig;
142
+ abTests?: Test[];
143
+ onSelect: (abTest: Test) => void;
144
+ value?: Test;
145
+ }
146
+ interface AbTestSelectorProps {
147
+ value?: Test;
148
+ setValue: (value?: Test) => void;
149
+ contextConfig: ContextConfig;
150
+ loading?: boolean;
151
+ }
152
+ declare const AbTestSelector: ({ value, setValue, contextConfig, loading }: AbTestSelectorProps) => _emotion_react_types_jsx_namespace.EmotionJSX.Element;
153
+
139
154
  interface UseValidateContextConfigResult {
140
155
  validating: boolean;
141
156
  error?: Error;
@@ -153,4 +168,4 @@ declare const validateContextConfig: (contextConfig?: ContextConfig) => Promise<
153
168
  result?: ManifestGetResponse;
154
169
  }>;
155
170
 
156
- export { type ContextConfig, ContextData, type ContextDataProps, CriteriaMatchMenu, type CriteriaMatchMenuProps, CriteriaOperatorMenu, type CriteriaOperatorMenuProps, type DataContextErrorProps, DimensionMenu, type DimensionMenuProps, DimensionValue, type DimensionValueProps, type DimensionsData, EditLink, type EditLinkProps, EnrichmentTag, type EnrichmentTagProps, PersonalizationCriteria, type PersonalizationCriteriaProps, PersonalizationCriteriaStatic, type PersonalizationCriteriaStaticProps, ProjectUIVersion, type ResolvedDimensionDefinition, type UseContextDataResult, type UseDimensionsResult, type UseValidateContextConfigResult, addEnrichmentLink, contextCriteriaMenuOperators, convertErrorsToObj, isEnrichmentTagData, isPersonalizationCriteriaData, opHasRhs, useContextConfig, useContextData, useDimensions, useDimensionsDataContext, useManifest, useValidateContextConfig, validateContextConfig };
171
+ export { type AbTestListProps, AbTestSelector, type AbTestSelectorProps, type ContextConfig, ContextData, type ContextDataProps, CriteriaMatchMenu, type CriteriaMatchMenuProps, CriteriaOperatorMenu, type CriteriaOperatorMenuProps, type DataContextErrorProps, DimensionMenu, type DimensionMenuProps, DimensionValue, type DimensionValueProps, type DimensionsData, EditLink, type EditLinkProps, EnrichmentTag, type EnrichmentTagProps, PersonalizationCriteria, type PersonalizationCriteriaProps, PersonalizationCriteriaStatic, type PersonalizationCriteriaStaticProps, ProjectUIVersion, type ResolvedDimensionDefinition, type UseContextDataResult, type UseDimensionsResult, type UseValidateContextConfigResult, addAbTestLink, addEnrichmentLink, contextCriteriaMenuOperators, convertErrorsToObj, isEnrichmentTagData, isPersonalizationCriteriaData, opHasRhs, useContextConfig, useContextData, useDimensions, useDimensionsDataContext, useManifest, useValidateContextConfig, validateContextConfig };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as _emotion_react_types_jsx_namespace from '@emotion/react/types/jsx-na
2
2
  import { DimensionMatch, EnrichmentData, VariantMatchCriteria } from '@uniformdev/context';
3
3
  import { InputComboBoxProps, InputComboBoxOption } from '@uniformdev/design-system';
4
4
  export * from '@uniformdev/design-system';
5
- import { DimensionDefinition, ManifestGetResponse } from '@uniformdev/context/api';
5
+ import { DimensionDefinition, ManifestGetResponse, Test } from '@uniformdev/context/api';
6
6
  import React, { ComponentType, ReactElement } from 'react';
7
7
  import * as _emotion_react from '@emotion/react';
8
8
  import * as yup from 'yup';
@@ -136,6 +136,21 @@ type UIVersionProps = {
136
136
  };
137
137
  declare function ProjectUIVersion({ children, versionMap, contextConfig }: UIVersionProps): ReactElement;
138
138
 
139
+ declare const addAbTestLink: _emotion_react.SerializedStyles;
140
+ interface AbTestListProps {
141
+ contextConfig: ContextConfig;
142
+ abTests?: Test[];
143
+ onSelect: (abTest: Test) => void;
144
+ value?: Test;
145
+ }
146
+ interface AbTestSelectorProps {
147
+ value?: Test;
148
+ setValue: (value?: Test) => void;
149
+ contextConfig: ContextConfig;
150
+ loading?: boolean;
151
+ }
152
+ declare const AbTestSelector: ({ value, setValue, contextConfig, loading }: AbTestSelectorProps) => _emotion_react_types_jsx_namespace.EmotionJSX.Element;
153
+
139
154
  interface UseValidateContextConfigResult {
140
155
  validating: boolean;
141
156
  error?: Error;
@@ -153,4 +168,4 @@ declare const validateContextConfig: (contextConfig?: ContextConfig) => Promise<
153
168
  result?: ManifestGetResponse;
154
169
  }>;
155
170
 
156
- export { type ContextConfig, ContextData, type ContextDataProps, CriteriaMatchMenu, type CriteriaMatchMenuProps, CriteriaOperatorMenu, type CriteriaOperatorMenuProps, type DataContextErrorProps, DimensionMenu, type DimensionMenuProps, DimensionValue, type DimensionValueProps, type DimensionsData, EditLink, type EditLinkProps, EnrichmentTag, type EnrichmentTagProps, PersonalizationCriteria, type PersonalizationCriteriaProps, PersonalizationCriteriaStatic, type PersonalizationCriteriaStaticProps, ProjectUIVersion, type ResolvedDimensionDefinition, type UseContextDataResult, type UseDimensionsResult, type UseValidateContextConfigResult, addEnrichmentLink, contextCriteriaMenuOperators, convertErrorsToObj, isEnrichmentTagData, isPersonalizationCriteriaData, opHasRhs, useContextConfig, useContextData, useDimensions, useDimensionsDataContext, useManifest, useValidateContextConfig, validateContextConfig };
171
+ export { type AbTestListProps, AbTestSelector, type AbTestSelectorProps, type ContextConfig, ContextData, type ContextDataProps, CriteriaMatchMenu, type CriteriaMatchMenuProps, CriteriaOperatorMenu, type CriteriaOperatorMenuProps, type DataContextErrorProps, DimensionMenu, type DimensionMenuProps, DimensionValue, type DimensionValueProps, type DimensionsData, EditLink, type EditLinkProps, EnrichmentTag, type EnrichmentTagProps, PersonalizationCriteria, type PersonalizationCriteriaProps, PersonalizationCriteriaStatic, type PersonalizationCriteriaStaticProps, ProjectUIVersion, type ResolvedDimensionDefinition, type UseContextDataResult, type UseDimensionsResult, type UseValidateContextConfigResult, addAbTestLink, addEnrichmentLink, contextCriteriaMenuOperators, convertErrorsToObj, isEnrichmentTagData, isPersonalizationCriteriaData, opHasRhs, useContextConfig, useContextData, useDimensions, useDimensionsDataContext, useManifest, useValidateContextConfig, validateContextConfig };
package/dist/index.esm.js CHANGED
@@ -1488,8 +1488,178 @@ function ProjectUIVersion({ children, versionMap, contextConfig }) {
1488
1488
  return /* @__PURE__ */ jsx18(Fragment5, { children });
1489
1489
  }
1490
1490
 
1491
- // src/hooks/useValidateContextConfig.ts
1491
+ // src/components/AbTestSelector/AbTestSelector.tsx
1492
+ import { css as css7 } from "@emotion/react";
1493
+ import {
1494
+ AddListButton as AddListButton3,
1495
+ Button as Button2,
1496
+ Callout as Callout4,
1497
+ Heading,
1498
+ Link,
1499
+ LoadingIndicator as LoadingIndicator5,
1500
+ ScrollableList,
1501
+ ScrollableListItem
1502
+ } from "@uniformdev/design-system";
1503
+ import { useState as useState7 } from "react";
1504
+
1505
+ // src/hooks/useABTests.ts
1506
+ import { ApiClientError as ApiClientError3, CachedTestClient } from "@uniformdev/context/api";
1492
1507
  import { useEffect as useEffect3, useState as useState6 } from "react";
1508
+ function useABTests({ apiHost, apiKey, projectId }) {
1509
+ const [reload, setReload] = useState6(true);
1510
+ const [state, setState] = useState6({
1511
+ loading: false,
1512
+ notConfigured: false,
1513
+ error: null,
1514
+ result: null
1515
+ });
1516
+ useEffect3(() => {
1517
+ if (!projectId || !apiKey || !apiHost) {
1518
+ setState({ notConfigured: true, loading: false, error: null, result: null });
1519
+ return;
1520
+ }
1521
+ const runEffect = async () => {
1522
+ setState({ notConfigured: false, loading: true, error: null, result: null });
1523
+ try {
1524
+ const client = new CachedTestClient({
1525
+ projectId,
1526
+ apiKey,
1527
+ apiHost
1528
+ });
1529
+ const { tests } = await client.get();
1530
+ setState({ notConfigured: false, loading: false, error: null, result: tests });
1531
+ } catch (e) {
1532
+ let message;
1533
+ if (e instanceof ApiClientError3) {
1534
+ message = e.message;
1535
+ } else {
1536
+ message = e.toString();
1537
+ }
1538
+ setState({ notConfigured: false, loading: false, error: message, result: null });
1539
+ return;
1540
+ }
1541
+ };
1542
+ if (reload) {
1543
+ runEffect().then(() => {
1544
+ setReload(false);
1545
+ });
1546
+ }
1547
+ }, [apiHost, apiKey, projectId, reload]);
1548
+ return {
1549
+ result: state.result,
1550
+ error: state.error,
1551
+ loading: state.loading,
1552
+ notConfigured: state.notConfigured,
1553
+ doReload: () => setReload(true)
1554
+ };
1555
+ }
1556
+
1557
+ // src/components/AbTestSelector/AbTestSelector.tsx
1558
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
1559
+ var addAbTestLink = css7`
1560
+ flex: 2;
1561
+ display: flex;
1562
+ width: 50%;
1563
+ align-items: center;
1564
+ font-weight: var(--fw-bold);
1565
+ color: var(--brand-primary-1);
1566
+ &:hover,
1567
+ &:focus {
1568
+ text-decoration-line: underline;
1569
+ }
1570
+ `;
1571
+ var AbTestList = ({ contextConfig, onSelect, value }) => {
1572
+ const { loading, result, doReload = () => {
1573
+ } } = useABTests(contextConfig);
1574
+ if (loading) {
1575
+ return /* @__PURE__ */ jsx19(LoadingIndicator5, {});
1576
+ }
1577
+ return /* @__PURE__ */ jsxs10(Fragment6, { children: [
1578
+ /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(Link, { text: "Refresh A/B Test list", style: { marginRight: "10px" }, onClick: () => doReload() }) }),
1579
+ !result || result.length === 0 ? /* @__PURE__ */ jsx19(NoAbTestsView, { contextConfig }) : /* @__PURE__ */ jsxs10("div", { style: { marginTop: "10px" }, children: [
1580
+ /* @__PURE__ */ jsx19(ScrollableList, { children: result.map((abTest) => {
1581
+ const { id, name } = abTest;
1582
+ return /* @__PURE__ */ jsx19(
1583
+ ScrollableListItem,
1584
+ {
1585
+ buttonText: name,
1586
+ active: id === (value == null ? void 0 : value.id),
1587
+ onClick: () => onSelect(abTest)
1588
+ },
1589
+ id
1590
+ );
1591
+ }) }),
1592
+ /* @__PURE__ */ jsx19(
1593
+ AddListButton3,
1594
+ {
1595
+ className: "add-more",
1596
+ onButtonClick: () => {
1597
+ window.open(
1598
+ `${contextConfig.apiHost}/projects/${encodeURIComponent(contextConfig.projectId)}/testing`,
1599
+ "_blank"
1600
+ );
1601
+ },
1602
+ buttonText: "Add new A/B Test"
1603
+ }
1604
+ )
1605
+ ] })
1606
+ ] });
1607
+ };
1608
+ var AbTestSelector = ({ value, setValue, contextConfig, loading }) => {
1609
+ var _a;
1610
+ const [showAbTests, setShowAbTests] = useState7(false);
1611
+ if (loading) {
1612
+ return /* @__PURE__ */ jsx19(LoadingIndicator5, {});
1613
+ }
1614
+ return /* @__PURE__ */ jsx19("fieldset", { className: "ab-test", children: /* @__PURE__ */ jsxs10("div", { children: [
1615
+ !showAbTests && /* @__PURE__ */ jsxs10("div", { children: [
1616
+ value && Object.keys(value).length > 0 && /* @__PURE__ */ jsx19(Heading, { level: 4, style: { marginBottom: "10px" }, children: (_a = value == null ? void 0 : value.name) != null ? _a : "Unknown test" }),
1617
+ /* @__PURE__ */ jsx19(Button2, { buttonType: "primary", style: { marginRight: "10px" }, onClick: () => setShowAbTests(true), children: "Select A/B Test" })
1618
+ ] }),
1619
+ showAbTests && /* @__PURE__ */ jsx19(
1620
+ AbTestList,
1621
+ {
1622
+ contextConfig,
1623
+ onSelect: (abTest) => {
1624
+ if ((value == null ? void 0 : value.id) === abTest.id) {
1625
+ setValue(void 0);
1626
+ setShowAbTests(true);
1627
+ return;
1628
+ }
1629
+ setValue(abTest);
1630
+ setShowAbTests(false);
1631
+ },
1632
+ value
1633
+ }
1634
+ )
1635
+ ] }) });
1636
+ };
1637
+ var NoAbTestsView = ({ contextConfig }) => /* @__PURE__ */ jsx19(
1638
+ Callout4,
1639
+ {
1640
+ title: "No A/B tests found in your Uniform project.",
1641
+ type: "caution",
1642
+ css: { marginBlock: "var(--spacing-base)" },
1643
+ children: /* @__PURE__ */ jsxs10("p", { children: [
1644
+ "Looks like you do not have any A/B tests created in your connected Uniform project. Start by creating your first test",
1645
+ " ",
1646
+ /* @__PURE__ */ jsx19(
1647
+ "a",
1648
+ {
1649
+ href: `${contextConfig.apiHost}/projects/${encodeURIComponent(contextConfig.projectId)}/testing`,
1650
+ target: "_blank",
1651
+ rel: "noopener noreferrer",
1652
+ css: { ":hover": { textDecorationLine: "underline" } },
1653
+ children: "here"
1654
+ }
1655
+ ),
1656
+ "."
1657
+ ] })
1658
+ }
1659
+ );
1660
+
1661
+ // src/hooks/useValidateContextConfig.ts
1662
+ import { useEffect as useEffect4, useState as useState8 } from "react";
1493
1663
 
1494
1664
  // src/utils/validateContextConfig.ts
1495
1665
  import { UncachedManifestClient } from "@uniformdev/context/api";
@@ -1525,12 +1695,12 @@ var validateContextConfig = async (contextConfig) => {
1525
1695
 
1526
1696
  // src/hooks/useValidateContextConfig.ts
1527
1697
  var useValidateContextConfig = (contextConfig) => {
1528
- const [state, setState] = useState6({
1698
+ const [state, setState] = useState8({
1529
1699
  validating: false,
1530
1700
  error: void 0
1531
1701
  });
1532
1702
  const { apiKey, apiHost, projectId } = contextConfig || {};
1533
- useEffect3(() => {
1703
+ useEffect4(() => {
1534
1704
  if (!apiKey || !apiHost) {
1535
1705
  return;
1536
1706
  }
@@ -1555,6 +1725,7 @@ var useValidateContextConfig = (contextConfig) => {
1555
1725
  // src/index.ts
1556
1726
  export * from "@uniformdev/design-system";
1557
1727
  export {
1728
+ AbTestSelector,
1558
1729
  ContextData,
1559
1730
  CriteriaMatchMenu,
1560
1731
  CriteriaOperatorMenu,
@@ -1565,6 +1736,7 @@ export {
1565
1736
  PersonalizationCriteria,
1566
1737
  PersonalizationCriteriaStatic,
1567
1738
  ProjectUIVersion,
1739
+ addAbTestLink,
1568
1740
  addEnrichmentLink,
1569
1741
  contextCriteriaMenuOperators,
1570
1742
  convertErrorsToObj,
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var src_exports = {};
33
33
  __export(src_exports, {
34
+ AbTestSelector: () => AbTestSelector,
34
35
  ContextData: () => ContextData,
35
36
  CriteriaMatchMenu: () => CriteriaMatchMenu,
36
37
  CriteriaOperatorMenu: () => CriteriaOperatorMenu,
@@ -41,6 +42,7 @@ __export(src_exports, {
41
42
  PersonalizationCriteria: () => PersonalizationCriteria,
42
43
  PersonalizationCriteriaStatic: () => PersonalizationCriteriaStatic,
43
44
  ProjectUIVersion: () => ProjectUIVersion,
45
+ addAbTestLink: () => addAbTestLink,
44
46
  addEnrichmentLink: () => addEnrichmentLink,
45
47
  contextCriteriaMenuOperators: () => contextCriteriaMenuOperators,
46
48
  convertErrorsToObj: () => convertErrorsToObj,
@@ -1539,11 +1541,172 @@ function ProjectUIVersion({ children, versionMap, contextConfig }) {
1539
1541
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children });
1540
1542
  }
1541
1543
 
1542
- // src/hooks/useValidateContextConfig.ts
1544
+ // src/components/AbTestSelector/AbTestSelector.tsx
1545
+ var import_react15 = require("@emotion/react");
1546
+ var import_design_system12 = require("@uniformdev/design-system");
1547
+ var import_react16 = require("react");
1548
+
1549
+ // src/hooks/useABTests.ts
1550
+ var import_api3 = require("@uniformdev/context/api");
1543
1551
  var import_react14 = require("react");
1552
+ function useABTests({ apiHost, apiKey, projectId }) {
1553
+ const [reload, setReload] = (0, import_react14.useState)(true);
1554
+ const [state, setState] = (0, import_react14.useState)({
1555
+ loading: false,
1556
+ notConfigured: false,
1557
+ error: null,
1558
+ result: null
1559
+ });
1560
+ (0, import_react14.useEffect)(() => {
1561
+ if (!projectId || !apiKey || !apiHost) {
1562
+ setState({ notConfigured: true, loading: false, error: null, result: null });
1563
+ return;
1564
+ }
1565
+ const runEffect = async () => {
1566
+ setState({ notConfigured: false, loading: true, error: null, result: null });
1567
+ try {
1568
+ const client = new import_api3.CachedTestClient({
1569
+ projectId,
1570
+ apiKey,
1571
+ apiHost
1572
+ });
1573
+ const { tests } = await client.get();
1574
+ setState({ notConfigured: false, loading: false, error: null, result: tests });
1575
+ } catch (e) {
1576
+ let message;
1577
+ if (e instanceof import_api3.ApiClientError) {
1578
+ message = e.message;
1579
+ } else {
1580
+ message = e.toString();
1581
+ }
1582
+ setState({ notConfigured: false, loading: false, error: message, result: null });
1583
+ return;
1584
+ }
1585
+ };
1586
+ if (reload) {
1587
+ runEffect().then(() => {
1588
+ setReload(false);
1589
+ });
1590
+ }
1591
+ }, [apiHost, apiKey, projectId, reload]);
1592
+ return {
1593
+ result: state.result,
1594
+ error: state.error,
1595
+ loading: state.loading,
1596
+ notConfigured: state.notConfigured,
1597
+ doReload: () => setReload(true)
1598
+ };
1599
+ }
1600
+
1601
+ // src/components/AbTestSelector/AbTestSelector.tsx
1602
+ var import_jsx_runtime18 = require("@emotion/react/jsx-runtime");
1603
+ var addAbTestLink = import_react15.css`
1604
+ flex: 2;
1605
+ display: flex;
1606
+ width: 50%;
1607
+ align-items: center;
1608
+ font-weight: var(--fw-bold);
1609
+ color: var(--brand-primary-1);
1610
+ &:hover,
1611
+ &:focus {
1612
+ text-decoration-line: underline;
1613
+ }
1614
+ `;
1615
+ var AbTestList = ({ contextConfig, onSelect, value }) => {
1616
+ const { loading, result, doReload = () => {
1617
+ } } = useABTests(contextConfig);
1618
+ if (loading) {
1619
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system12.LoadingIndicator, {});
1620
+ }
1621
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1622
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system12.Link, { text: "Refresh A/B Test list", style: { marginRight: "10px" }, onClick: () => doReload() }) }),
1623
+ !result || result.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NoAbTestsView, { contextConfig }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginTop: "10px" }, children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system12.ScrollableList, { children: result.map((abTest) => {
1625
+ const { id, name } = abTest;
1626
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1627
+ import_design_system12.ScrollableListItem,
1628
+ {
1629
+ buttonText: name,
1630
+ active: id === (value == null ? void 0 : value.id),
1631
+ onClick: () => onSelect(abTest)
1632
+ },
1633
+ id
1634
+ );
1635
+ }) }),
1636
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1637
+ import_design_system12.AddListButton,
1638
+ {
1639
+ className: "add-more",
1640
+ onButtonClick: () => {
1641
+ window.open(
1642
+ `${contextConfig.apiHost}/projects/${encodeURIComponent(contextConfig.projectId)}/testing`,
1643
+ "_blank"
1644
+ );
1645
+ },
1646
+ buttonText: "Add new A/B Test"
1647
+ }
1648
+ )
1649
+ ] })
1650
+ ] });
1651
+ };
1652
+ var AbTestSelector = ({ value, setValue, contextConfig, loading }) => {
1653
+ var _a;
1654
+ const [showAbTests, setShowAbTests] = (0, import_react16.useState)(false);
1655
+ if (loading) {
1656
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system12.LoadingIndicator, {});
1657
+ }
1658
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("fieldset", { className: "ab-test", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
1659
+ !showAbTests && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
1660
+ value && Object.keys(value).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system12.Heading, { level: 4, style: { marginBottom: "10px" }, children: (_a = value == null ? void 0 : value.name) != null ? _a : "Unknown test" }),
1661
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system12.Button, { buttonType: "primary", style: { marginRight: "10px" }, onClick: () => setShowAbTests(true), children: "Select A/B Test" })
1662
+ ] }),
1663
+ showAbTests && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1664
+ AbTestList,
1665
+ {
1666
+ contextConfig,
1667
+ onSelect: (abTest) => {
1668
+ if ((value == null ? void 0 : value.id) === abTest.id) {
1669
+ setValue(void 0);
1670
+ setShowAbTests(true);
1671
+ return;
1672
+ }
1673
+ setValue(abTest);
1674
+ setShowAbTests(false);
1675
+ },
1676
+ value
1677
+ }
1678
+ )
1679
+ ] }) });
1680
+ };
1681
+ var NoAbTestsView = ({ contextConfig }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1682
+ import_design_system12.Callout,
1683
+ {
1684
+ title: "No A/B tests found in your Uniform project.",
1685
+ type: "caution",
1686
+ css: { marginBlock: "var(--spacing-base)" },
1687
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { children: [
1688
+ "Looks like you do not have any A/B tests created in your connected Uniform project. Start by creating your first test",
1689
+ " ",
1690
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1691
+ "a",
1692
+ {
1693
+ href: `${contextConfig.apiHost}/projects/${encodeURIComponent(contextConfig.projectId)}/testing`,
1694
+ target: "_blank",
1695
+ rel: "noopener noreferrer",
1696
+ css: { ":hover": { textDecorationLine: "underline" } },
1697
+ children: "here"
1698
+ }
1699
+ ),
1700
+ "."
1701
+ ] })
1702
+ }
1703
+ );
1704
+
1705
+ // src/hooks/useValidateContextConfig.ts
1706
+ var import_react17 = require("react");
1544
1707
 
1545
1708
  // src/utils/validateContextConfig.ts
1546
- var import_api3 = require("@uniformdev/context/api");
1709
+ var import_api4 = require("@uniformdev/context/api");
1547
1710
  var import_uuid = require("uuid");
1548
1711
  var validateContextConfig = async (contextConfig) => {
1549
1712
  if (!contextConfig) {
@@ -1558,7 +1721,7 @@ var validateContextConfig = async (contextConfig) => {
1558
1721
  if (!(0, import_uuid.validate)(contextConfig.apiKey) && !contextConfig.projectId) {
1559
1722
  return { valid: false, error: new Error("projectId is required when using a modern API key.") };
1560
1723
  }
1561
- const client = new import_api3.UncachedManifestClient({
1724
+ const client = new import_api4.UncachedManifestClient({
1562
1725
  projectId: contextConfig.projectId,
1563
1726
  apiKey: contextConfig.apiKey,
1564
1727
  apiHost: contextConfig.apiHost
@@ -1576,12 +1739,12 @@ var validateContextConfig = async (contextConfig) => {
1576
1739
 
1577
1740
  // src/hooks/useValidateContextConfig.ts
1578
1741
  var useValidateContextConfig = (contextConfig) => {
1579
- const [state, setState] = (0, import_react14.useState)({
1742
+ const [state, setState] = (0, import_react17.useState)({
1580
1743
  validating: false,
1581
1744
  error: void 0
1582
1745
  });
1583
1746
  const { apiKey, apiHost, projectId } = contextConfig || {};
1584
- (0, import_react14.useEffect)(() => {
1747
+ (0, import_react17.useEffect)(() => {
1585
1748
  if (!apiKey || !apiHost) {
1586
1749
  return;
1587
1750
  }
@@ -1607,6 +1770,7 @@ var useValidateContextConfig = (contextConfig) => {
1607
1770
  __reExport(src_exports, require("@uniformdev/design-system"), module.exports);
1608
1771
  // Annotate the CommonJS export names for ESM import in node:
1609
1772
  0 && (module.exports = {
1773
+ AbTestSelector,
1610
1774
  ContextData,
1611
1775
  CriteriaMatchMenu,
1612
1776
  CriteriaOperatorMenu,
@@ -1617,6 +1781,7 @@ __reExport(src_exports, require("@uniformdev/design-system"), module.exports);
1617
1781
  PersonalizationCriteria,
1618
1782
  PersonalizationCriteriaStatic,
1619
1783
  ProjectUIVersion,
1784
+ addAbTestLink,
1620
1785
  addEnrichmentLink,
1621
1786
  contextCriteriaMenuOperators,
1622
1787
  convertErrorsToObj,
package/dist/index.mjs CHANGED
@@ -1488,8 +1488,178 @@ function ProjectUIVersion({ children, versionMap, contextConfig }) {
1488
1488
  return /* @__PURE__ */ jsx18(Fragment5, { children });
1489
1489
  }
1490
1490
 
1491
- // src/hooks/useValidateContextConfig.ts
1491
+ // src/components/AbTestSelector/AbTestSelector.tsx
1492
+ import { css as css7 } from "@emotion/react";
1493
+ import {
1494
+ AddListButton as AddListButton3,
1495
+ Button as Button2,
1496
+ Callout as Callout4,
1497
+ Heading,
1498
+ Link,
1499
+ LoadingIndicator as LoadingIndicator5,
1500
+ ScrollableList,
1501
+ ScrollableListItem
1502
+ } from "@uniformdev/design-system";
1503
+ import { useState as useState7 } from "react";
1504
+
1505
+ // src/hooks/useABTests.ts
1506
+ import { ApiClientError as ApiClientError3, CachedTestClient } from "@uniformdev/context/api";
1492
1507
  import { useEffect as useEffect3, useState as useState6 } from "react";
1508
+ function useABTests({ apiHost, apiKey, projectId }) {
1509
+ const [reload, setReload] = useState6(true);
1510
+ const [state, setState] = useState6({
1511
+ loading: false,
1512
+ notConfigured: false,
1513
+ error: null,
1514
+ result: null
1515
+ });
1516
+ useEffect3(() => {
1517
+ if (!projectId || !apiKey || !apiHost) {
1518
+ setState({ notConfigured: true, loading: false, error: null, result: null });
1519
+ return;
1520
+ }
1521
+ const runEffect = async () => {
1522
+ setState({ notConfigured: false, loading: true, error: null, result: null });
1523
+ try {
1524
+ const client = new CachedTestClient({
1525
+ projectId,
1526
+ apiKey,
1527
+ apiHost
1528
+ });
1529
+ const { tests } = await client.get();
1530
+ setState({ notConfigured: false, loading: false, error: null, result: tests });
1531
+ } catch (e) {
1532
+ let message;
1533
+ if (e instanceof ApiClientError3) {
1534
+ message = e.message;
1535
+ } else {
1536
+ message = e.toString();
1537
+ }
1538
+ setState({ notConfigured: false, loading: false, error: message, result: null });
1539
+ return;
1540
+ }
1541
+ };
1542
+ if (reload) {
1543
+ runEffect().then(() => {
1544
+ setReload(false);
1545
+ });
1546
+ }
1547
+ }, [apiHost, apiKey, projectId, reload]);
1548
+ return {
1549
+ result: state.result,
1550
+ error: state.error,
1551
+ loading: state.loading,
1552
+ notConfigured: state.notConfigured,
1553
+ doReload: () => setReload(true)
1554
+ };
1555
+ }
1556
+
1557
+ // src/components/AbTestSelector/AbTestSelector.tsx
1558
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
1559
+ var addAbTestLink = css7`
1560
+ flex: 2;
1561
+ display: flex;
1562
+ width: 50%;
1563
+ align-items: center;
1564
+ font-weight: var(--fw-bold);
1565
+ color: var(--brand-primary-1);
1566
+ &:hover,
1567
+ &:focus {
1568
+ text-decoration-line: underline;
1569
+ }
1570
+ `;
1571
+ var AbTestList = ({ contextConfig, onSelect, value }) => {
1572
+ const { loading, result, doReload = () => {
1573
+ } } = useABTests(contextConfig);
1574
+ if (loading) {
1575
+ return /* @__PURE__ */ jsx19(LoadingIndicator5, {});
1576
+ }
1577
+ return /* @__PURE__ */ jsxs10(Fragment6, { children: [
1578
+ /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(Link, { text: "Refresh A/B Test list", style: { marginRight: "10px" }, onClick: () => doReload() }) }),
1579
+ !result || result.length === 0 ? /* @__PURE__ */ jsx19(NoAbTestsView, { contextConfig }) : /* @__PURE__ */ jsxs10("div", { style: { marginTop: "10px" }, children: [
1580
+ /* @__PURE__ */ jsx19(ScrollableList, { children: result.map((abTest) => {
1581
+ const { id, name } = abTest;
1582
+ return /* @__PURE__ */ jsx19(
1583
+ ScrollableListItem,
1584
+ {
1585
+ buttonText: name,
1586
+ active: id === (value == null ? void 0 : value.id),
1587
+ onClick: () => onSelect(abTest)
1588
+ },
1589
+ id
1590
+ );
1591
+ }) }),
1592
+ /* @__PURE__ */ jsx19(
1593
+ AddListButton3,
1594
+ {
1595
+ className: "add-more",
1596
+ onButtonClick: () => {
1597
+ window.open(
1598
+ `${contextConfig.apiHost}/projects/${encodeURIComponent(contextConfig.projectId)}/testing`,
1599
+ "_blank"
1600
+ );
1601
+ },
1602
+ buttonText: "Add new A/B Test"
1603
+ }
1604
+ )
1605
+ ] })
1606
+ ] });
1607
+ };
1608
+ var AbTestSelector = ({ value, setValue, contextConfig, loading }) => {
1609
+ var _a;
1610
+ const [showAbTests, setShowAbTests] = useState7(false);
1611
+ if (loading) {
1612
+ return /* @__PURE__ */ jsx19(LoadingIndicator5, {});
1613
+ }
1614
+ return /* @__PURE__ */ jsx19("fieldset", { className: "ab-test", children: /* @__PURE__ */ jsxs10("div", { children: [
1615
+ !showAbTests && /* @__PURE__ */ jsxs10("div", { children: [
1616
+ value && Object.keys(value).length > 0 && /* @__PURE__ */ jsx19(Heading, { level: 4, style: { marginBottom: "10px" }, children: (_a = value == null ? void 0 : value.name) != null ? _a : "Unknown test" }),
1617
+ /* @__PURE__ */ jsx19(Button2, { buttonType: "primary", style: { marginRight: "10px" }, onClick: () => setShowAbTests(true), children: "Select A/B Test" })
1618
+ ] }),
1619
+ showAbTests && /* @__PURE__ */ jsx19(
1620
+ AbTestList,
1621
+ {
1622
+ contextConfig,
1623
+ onSelect: (abTest) => {
1624
+ if ((value == null ? void 0 : value.id) === abTest.id) {
1625
+ setValue(void 0);
1626
+ setShowAbTests(true);
1627
+ return;
1628
+ }
1629
+ setValue(abTest);
1630
+ setShowAbTests(false);
1631
+ },
1632
+ value
1633
+ }
1634
+ )
1635
+ ] }) });
1636
+ };
1637
+ var NoAbTestsView = ({ contextConfig }) => /* @__PURE__ */ jsx19(
1638
+ Callout4,
1639
+ {
1640
+ title: "No A/B tests found in your Uniform project.",
1641
+ type: "caution",
1642
+ css: { marginBlock: "var(--spacing-base)" },
1643
+ children: /* @__PURE__ */ jsxs10("p", { children: [
1644
+ "Looks like you do not have any A/B tests created in your connected Uniform project. Start by creating your first test",
1645
+ " ",
1646
+ /* @__PURE__ */ jsx19(
1647
+ "a",
1648
+ {
1649
+ href: `${contextConfig.apiHost}/projects/${encodeURIComponent(contextConfig.projectId)}/testing`,
1650
+ target: "_blank",
1651
+ rel: "noopener noreferrer",
1652
+ css: { ":hover": { textDecorationLine: "underline" } },
1653
+ children: "here"
1654
+ }
1655
+ ),
1656
+ "."
1657
+ ] })
1658
+ }
1659
+ );
1660
+
1661
+ // src/hooks/useValidateContextConfig.ts
1662
+ import { useEffect as useEffect4, useState as useState8 } from "react";
1493
1663
 
1494
1664
  // src/utils/validateContextConfig.ts
1495
1665
  import { UncachedManifestClient } from "@uniformdev/context/api";
@@ -1525,12 +1695,12 @@ var validateContextConfig = async (contextConfig) => {
1525
1695
 
1526
1696
  // src/hooks/useValidateContextConfig.ts
1527
1697
  var useValidateContextConfig = (contextConfig) => {
1528
- const [state, setState] = useState6({
1698
+ const [state, setState] = useState8({
1529
1699
  validating: false,
1530
1700
  error: void 0
1531
1701
  });
1532
1702
  const { apiKey, apiHost, projectId } = contextConfig || {};
1533
- useEffect3(() => {
1703
+ useEffect4(() => {
1534
1704
  if (!apiKey || !apiHost) {
1535
1705
  return;
1536
1706
  }
@@ -1555,6 +1725,7 @@ var useValidateContextConfig = (contextConfig) => {
1555
1725
  // src/index.ts
1556
1726
  export * from "@uniformdev/design-system";
1557
1727
  export {
1728
+ AbTestSelector,
1558
1729
  ContextData,
1559
1730
  CriteriaMatchMenu,
1560
1731
  CriteriaOperatorMenu,
@@ -1565,6 +1736,7 @@ export {
1565
1736
  PersonalizationCriteria,
1566
1737
  PersonalizationCriteriaStatic,
1567
1738
  ProjectUIVersion,
1739
+ addAbTestLink,
1568
1740
  addEnrichmentLink,
1569
1741
  contextCriteriaMenuOperators,
1570
1742
  convertErrorsToObj,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/context-ui",
3
- "version": "19.92.3",
3
+ "version": "19.94.0",
4
4
  "description": "React-based functionality and components for Uniform Context",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "main": "./dist/index.js",
@@ -34,8 +34,8 @@
34
34
  "dependencies": {
35
35
  "@emotion/react": "11.11.3",
36
36
  "@react-icons/all-files": "https://github.com/react-icons/react-icons/releases/download/v4.10.1/react-icons-all-files-4.10.1.tgz",
37
- "@uniformdev/context": "19.92.3",
38
- "@uniformdev/design-system": "19.92.3",
37
+ "@uniformdev/context": "19.94.0",
38
+ "@uniformdev/design-system": "19.94.0",
39
39
  "immer": "10.0.3",
40
40
  "react-beautiful-dnd": "13.1.1",
41
41
  "react-select": "5.7.7",
@@ -73,5 +73,5 @@
73
73
  "publishConfig": {
74
74
  "access": "public"
75
75
  },
76
- "gitHead": "7eeadbc2ffc4a2808ddbe8ef9258ae46504cec91"
76
+ "gitHead": "83b33647cd09dafcd4ea23012c4e87a45b71c0af"
77
77
  }