@flagsmith/backstage-plugin 0.1.0-pr.7.3135fb9 → 0.1.0-pr.7.ffc27ed
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/api/FlagsmithClient.esm.js +2 -28
- package/dist/api/FlagsmithClient.esm.js.map +1 -1
- package/dist/components/FlagsTab/EnvironmentTable.esm.js +45 -83
- package/dist/components/FlagsTab/EnvironmentTable.esm.js.map +1 -1
- package/dist/components/FlagsTab/ExpandableRow.esm.js +101 -188
- package/dist/components/FlagsTab/ExpandableRow.esm.js.map +1 -1
- package/dist/components/FlagsTab/FeatureDetailsGrid.esm.js +35 -111
- package/dist/components/FlagsTab/FeatureDetailsGrid.esm.js.map +1 -1
- package/dist/components/FlagsTab/SegmentOverridesSection.esm.js +0 -1
- package/dist/components/FlagsTab/SegmentOverridesSection.esm.js.map +1 -1
- package/dist/components/FlagsTab/index.esm.js +16 -48
- package/dist/components/FlagsTab/index.esm.js.map +1 -1
- package/dist/components/FlagsmithOverviewCard/FeatureFlagRow.esm.js +0 -1
- package/dist/components/FlagsmithOverviewCard/FeatureFlagRow.esm.js.map +1 -1
- package/dist/components/FlagsmithOverviewCard/FlagStatsRow.esm.js +0 -1
- package/dist/components/FlagsmithOverviewCard/FlagStatsRow.esm.js.map +1 -1
- package/dist/components/FlagsmithOverviewCard/index.esm.js +5 -4
- package/dist/components/FlagsmithOverviewCard/index.esm.js.map +1 -1
- package/dist/components/FlagsmithUsageCard/UsageChart.esm.js +3 -40
- package/dist/components/FlagsmithUsageCard/UsageChart.esm.js.map +1 -1
- package/dist/components/FlagsmithUsageCard/UsageTooltip.esm.js +52 -0
- package/dist/components/FlagsmithUsageCard/UsageTooltip.esm.js.map +1 -0
- package/dist/components/FlagsmithUsageCard/index.esm.js +13 -11
- package/dist/components/FlagsmithUsageCard/index.esm.js.map +1 -1
- package/dist/components/shared/FlagsmithLink.esm.js +4 -12
- package/dist/components/shared/FlagsmithLink.esm.js.map +1 -1
- package/dist/hooks/useFlagsmithProject.esm.js +1 -7
- package/dist/hooks/useFlagsmithProject.esm.js.map +1 -1
- package/dist/hooks/useFlagsmithUsage.esm.js +3 -6
- package/dist/hooks/useFlagsmithUsage.esm.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/components/FlagsTab/FeatureAnalyticsSection.esm.js +0 -178
- package/dist/components/FlagsTab/FeatureAnalyticsSection.esm.js.map +0 -1
- package/dist/components/shared/ChartTooltip.esm.js +0 -33
- package/dist/components/shared/ChartTooltip.esm.js.map +0 -1
- package/dist/components/shared/ErrorState.esm.js +0 -13
- package/dist/components/shared/ErrorState.esm.js.map +0 -1
- package/dist/constants/index.esm.js +0 -38
- package/dist/constants/index.esm.js.map +0 -1
- package/dist/theme/sharedStyles.esm.js +0 -19
- package/dist/theme/sharedStyles.esm.js.map +0 -1
- package/dist/utils/dateFormatters.esm.js +0 -15
- package/dist/utils/dateFormatters.esm.js.map +0 -1
- package/dist/utils/flagTypeHelpers.esm.js +0 -42
- package/dist/utils/flagTypeHelpers.esm.js.map +0 -1
|
@@ -4,7 +4,7 @@ import { makeStyles } from '@material-ui/core/styles';
|
|
|
4
4
|
import LaunchIcon from '@material-ui/icons/Launch';
|
|
5
5
|
import { flagsmithColors } from '../../theme/flagsmithTheme.esm.js';
|
|
6
6
|
|
|
7
|
-
const useStyles = makeStyles((
|
|
7
|
+
const useStyles = makeStyles(() => ({
|
|
8
8
|
link: {
|
|
9
9
|
display: "inline-flex",
|
|
10
10
|
alignItems: "center",
|
|
@@ -23,23 +23,17 @@ const useStyles = makeStyles((theme) => ({
|
|
|
23
23
|
iconButton: {
|
|
24
24
|
padding: 4,
|
|
25
25
|
color: flagsmithColors.primary
|
|
26
|
-
},
|
|
27
|
-
tooltip: {
|
|
28
|
-
backgroundColor: theme.palette.grey[700],
|
|
29
|
-
color: theme.palette.common.white,
|
|
30
|
-
fontSize: "0.75rem"
|
|
31
26
|
}
|
|
32
27
|
}));
|
|
33
28
|
const FlagsmithLink = ({
|
|
34
29
|
href,
|
|
35
30
|
children,
|
|
36
31
|
tooltip = "Open in Flagsmith",
|
|
37
|
-
iconOnly = false
|
|
38
|
-
onClick
|
|
32
|
+
iconOnly = false
|
|
39
33
|
}) => {
|
|
40
34
|
const classes = useStyles();
|
|
41
35
|
if (iconOnly) {
|
|
42
|
-
return /* @__PURE__ */ jsx(Tooltip, { title: tooltip,
|
|
36
|
+
return /* @__PURE__ */ jsx(Tooltip, { title: tooltip, children: /* @__PURE__ */ jsx(
|
|
43
37
|
IconButton,
|
|
44
38
|
{
|
|
45
39
|
className: classes.iconButton,
|
|
@@ -48,12 +42,11 @@ const FlagsmithLink = ({
|
|
|
48
42
|
rel: "noopener noreferrer",
|
|
49
43
|
size: "small",
|
|
50
44
|
"aria-label": tooltip,
|
|
51
|
-
onClick,
|
|
52
45
|
children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small", "aria-hidden": "true" })
|
|
53
46
|
}
|
|
54
47
|
) });
|
|
55
48
|
}
|
|
56
|
-
return /* @__PURE__ */ jsx(Tooltip, { title: tooltip,
|
|
49
|
+
return /* @__PURE__ */ jsx(Tooltip, { title: tooltip, children: /* @__PURE__ */ jsxs(
|
|
57
50
|
Link,
|
|
58
51
|
{
|
|
59
52
|
className: classes.link,
|
|
@@ -61,7 +54,6 @@ const FlagsmithLink = ({
|
|
|
61
54
|
target: "_blank",
|
|
62
55
|
rel: "noopener noreferrer",
|
|
63
56
|
"aria-label": `${tooltip} (opens in new tab)`,
|
|
64
|
-
onClick,
|
|
65
57
|
children: [
|
|
66
58
|
children,
|
|
67
59
|
/* @__PURE__ */ jsx(LaunchIcon, { className: classes.icon, "aria-hidden": "true" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlagsmithLink.esm.js","sources":["../../../src/components/shared/FlagsmithLink.tsx"],"sourcesContent":["import { Link, Tooltip, IconButton } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport LaunchIcon from '@material-ui/icons/Launch';\nimport { flagsmithColors } from '../../theme/flagsmithTheme';\n\nconst useStyles = makeStyles(
|
|
1
|
+
{"version":3,"file":"FlagsmithLink.esm.js","sources":["../../../src/components/shared/FlagsmithLink.tsx"],"sourcesContent":["import { Link, Tooltip, IconButton } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport LaunchIcon from '@material-ui/icons/Launch';\nimport { flagsmithColors } from '../../theme/flagsmithTheme';\n\nconst useStyles = makeStyles(() => ({\n link: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n color: 'inherit',\n textDecoration: 'none',\n '&:hover': {\n color: flagsmithColors.primary,\n textDecoration: 'underline',\n },\n },\n icon: {\n fontSize: '0.875rem',\n opacity: 0.7,\n },\n iconButton: {\n padding: 4,\n color: flagsmithColors.primary,\n },\n}));\n\ninterface FlagsmithLinkProps {\n href: string;\n children?: React.ReactNode;\n tooltip?: string;\n iconOnly?: boolean;\n}\n\n/**\n * External link to Flagsmith dashboard\n * Opens in a new tab with appropriate security attributes\n */\nexport const FlagsmithLink = ({\n href,\n children,\n tooltip = 'Open in Flagsmith',\n iconOnly = false,\n}: FlagsmithLinkProps) => {\n const classes = useStyles();\n\n if (iconOnly) {\n return (\n <Tooltip title={tooltip}>\n <IconButton\n className={classes.iconButton}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n size=\"small\"\n aria-label={tooltip}\n >\n <LaunchIcon fontSize=\"small\" aria-hidden=\"true\" />\n </IconButton>\n </Tooltip>\n );\n }\n\n return (\n <Tooltip title={tooltip}>\n <Link\n className={classes.link}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`${tooltip} (opens in new tab)`}\n >\n {children}\n <LaunchIcon className={classes.icon} aria-hidden=\"true\" />\n </Link>\n </Tooltip>\n );\n};\n"],"names":[],"mappings":";;;;;;AAKA,MAAM,SAAA,GAAY,WAAW,OAAO;AAAA,EAClC,IAAA,EAAM;AAAA,IACJ,OAAA,EAAS,aAAA;AAAA,IACT,UAAA,EAAY,QAAA;AAAA,IACZ,GAAA,EAAK,CAAA;AAAA,IACL,KAAA,EAAO,SAAA;AAAA,IACP,cAAA,EAAgB,MAAA;AAAA,IAChB,SAAA,EAAW;AAAA,MACT,OAAO,eAAA,CAAgB,OAAA;AAAA,MACvB,cAAA,EAAgB;AAAA;AAClB,GACF;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,QAAA,EAAU,UAAA;AAAA,IACV,OAAA,EAAS;AAAA,GACX;AAAA,EACA,UAAA,EAAY;AAAA,IACV,OAAA,EAAS,CAAA;AAAA,IACT,OAAO,eAAA,CAAgB;AAAA;AAE3B,CAAA,CAAE,CAAA;AAaK,MAAM,gBAAgB,CAAC;AAAA,EAC5B,IAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA,GAAU,mBAAA;AAAA,EACV,QAAA,GAAW;AACb,CAAA,KAA0B;AACxB,EAAA,MAAM,UAAU,SAAA,EAAU;AAE1B,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBACE,GAAA,CAAC,OAAA,EAAA,EAAQ,KAAA,EAAO,OAAA,EACd,QAAA,kBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,WAAW,OAAA,CAAQ,UAAA;AAAA,QACnB,IAAA;AAAA,QACA,MAAA,EAAO,QAAA;AAAA,QACP,GAAA,EAAI,qBAAA;AAAA,QACJ,IAAA,EAAK,OAAA;AAAA,QACL,YAAA,EAAY,OAAA;AAAA,QAEZ,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,QAAA,EAAS,OAAA,EAAQ,eAAY,MAAA,EAAO;AAAA;AAAA,KAClD,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,GAAA,CAAC,OAAA,EAAA,EAAQ,KAAA,EAAO,OAAA,EACd,QAAA,kBAAA,IAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAW,OAAA,CAAQ,IAAA;AAAA,MACnB,IAAA;AAAA,MACA,MAAA,EAAO,QAAA;AAAA,MACP,GAAA,EAAI,qBAAA;AAAA,MACJ,YAAA,EAAY,GAAG,OAAO,CAAA,mBAAA,CAAA;AAAA,MAErB,QAAA,EAAA;AAAA,QAAA,QAAA;AAAA,4BACA,UAAA,EAAA,EAAW,SAAA,EAAW,OAAA,CAAQ,IAAA,EAAM,eAAY,MAAA,EAAO;AAAA;AAAA;AAAA,GAC1D,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -36,13 +36,7 @@ function useFlagsmithProject(projectId) {
|
|
|
36
36
|
};
|
|
37
37
|
fetchData();
|
|
38
38
|
}, [projectId, client]);
|
|
39
|
-
|
|
40
|
-
const memoizedEnvironments = useMemo(
|
|
41
|
-
() => environments,
|
|
42
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
43
|
-
[envIds]
|
|
44
|
-
);
|
|
45
|
-
return { project, environments: memoizedEnvironments, features, loading, error, client };
|
|
39
|
+
return { project, environments, features, loading, error, client };
|
|
46
40
|
}
|
|
47
41
|
|
|
48
42
|
export { useFlagsmithProject };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFlagsmithProject.esm.js","sources":["../../src/hooks/useFlagsmithProject.ts"],"sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { useApi, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport {\n FlagsmithClient,\n FlagsmithProject,\n FlagsmithEnvironment,\n FlagsmithFeature,\n} from '../api/FlagsmithClient';\n\nexport interface UseFlagsmithProjectResult {\n project: FlagsmithProject | null;\n environments: FlagsmithEnvironment[];\n features: FlagsmithFeature[];\n loading: boolean;\n error: string | null;\n client: FlagsmithClient;\n}\n\nexport function useFlagsmithProject(\n projectId: string | undefined,\n): UseFlagsmithProjectResult {\n const discoveryApi = useApi(discoveryApiRef);\n const fetchApi = useApi(fetchApiRef);\n\n const client = useMemo(\n () => new FlagsmithClient(discoveryApi, fetchApi),\n [discoveryApi, fetchApi],\n );\n\n const [project, setProject] = useState<FlagsmithProject | null>(null);\n const [environments, setEnvironments] = useState<FlagsmithEnvironment[]>([]);\n const [features, setFeatures] = useState<FlagsmithFeature[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!projectId) {\n setError('No Flagsmith project ID found in entity annotations');\n setLoading(false);\n return;\n }\n\n const fetchData = async () => {\n try {\n const projectData = await client.getProject(parseInt(projectId, 10));\n setProject(projectData);\n\n const envs = await client.getProjectEnvironments(parseInt(projectId, 10));\n setEnvironments(envs || []);\n\n const projectFeatures = await client.getProjectFeatures(projectId);\n setFeatures(projectFeatures || []);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Unknown error');\n } finally {\n setLoading(false);\n }\n };\n\n fetchData();\n }, [projectId, client]);\n\n
|
|
1
|
+
{"version":3,"file":"useFlagsmithProject.esm.js","sources":["../../src/hooks/useFlagsmithProject.ts"],"sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { useApi, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport {\n FlagsmithClient,\n FlagsmithProject,\n FlagsmithEnvironment,\n FlagsmithFeature,\n} from '../api/FlagsmithClient';\n\nexport interface UseFlagsmithProjectResult {\n project: FlagsmithProject | null;\n environments: FlagsmithEnvironment[];\n features: FlagsmithFeature[];\n loading: boolean;\n error: string | null;\n client: FlagsmithClient;\n}\n\nexport function useFlagsmithProject(\n projectId: string | undefined,\n): UseFlagsmithProjectResult {\n const discoveryApi = useApi(discoveryApiRef);\n const fetchApi = useApi(fetchApiRef);\n\n const client = useMemo(\n () => new FlagsmithClient(discoveryApi, fetchApi),\n [discoveryApi, fetchApi],\n );\n\n const [project, setProject] = useState<FlagsmithProject | null>(null);\n const [environments, setEnvironments] = useState<FlagsmithEnvironment[]>([]);\n const [features, setFeatures] = useState<FlagsmithFeature[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!projectId) {\n setError('No Flagsmith project ID found in entity annotations');\n setLoading(false);\n return;\n }\n\n const fetchData = async () => {\n try {\n const projectData = await client.getProject(parseInt(projectId, 10));\n setProject(projectData);\n\n const envs = await client.getProjectEnvironments(parseInt(projectId, 10));\n setEnvironments(envs || []);\n\n const projectFeatures = await client.getProjectFeatures(projectId);\n setFeatures(projectFeatures || []);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Unknown error');\n } finally {\n setLoading(false);\n }\n };\n\n fetchData();\n }, [projectId, client]);\n\n return { project, environments, features, loading, error, client };\n}\n"],"names":[],"mappings":";;;;AAkBO,SAAS,oBACd,SAAA,EAC2B;AAC3B,EAAA,MAAM,YAAA,GAAe,OAAO,eAAe,CAAA;AAC3C,EAAA,MAAM,QAAA,GAAW,OAAO,WAAW,CAAA;AAEnC,EAAA,MAAM,MAAA,GAAS,OAAA;AAAA,IACb,MAAM,IAAI,eAAA,CAAgB,YAAA,EAAc,QAAQ,CAAA;AAAA,IAChD,CAAC,cAAc,QAAQ;AAAA,GACzB;AAEA,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAkC,IAAI,CAAA;AACpE,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,QAAA,CAAiC,EAAE,CAAA;AAC3E,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA,CAA6B,EAAE,CAAA;AAC/D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,QAAA,CAAS,qDAAqD,CAAA;AAC9D,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,YAAY,YAAY;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,cAAc,MAAM,MAAA,CAAO,WAAW,QAAA,CAAS,SAAA,EAAW,EAAE,CAAC,CAAA;AACnE,QAAA,UAAA,CAAW,WAAW,CAAA;AAEtB,QAAA,MAAM,OAAO,MAAM,MAAA,CAAO,uBAAuB,QAAA,CAAS,SAAA,EAAW,EAAE,CAAC,CAAA;AACxE,QAAA,eAAA,CAAgB,IAAA,IAAQ,EAAE,CAAA;AAE1B,QAAA,MAAM,eAAA,GAAkB,MAAM,MAAA,CAAO,kBAAA,CAAmB,SAAS,CAAA;AACjE,QAAA,WAAA,CAAY,eAAA,IAAmB,EAAE,CAAA;AAAA,MACnC,SAAS,GAAA,EAAK;AACZ,QAAA,QAAA,CAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,eAAe,CAAA;AAAA,MAC/D,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAEA,IAAA,SAAA,EAAU;AAAA,EACZ,CAAA,EAAG,CAAC,SAAA,EAAW,MAAM,CAAC,CAAA;AAEtB,EAAA,OAAO,EAAE,OAAA,EAAS,YAAA,EAAc,QAAA,EAAU,OAAA,EAAS,OAAO,MAAA,EAAO;AACnE;;;;"}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
2
|
import { useApi, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';
|
|
3
3
|
import { FlagsmithClient } from '../api/FlagsmithClient.esm.js';
|
|
4
4
|
|
|
5
5
|
function useFlagsmithUsage(projectId, orgId) {
|
|
6
6
|
const discoveryApi = useApi(discoveryApiRef);
|
|
7
7
|
const fetchApi = useApi(fetchApiRef);
|
|
8
|
-
const client = useMemo(
|
|
9
|
-
() => new FlagsmithClient(discoveryApi, fetchApi),
|
|
10
|
-
[discoveryApi, fetchApi]
|
|
11
|
-
);
|
|
12
8
|
const [project, setProject] = useState(null);
|
|
13
9
|
const [usageData, setUsageData] = useState([]);
|
|
14
10
|
const [loading, setLoading] = useState(true);
|
|
@@ -21,6 +17,7 @@ function useFlagsmithUsage(projectId, orgId) {
|
|
|
21
17
|
}
|
|
22
18
|
const fetchData = async () => {
|
|
23
19
|
try {
|
|
20
|
+
const client = new FlagsmithClient(discoveryApi, fetchApi);
|
|
24
21
|
const projectData = await client.getProject(parseInt(projectId, 10));
|
|
25
22
|
setProject(projectData);
|
|
26
23
|
const usage = await client.getUsageData(
|
|
@@ -35,7 +32,7 @@ function useFlagsmithUsage(projectId, orgId) {
|
|
|
35
32
|
}
|
|
36
33
|
};
|
|
37
34
|
fetchData();
|
|
38
|
-
}, [projectId, orgId,
|
|
35
|
+
}, [projectId, orgId, discoveryApi, fetchApi]);
|
|
39
36
|
const totalFlags = usageData.reduce((sum, day) => sum + (day.flags ?? 0), 0);
|
|
40
37
|
return { project, usageData, totalFlags, loading, error };
|
|
41
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFlagsmithUsage.esm.js","sources":["../../src/hooks/useFlagsmithUsage.ts"],"sourcesContent":["import { useState, useEffect
|
|
1
|
+
{"version":3,"file":"useFlagsmithUsage.esm.js","sources":["../../src/hooks/useFlagsmithUsage.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { useApi, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport {\n FlagsmithClient,\n FlagsmithProject,\n FlagsmithUsageData,\n} from '../api/FlagsmithClient';\n\nexport interface UseFlagsmithUsageResult {\n project: FlagsmithProject | null;\n usageData: FlagsmithUsageData[];\n totalFlags: number;\n loading: boolean;\n error: string | null;\n}\n\nexport function useFlagsmithUsage(\n projectId: string | undefined,\n orgId: string | undefined,\n): UseFlagsmithUsageResult {\n const discoveryApi = useApi(discoveryApiRef);\n const fetchApi = useApi(fetchApiRef);\n\n const [project, setProject] = useState<FlagsmithProject | null>(null);\n const [usageData, setUsageData] = useState<FlagsmithUsageData[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!projectId || !orgId) {\n setError('Missing Flagsmith project ID or organization ID in entity annotations');\n setLoading(false);\n return;\n }\n\n const fetchData = async () => {\n try {\n const client = new FlagsmithClient(discoveryApi, fetchApi);\n\n const projectData = await client.getProject(parseInt(projectId, 10));\n setProject(projectData);\n\n const usage = await client.getUsageData(\n parseInt(orgId, 10),\n parseInt(projectId, 10),\n );\n setUsageData(usage);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Unknown error');\n } finally {\n setLoading(false);\n }\n };\n\n fetchData();\n }, [projectId, orgId, discoveryApi, fetchApi]);\n\n const totalFlags = usageData.reduce((sum, day) => sum + (day.flags ?? 0), 0);\n\n return { project, usageData, totalFlags, loading, error };\n}\n"],"names":[],"mappings":";;;;AAgBO,SAAS,iBAAA,CACd,WACA,KAAA,EACyB;AACzB,EAAA,MAAM,YAAA,GAAe,OAAO,eAAe,CAAA;AAC3C,EAAA,MAAM,QAAA,GAAW,OAAO,WAAW,CAAA;AAEnC,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAkC,IAAI,CAAA;AACpE,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,QAAA,CAA+B,EAAE,CAAA;AACnE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAA,IAAa,CAAC,KAAA,EAAO;AACxB,MAAA,QAAA,CAAS,uEAAuE,CAAA;AAChF,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,YAAY,YAAY;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB,YAAA,EAAc,QAAQ,CAAA;AAEzD,QAAA,MAAM,cAAc,MAAM,MAAA,CAAO,WAAW,QAAA,CAAS,SAAA,EAAW,EAAE,CAAC,CAAA;AACnE,QAAA,UAAA,CAAW,WAAW,CAAA;AAEtB,QAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,YAAA;AAAA,UACzB,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,UAClB,QAAA,CAAS,WAAW,EAAE;AAAA,SACxB;AACA,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,MACpB,SAAS,GAAA,EAAK;AACZ,QAAA,QAAA,CAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,eAAe,CAAA;AAAA,MAC/D,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAEA,IAAA,SAAA,EAAU;AAAA,EACZ,GAAG,CAAC,SAAA,EAAW,KAAA,EAAO,YAAA,EAAc,QAAQ,CAAC,CAAA;AAE7C,EAAA,MAAM,UAAA,GAAa,SAAA,CAAU,MAAA,CAAO,CAAC,GAAA,EAAK,QAAQ,GAAA,IAAO,GAAA,CAAI,KAAA,IAAS,CAAA,CAAA,EAAI,CAAC,CAAA;AAE3E,EAAA,OAAO,EAAE,OAAA,EAAS,SAAA,EAAW,UAAA,EAAY,SAAS,KAAA,EAAM;AAC1D;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -100,7 +100,7 @@ declare const flagsmithPlugin: _backstage_frontend_plugin_api.OverridableFronten
|
|
|
100
100
|
defaultTitle?: [Error: `Use the 'title' param instead`];
|
|
101
101
|
title: string;
|
|
102
102
|
defaultGroup?: [Error: `Use the 'group' param instead`];
|
|
103
|
-
group?: ("
|
|
103
|
+
group?: ("overview" | "documentation" | "development" | "deployment" | "operation" | "observability") | (string & {});
|
|
104
104
|
loader: () => Promise<JSX.Element>;
|
|
105
105
|
routeRef?: _backstage_frontend_plugin_api.RouteRef;
|
|
106
106
|
filter?: string | _backstage_plugin_catalog_react_alpha.EntityPredicate | ((entity: _backstage_catalog_model.Entity) => boolean);
|
package/package.json
CHANGED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
3
|
-
import { Box, Typography, CircularProgress } from '@material-ui/core';
|
|
4
|
-
import { makeStyles } from '@material-ui/core/styles';
|
|
5
|
-
import { ResponsiveContainer, LineChart, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Line } from 'recharts';
|
|
6
|
-
import { CHART_CONFIG, getEnvColor, MAX_TABLE_ENVIRONMENTS } from '../../constants/index.esm.js';
|
|
7
|
-
import { getErrorMessage } from '../../utils/flagTypeHelpers.esm.js';
|
|
8
|
-
import { formatShortDate } from '../../utils/dateFormatters.esm.js';
|
|
9
|
-
import '../shared/FlagStatusIndicator.esm.js';
|
|
10
|
-
import '../shared/SearchInput.esm.js';
|
|
11
|
-
import '../shared/FlagsmithLink.esm.js';
|
|
12
|
-
import '@material-ui/icons/ChevronLeft';
|
|
13
|
-
import '@material-ui/icons/ChevronRight';
|
|
14
|
-
import { ChartTooltip, ChartTooltipText } from '../shared/ChartTooltip.esm.js';
|
|
15
|
-
|
|
16
|
-
const useStyles = makeStyles((theme) => ({
|
|
17
|
-
container: {
|
|
18
|
-
padding: theme.spacing(2),
|
|
19
|
-
border: `1px solid ${theme.palette.divider}`,
|
|
20
|
-
borderRadius: theme.shape.borderRadius,
|
|
21
|
-
backgroundColor: theme.palette.background.paper
|
|
22
|
-
},
|
|
23
|
-
chartContainer: {
|
|
24
|
-
width: "100%",
|
|
25
|
-
height: CHART_CONFIG.HEIGHT,
|
|
26
|
-
marginTop: theme.spacing(1)
|
|
27
|
-
},
|
|
28
|
-
noData: {
|
|
29
|
-
display: "flex",
|
|
30
|
-
alignItems: "center",
|
|
31
|
-
justifyContent: "center",
|
|
32
|
-
height: 150,
|
|
33
|
-
color: theme.palette.text.secondary
|
|
34
|
-
},
|
|
35
|
-
loading: {
|
|
36
|
-
display: "flex",
|
|
37
|
-
alignItems: "center",
|
|
38
|
-
justifyContent: "center",
|
|
39
|
-
gap: theme.spacing(1),
|
|
40
|
-
height: 150
|
|
41
|
-
}
|
|
42
|
-
}));
|
|
43
|
-
const AnalyticsTooltip = ({ active, payload, label }) => {
|
|
44
|
-
return /* @__PURE__ */ jsx(ChartTooltip, { active, payload, label, children: (data, tooltipLabel) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
45
|
-
/* @__PURE__ */ jsx(ChartTooltipText, { variant: "subtitle2", fontWeight: 600, children: tooltipLabel }),
|
|
46
|
-
/* @__PURE__ */ jsx(Box, { mt: 1, children: data.map((entry, index) => /* @__PURE__ */ jsxs(
|
|
47
|
-
Box,
|
|
48
|
-
{
|
|
49
|
-
display: "flex",
|
|
50
|
-
alignItems: "center",
|
|
51
|
-
mt: 0.25,
|
|
52
|
-
style: { gap: "4px" },
|
|
53
|
-
children: [
|
|
54
|
-
/* @__PURE__ */ jsx(
|
|
55
|
-
"span",
|
|
56
|
-
{
|
|
57
|
-
style: {
|
|
58
|
-
display: "inline-block",
|
|
59
|
-
width: "8px",
|
|
60
|
-
height: "8px",
|
|
61
|
-
backgroundColor: entry.color,
|
|
62
|
-
borderRadius: "50%"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
),
|
|
66
|
-
/* @__PURE__ */ jsxs(ChartTooltipText, { children: [
|
|
67
|
-
entry.name,
|
|
68
|
-
": ",
|
|
69
|
-
entry.value
|
|
70
|
-
] })
|
|
71
|
-
]
|
|
72
|
-
},
|
|
73
|
-
`item-${index}`
|
|
74
|
-
)) })
|
|
75
|
-
] }) });
|
|
76
|
-
};
|
|
77
|
-
const transformUsageData = (usageByEnv) => {
|
|
78
|
-
const dataByDate = /* @__PURE__ */ new Map();
|
|
79
|
-
const envNames = [];
|
|
80
|
-
usageByEnv.forEach((data, envName) => {
|
|
81
|
-
envNames.push(envName);
|
|
82
|
-
data.forEach((item) => {
|
|
83
|
-
const date = formatShortDate(item.day);
|
|
84
|
-
if (!dataByDate.has(date)) {
|
|
85
|
-
dataByDate.set(date, { date });
|
|
86
|
-
}
|
|
87
|
-
const point = dataByDate.get(date);
|
|
88
|
-
point[envName] = item.flags ?? 0;
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
const sortedData = Array.from(dataByDate.values()).sort((a, b) => {
|
|
92
|
-
const dateA = new Date(a.date);
|
|
93
|
-
const dateB = new Date(b.date);
|
|
94
|
-
return dateA.getTime() - dateB.getTime();
|
|
95
|
-
});
|
|
96
|
-
return { chartData: sortedData, envNames };
|
|
97
|
-
};
|
|
98
|
-
const FeatureAnalyticsSection = ({
|
|
99
|
-
client,
|
|
100
|
-
orgId,
|
|
101
|
-
projectId,
|
|
102
|
-
environments
|
|
103
|
-
}) => {
|
|
104
|
-
const classes = useStyles();
|
|
105
|
-
const [loading, setLoading] = useState(true);
|
|
106
|
-
const [chartData, setChartData] = useState([]);
|
|
107
|
-
const [envNames, setEnvNames] = useState([]);
|
|
108
|
-
const [error, setError] = useState(null);
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
const fetchUsageData = async () => {
|
|
111
|
-
if (!orgId || !projectId || environments.length === 0) {
|
|
112
|
-
setLoading(false);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
setLoading(true);
|
|
117
|
-
setError(null);
|
|
118
|
-
const displayedEnvs = environments.slice(0, MAX_TABLE_ENVIRONMENTS);
|
|
119
|
-
const usageByEnv = await client.getUsageDataByEnvironments(
|
|
120
|
-
orgId,
|
|
121
|
-
projectId,
|
|
122
|
-
displayedEnvs
|
|
123
|
-
);
|
|
124
|
-
const { chartData: data, envNames: names } = transformUsageData(usageByEnv);
|
|
125
|
-
setChartData(data);
|
|
126
|
-
setEnvNames(names);
|
|
127
|
-
} catch (err) {
|
|
128
|
-
setError(getErrorMessage(err, "Failed to load analytics"));
|
|
129
|
-
} finally {
|
|
130
|
-
setLoading(false);
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
fetchUsageData();
|
|
134
|
-
}, [client, orgId, projectId, environments]);
|
|
135
|
-
if (loading) {
|
|
136
|
-
return /* @__PURE__ */ jsxs(Box, { className: classes.container, children: [
|
|
137
|
-
/* @__PURE__ */ jsx(Typography, { variant: "subtitle2", gutterBottom: true, children: "Usage Analytics" }),
|
|
138
|
-
/* @__PURE__ */ jsxs(Box, { className: classes.loading, children: [
|
|
139
|
-
/* @__PURE__ */ jsx(CircularProgress, { size: 20 }),
|
|
140
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "Loading analytics..." })
|
|
141
|
-
] })
|
|
142
|
-
] });
|
|
143
|
-
}
|
|
144
|
-
if (error) {
|
|
145
|
-
return /* @__PURE__ */ jsxs(Box, { className: classes.container, children: [
|
|
146
|
-
/* @__PURE__ */ jsx(Typography, { variant: "subtitle2", gutterBottom: true, children: "Usage Analytics" }),
|
|
147
|
-
/* @__PURE__ */ jsx(Box, { className: classes.noData, children: /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "error", children: error }) })
|
|
148
|
-
] });
|
|
149
|
-
}
|
|
150
|
-
if (chartData.length === 0) {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
return /* @__PURE__ */ jsxs(Box, { className: classes.container, children: [
|
|
154
|
-
/* @__PURE__ */ jsx(Typography, { variant: "subtitle2", gutterBottom: true, children: "Usage Analytics (Last 30 Days)" }),
|
|
155
|
-
/* @__PURE__ */ jsx(Box, { className: classes.chartContainer, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(LineChart, { data: chartData, margin: CHART_CONFIG.MARGIN, children: [
|
|
156
|
-
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3" }),
|
|
157
|
-
/* @__PURE__ */ jsx(XAxis, { dataKey: "date", fontSize: 12 }),
|
|
158
|
-
/* @__PURE__ */ jsx(YAxis, { fontSize: 12 }),
|
|
159
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(AnalyticsTooltip, {}) }),
|
|
160
|
-
/* @__PURE__ */ jsx(Legend, {}),
|
|
161
|
-
envNames.map((envName, index) => /* @__PURE__ */ jsx(
|
|
162
|
-
Line,
|
|
163
|
-
{
|
|
164
|
-
type: "monotone",
|
|
165
|
-
dataKey: envName,
|
|
166
|
-
stroke: getEnvColor(envName, index),
|
|
167
|
-
strokeWidth: 2,
|
|
168
|
-
dot: false,
|
|
169
|
-
activeDot: { r: 4 }
|
|
170
|
-
},
|
|
171
|
-
envName
|
|
172
|
-
))
|
|
173
|
-
] }) }) })
|
|
174
|
-
] });
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
export { FeatureAnalyticsSection };
|
|
178
|
-
//# sourceMappingURL=FeatureAnalyticsSection.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FeatureAnalyticsSection.esm.js","sources":["../../../src/components/FlagsTab/FeatureAnalyticsSection.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { Box, CircularProgress, Typography } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport {\n LineChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n Legend,\n ResponsiveContainer,\n} from 'recharts';\nimport {\n FlagsmithClient,\n FlagsmithEnvironment,\n FlagsmithUsageData,\n} from '../../api/FlagsmithClient';\nimport {\n CHART_CONFIG,\n MAX_TABLE_ENVIRONMENTS,\n getEnvColor,\n} from '../../constants';\nimport { getErrorMessage } from '../../utils/flagTypeHelpers';\nimport { formatShortDate } from '../../utils/dateFormatters';\nimport { ChartTooltip, ChartTooltipText } from '../shared';\n\nconst useStyles = makeStyles(theme => ({\n container: {\n padding: theme.spacing(2),\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: theme.shape.borderRadius,\n backgroundColor: theme.palette.background.paper,\n },\n chartContainer: {\n width: '100%',\n height: CHART_CONFIG.HEIGHT,\n marginTop: theme.spacing(1),\n },\n noData: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: 150,\n color: theme.palette.text.secondary,\n },\n loading: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing(1),\n height: 150,\n },\n}));\n\ninterface ChartDataPoint {\n date: string;\n [envName: string]: number | string;\n}\n\n/**\n * Custom tooltip component for analytics chart\n */\nconst AnalyticsTooltip = ({ active, payload, label }: any) => {\n return (\n <ChartTooltip active={active} payload={payload} label={label}>\n {(data, tooltipLabel) => (\n <>\n <ChartTooltipText variant=\"subtitle2\" fontWeight={600}>\n {tooltipLabel}\n </ChartTooltipText>\n <Box mt={1}>\n {data.map((entry: any, index: number) => (\n <Box\n key={`item-${index}`}\n display=\"flex\"\n alignItems=\"center\"\n mt={0.25}\n style={{ gap: '4px' }}\n >\n <span\n style={{\n display: 'inline-block',\n width: '8px',\n height: '8px',\n backgroundColor: entry.color,\n borderRadius: '50%',\n }}\n />\n <ChartTooltipText>\n {entry.name}: {entry.value}\n </ChartTooltipText>\n </Box>\n ))}\n </Box>\n </>\n )}\n </ChartTooltip>\n );\n};\n\ninterface FeatureAnalyticsSectionProps {\n client: FlagsmithClient;\n orgId: number;\n projectId: number;\n environments: FlagsmithEnvironment[];\n}\n\n/**\n * Transform usage data by environment into chart-friendly format\n */\nconst transformUsageData = (\n usageByEnv: Map<string, FlagsmithUsageData[]>,\n): { chartData: ChartDataPoint[]; envNames: string[] } => {\n const dataByDate = new Map<string, ChartDataPoint>();\n const envNames: string[] = [];\n\n usageByEnv.forEach((data: FlagsmithUsageData[], envName: string) => {\n envNames.push(envName);\n data.forEach(item => {\n const date = formatShortDate(item.day);\n if (!dataByDate.has(date)) {\n dataByDate.set(date, { date });\n }\n const point = dataByDate.get(date)!;\n point[envName] = item.flags ?? 0;\n });\n });\n\n const sortedData = Array.from(dataByDate.values()).sort((a, b) => {\n const dateA = new Date(a.date);\n const dateB = new Date(b.date);\n return dateA.getTime() - dateB.getTime();\n });\n\n return { chartData: sortedData, envNames };\n};\n\nexport const FeatureAnalyticsSection = ({\n client,\n orgId,\n projectId,\n environments,\n}: FeatureAnalyticsSectionProps) => {\n const classes = useStyles();\n const [loading, setLoading] = useState(true);\n const [chartData, setChartData] = useState<ChartDataPoint[]>([]);\n const [envNames, setEnvNames] = useState<string[]>([]);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const fetchUsageData = async () => {\n if (!orgId || !projectId || environments.length === 0) {\n setLoading(false);\n return;\n }\n\n try {\n setLoading(true);\n setError(null);\n\n const displayedEnvs = environments.slice(0, MAX_TABLE_ENVIRONMENTS);\n\n const usageByEnv = await client.getUsageDataByEnvironments(\n orgId,\n projectId,\n displayedEnvs,\n );\n\n const { chartData: data, envNames: names } = transformUsageData(usageByEnv);\n setChartData(data);\n setEnvNames(names);\n } catch (err) {\n setError(getErrorMessage(err, 'Failed to load analytics'));\n } finally {\n setLoading(false);\n }\n };\n\n fetchUsageData();\n }, [client, orgId, projectId, environments]);\n\n if (loading) {\n return (\n <Box className={classes.container}>\n <Typography variant=\"subtitle2\" gutterBottom>\n Usage Analytics\n </Typography>\n <Box className={classes.loading}>\n <CircularProgress size={20} />\n <Typography variant=\"body2\" color=\"textSecondary\">\n Loading analytics...\n </Typography>\n </Box>\n </Box>\n );\n }\n\n if (error) {\n return (\n <Box className={classes.container}>\n <Typography variant=\"subtitle2\" gutterBottom>\n Usage Analytics\n </Typography>\n <Box className={classes.noData}>\n <Typography variant=\"body2\" color=\"error\">\n {error}\n </Typography>\n </Box>\n </Box>\n );\n }\n\n if (chartData.length === 0) {\n return null;\n }\n\n return (\n <Box className={classes.container}>\n <Typography variant=\"subtitle2\" gutterBottom>\n Usage Analytics (Last 30 Days)\n </Typography>\n <Box className={classes.chartContainer}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart data={chartData} margin={CHART_CONFIG.MARGIN}>\n <CartesianGrid strokeDasharray=\"3 3\" />\n <XAxis dataKey=\"date\" fontSize={12} />\n <YAxis fontSize={12} />\n <Tooltip content={<AnalyticsTooltip />} />\n <Legend />\n {envNames.map((envName, index) => (\n <Line\n key={envName}\n type=\"monotone\"\n dataKey={envName}\n stroke={getEnvColor(envName, index)}\n strokeWidth={2}\n dot={false}\n activeDot={{ r: 4 }}\n />\n ))}\n </LineChart>\n </ResponsiveContainer>\n </Box>\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { Box, Typography } from '@material-ui/core';
|
|
3
|
-
import { makeStyles } from '@material-ui/core/styles';
|
|
4
|
-
|
|
5
|
-
const useStyles = makeStyles((theme) => ({
|
|
6
|
-
tooltipBox: {
|
|
7
|
-
backgroundColor: theme.palette.grey[800],
|
|
8
|
-
border: "none",
|
|
9
|
-
borderRadius: theme.shape.borderRadius,
|
|
10
|
-
boxShadow: "0 2px 8px rgba(0,0,0,0.15)"
|
|
11
|
-
},
|
|
12
|
-
tooltipText: {
|
|
13
|
-
color: theme.palette.common.white
|
|
14
|
-
}
|
|
15
|
-
}));
|
|
16
|
-
const ChartTooltip = ({ active, payload, label, children }) => {
|
|
17
|
-
const classes = useStyles();
|
|
18
|
-
if (!active || !payload?.length) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
return /* @__PURE__ */ jsx(Box, { p: 1.5, className: classes.tooltipBox, children: children(payload, label) });
|
|
22
|
-
};
|
|
23
|
-
const ChartTooltipText = ({
|
|
24
|
-
variant = "body2",
|
|
25
|
-
fontWeight,
|
|
26
|
-
children
|
|
27
|
-
}) => {
|
|
28
|
-
const classes = useStyles();
|
|
29
|
-
return /* @__PURE__ */ jsx(Typography, { variant, className: classes.tooltipText, style: { fontWeight }, children });
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export { ChartTooltip, ChartTooltipText };
|
|
33
|
-
//# sourceMappingURL=ChartTooltip.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ChartTooltip.esm.js","sources":["../../../src/components/shared/ChartTooltip.tsx"],"sourcesContent":["import { Box, Typography } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { ReactNode } from 'react';\n\nconst useStyles = makeStyles((theme) => ({\n tooltipBox: {\n backgroundColor: theme.palette.grey[800],\n border: 'none',\n borderRadius: theme.shape.borderRadius,\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\n },\n tooltipText: {\n color: theme.palette.common.white,\n },\n}));\n\ninterface ChartTooltipProps {\n active?: boolean;\n payload?: any[];\n label?: string;\n children: (payload: any[], label?: string) => ReactNode;\n}\n\n/**\n * Generic Recharts custom tooltip component\n * Uses theme colors for consistent theming across light and dark modes\n * Accepts a render function to customize content per use case\n *\n * @example\n * <Tooltip content={\n * <ChartTooltip>\n * {(payload, label) => (\n * <>\n * <ChartTooltipText variant=\"subtitle2\">{label}</ChartTooltipText>\n * <ChartTooltipText>Value: {payload[0].value}</ChartTooltipText>\n * </>\n * )}\n * </ChartTooltip>\n * } />\n */\nexport const ChartTooltip = ({ active, payload, label, children }: ChartTooltipProps) => {\n const classes = useStyles();\n\n if (!active || !payload?.length) {\n return null;\n }\n\n return (\n <Box p={1.5} className={classes.tooltipBox}>\n {children(payload, label)}\n </Box>\n );\n};\n\ninterface ChartTooltipTextProps {\n variant?: 'subtitle2' | 'body2';\n fontWeight?: number;\n children: ReactNode;\n}\n\n/**\n * Text component for chart tooltips with theme-aware white color\n */\nexport const ChartTooltipText = ({\n variant = 'body2',\n fontWeight,\n children,\n}: ChartTooltipTextProps) => {\n const classes = useStyles();\n\n return (\n <Typography variant={variant} className={classes.tooltipText} style={{ fontWeight }}>\n {children}\n </Typography>\n );\n};\n"],"names":[],"mappings":";;;;AAIA,MAAM,SAAA,GAAY,UAAA,CAAW,CAAC,KAAA,MAAW;AAAA,EACvC,UAAA,EAAY;AAAA,IACV,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA;AAAA,IACvC,MAAA,EAAQ,MAAA;AAAA,IACR,YAAA,EAAc,MAAM,KAAA,CAAM,YAAA;AAAA,IAC1B,SAAA,EAAW;AAAA,GACb;AAAA,EACA,WAAA,EAAa;AAAA,IACX,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO;AAAA;AAEhC,CAAA,CAAE,CAAA;AA0BK,MAAM,eAAe,CAAC,EAAE,QAAQ,OAAA,EAAS,KAAA,EAAO,UAAS,KAAyB;AACvF,EAAA,MAAM,UAAU,SAAA,EAAU;AAE1B,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,OAAA,EAAS,MAAA,EAAQ;AAC/B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACE,GAAA,CAAC,GAAA,EAAA,EAAI,CAAA,EAAG,GAAA,EAAK,SAAA,EAAW,QAAQ,UAAA,EAC7B,QAAA,EAAA,QAAA,CAAS,OAAA,EAAS,KAAK,CAAA,EAC1B,CAAA;AAEJ;AAWO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,OAAA,GAAU,OAAA;AAAA,EACV,UAAA;AAAA,EACA;AACF,CAAA,KAA6B;AAC3B,EAAA,MAAM,UAAU,SAAA,EAAU;AAE1B,EAAA,uBACE,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAkB,SAAA,EAAW,OAAA,CAAQ,aAAa,KAAA,EAAO,EAAE,UAAA,EAAW,EAC/E,QAAA,EACH,CAAA;AAEJ;;;;"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { Box, Typography } from '@material-ui/core';
|
|
3
|
-
|
|
4
|
-
const ErrorState = ({ message, hint }) => /* @__PURE__ */ jsxs(Box, { p: 2, children: [
|
|
5
|
-
/* @__PURE__ */ jsxs(Typography, { color: "error", children: [
|
|
6
|
-
"Error: ",
|
|
7
|
-
message
|
|
8
|
-
] }),
|
|
9
|
-
hint && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", style: { marginTop: 8 }, children: hint })
|
|
10
|
-
] });
|
|
11
|
-
|
|
12
|
-
export { ErrorState };
|
|
13
|
-
//# sourceMappingURL=ErrorState.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorState.esm.js","sources":["../../../src/components/shared/ErrorState.tsx"],"sourcesContent":["import { Box, Typography } from '@material-ui/core';\n\ninterface ErrorStateProps {\n message: string;\n hint?: string;\n}\n\nexport const ErrorState = ({ message, hint }: ErrorStateProps) => (\n <Box p={2}>\n <Typography color=\"error\">Error: {message}</Typography>\n {hint && (\n <Typography variant=\"body2\" color=\"textSecondary\" style={{ marginTop: 8 }}>\n {hint}\n </Typography>\n )}\n </Box>\n);\n"],"names":[],"mappings":";;;AAOO,MAAM,UAAA,GAAa,CAAC,EAAE,OAAA,EAAS,MAAK,qBACzC,IAAA,CAAC,GAAA,EAAA,EAAI,CAAA,EAAG,CAAA,EACN,QAAA,EAAA;AAAA,kBAAA,IAAA,CAAC,UAAA,EAAA,EAAW,OAAM,OAAA,EAAQ,QAAA,EAAA;AAAA,IAAA,SAAA;AAAA,IAAQ;AAAA,GAAA,EAAQ,CAAA;AAAA,EACzC,IAAA,oBACC,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,OAAA,EAAQ,KAAA,EAAM,eAAA,EAAgB,KAAA,EAAO,EAAE,SAAA,EAAW,CAAA,EAAE,EACrE,QAAA,EAAA,IAAA,EACH;AAAA,CAAA,EAEJ;;;;"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const FEATURE_TYPES = {
|
|
2
|
-
CONFIG: "CONFIG"};
|
|
3
|
-
const MAX_DISPLAY_TAGS = 3;
|
|
4
|
-
const MAX_TABLE_ENVIRONMENTS = 6;
|
|
5
|
-
const MAX_DETAIL_ENVIRONMENTS = 10;
|
|
6
|
-
const DESCRIPTION_TRUNCATE_LENGTH = 60;
|
|
7
|
-
const PAGINATION_OPTIONS = [10, 25, 50, 100];
|
|
8
|
-
const DEFAULT_ROWS_PER_PAGE = 50;
|
|
9
|
-
const CHART_CONFIG = {
|
|
10
|
-
HEIGHT: 250,
|
|
11
|
-
MARGIN: { top: 5, right: 30, left: 0, bottom: 5 }
|
|
12
|
-
};
|
|
13
|
-
const ENV_COLORS = {
|
|
14
|
-
development: "#4caf50",
|
|
15
|
-
dev: "#4caf50",
|
|
16
|
-
staging: "#ff9800",
|
|
17
|
-
stage: "#ff9800",
|
|
18
|
-
production: "#f44336",
|
|
19
|
-
prod: "#f44336"
|
|
20
|
-
};
|
|
21
|
-
const DEFAULT_ENV_COLORS = [
|
|
22
|
-
"#2196f3",
|
|
23
|
-
"#9c27b0",
|
|
24
|
-
"#00bcd4",
|
|
25
|
-
"#795548",
|
|
26
|
-
"#607d8b",
|
|
27
|
-
"#e91e63"
|
|
28
|
-
];
|
|
29
|
-
const getEnvColor = (envName, index) => {
|
|
30
|
-
const lowerName = envName.toLowerCase();
|
|
31
|
-
for (const [key, color] of Object.entries(ENV_COLORS)) {
|
|
32
|
-
if (lowerName.includes(key)) return color;
|
|
33
|
-
}
|
|
34
|
-
return DEFAULT_ENV_COLORS[index % DEFAULT_ENV_COLORS.length] || "#2196f3";
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export { CHART_CONFIG, DEFAULT_ENV_COLORS, DEFAULT_ROWS_PER_PAGE, DESCRIPTION_TRUNCATE_LENGTH, ENV_COLORS, FEATURE_TYPES, MAX_DETAIL_ENVIRONMENTS, MAX_DISPLAY_TAGS, MAX_TABLE_ENVIRONMENTS, PAGINATION_OPTIONS, getEnvColor };
|
|
38
|
-
//# sourceMappingURL=index.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../../src/constants/index.ts"],"sourcesContent":["/**\n * Constants for FlagsTab and related components\n */\n\n/** Feature types from Flagsmith API */\nexport const FEATURE_TYPES = {\n CONFIG: 'CONFIG',\n FLAG: 'FLAG',\n} as const;\n\n/** Maximum number of tags to display inline before showing \"+N more\" */\nexport const MAX_DISPLAY_TAGS = 3;\n\n/** Maximum number of environments to show in the main table columns */\nexport const MAX_TABLE_ENVIRONMENTS = 6;\n\n/** Maximum number of environments to show in the detailed environment table */\nexport const MAX_DETAIL_ENVIRONMENTS = 10;\n\n/** Maximum characters for description truncation */\nexport const DESCRIPTION_TRUNCATE_LENGTH = 60;\n\n/** Pagination options for the flags table */\nexport const PAGINATION_OPTIONS = [10, 25, 50, 100];\n\n/** Default rows per page */\nexport const DEFAULT_ROWS_PER_PAGE = 50;\n\n/** Chart dimensions */\nexport const CHART_CONFIG = {\n HEIGHT: 250,\n MARGIN: { top: 5, right: 30, left: 0, bottom: 5 },\n} as const;\n\n/** Environment colors for analytics chart */\nexport const ENV_COLORS: Record<string, string> = {\n development: '#4caf50',\n dev: '#4caf50',\n staging: '#ff9800',\n stage: '#ff9800',\n production: '#f44336',\n prod: '#f44336',\n};\n\n/** Fallback colors for environments not matching predefined names */\nexport const DEFAULT_ENV_COLORS = [\n '#2196f3',\n '#9c27b0',\n '#00bcd4',\n '#795548',\n '#607d8b',\n '#e91e63',\n] as const;\n\n/**\n * Get color for an environment based on its name\n */\nexport const getEnvColor = (envName: string, index: number): string => {\n const lowerName = envName.toLowerCase();\n for (const [key, color] of Object.entries(ENV_COLORS)) {\n if (lowerName.includes(key)) return color;\n }\n return DEFAULT_ENV_COLORS[index % DEFAULT_ENV_COLORS.length] || '#2196f3';\n};\n"],"names":[],"mappings":"AAKO,MAAM,aAAA,GAAgB;AAAA,EAC3B,MAAA,EAAQ,QAEV;AAGO,MAAM,gBAAA,GAAmB;AAGzB,MAAM,sBAAA,GAAyB;AAG/B,MAAM,uBAAA,GAA0B;AAGhC,MAAM,2BAAA,GAA8B;AAGpC,MAAM,kBAAA,GAAqB,CAAC,EAAA,EAAI,EAAA,EAAI,IAAI,GAAG;AAG3C,MAAM,qBAAA,GAAwB;AAG9B,MAAM,YAAA,GAAe;AAAA,EAC1B,MAAA,EAAQ,GAAA;AAAA,EACR,MAAA,EAAQ,EAAE,GAAA,EAAK,CAAA,EAAG,OAAO,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG,MAAA,EAAQ,CAAA;AAChD;AAGO,MAAM,UAAA,GAAqC;AAAA,EAChD,WAAA,EAAa,SAAA;AAAA,EACb,GAAA,EAAK,SAAA;AAAA,EACL,OAAA,EAAS,SAAA;AAAA,EACT,KAAA,EAAO,SAAA;AAAA,EACP,UAAA,EAAY,SAAA;AAAA,EACZ,IAAA,EAAM;AACR;AAGO,MAAM,kBAAA,GAAqB;AAAA,EAChC,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF;AAKO,MAAM,WAAA,GAAc,CAAC,OAAA,EAAiB,KAAA,KAA0B;AACrE,EAAA,MAAM,SAAA,GAAY,QAAQ,WAAA,EAAY;AACtC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,EAAG;AACrD,IAAA,IAAI,SAAA,CAAU,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,KAAA;AAAA,EACtC;AACA,EAAA,OAAO,kBAAA,CAAmB,KAAA,GAAQ,kBAAA,CAAmB,MAAM,CAAA,IAAK,SAAA;AAClE;;;;"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { flagsmithColors } from './flagsmithTheme.esm.js';
|
|
2
|
-
|
|
3
|
-
const switchOnStyle = {
|
|
4
|
-
"& .MuiSwitch-switchBase.Mui-checked": {
|
|
5
|
-
color: flagsmithColors.primary
|
|
6
|
-
},
|
|
7
|
-
"& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track": {
|
|
8
|
-
backgroundColor: flagsmithColors.primary
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
const detailCardStyle = (theme) => ({
|
|
12
|
-
padding: theme.spacing(1.5),
|
|
13
|
-
marginBottom: theme.spacing(1),
|
|
14
|
-
border: `1px solid ${theme.palette.divider}`,
|
|
15
|
-
borderRadius: theme.shape.borderRadius
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
export { detailCardStyle, switchOnStyle };
|
|
19
|
-
//# sourceMappingURL=sharedStyles.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sharedStyles.esm.js","sources":["../../src/theme/sharedStyles.ts"],"sourcesContent":["import { Theme } from '@material-ui/core/styles';\nimport { flagsmithColors } from './flagsmithTheme';\n\n/**\n * Shared style for colored Switch components\n */\nexport const switchOnStyle = {\n '& .MuiSwitch-switchBase.Mui-checked': {\n color: flagsmithColors.primary,\n },\n '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': {\n backgroundColor: flagsmithColors.primary,\n },\n};\n\n/**\n * Shared styles for small chips (tags, badges)\n */\nexport const smallChipStyle = (theme: Theme) => ({\n fontSize: '0.7rem',\n height: 20,\n marginRight: theme.spacing(0.5),\n});\n\n/**\n * Shared styles for detail cards\n */\nexport const detailCardStyle = (theme: Theme) => ({\n padding: theme.spacing(1.5),\n marginBottom: theme.spacing(1),\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: theme.shape.borderRadius,\n});\n"],"names":[],"mappings":";;AAMO,MAAM,aAAA,GAAgB;AAAA,EAC3B,qCAAA,EAAuC;AAAA,IACrC,OAAO,eAAA,CAAgB;AAAA,GACzB;AAAA,EACA,wDAAA,EAA0D;AAAA,IACxD,iBAAiB,eAAA,CAAgB;AAAA;AAErC;AAcO,MAAM,eAAA,GAAkB,CAAC,KAAA,MAAkB;AAAA,EAChD,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAAA,EAC1B,YAAA,EAAc,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,EAC7B,MAAA,EAAQ,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,EAC1C,YAAA,EAAc,MAAM,KAAA,CAAM;AAC5B,CAAA;;;;"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const formatDate = (date) => {
|
|
2
|
-
return new Date(date).toLocaleDateString();
|
|
3
|
-
};
|
|
4
|
-
const formatDateTime = (date) => {
|
|
5
|
-
return new Date(date).toLocaleString();
|
|
6
|
-
};
|
|
7
|
-
const formatShortDate = (date) => {
|
|
8
|
-
return new Date(date).toLocaleDateString("en-US", {
|
|
9
|
-
month: "short",
|
|
10
|
-
day: "numeric"
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export { formatDate, formatDateTime, formatShortDate };
|
|
15
|
-
//# sourceMappingURL=dateFormatters.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dateFormatters.esm.js","sources":["../../src/utils/dateFormatters.ts"],"sourcesContent":["/**\n * Consistent date formatting utilities\n */\n\n/**\n * Format a date as a short date string (e.g., \"1/15/2024\")\n */\nexport const formatDate = (date: string | Date): string => {\n return new Date(date).toLocaleDateString();\n};\n\n/**\n * Format a date with time (e.g., \"1/15/2024, 10:30 AM\")\n */\nexport const formatDateTime = (date: string | Date): string => {\n return new Date(date).toLocaleString();\n};\n\n/**\n * Format a date as short month and day (e.g., \"Jan 15\")\n */\nexport const formatShortDate = (date: string | Date): string => {\n return new Date(date).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n });\n};\n\n/**\n * Check if a date is in the future\n */\nexport const isFutureDate = (date: string | Date): boolean => {\n return new Date(date) > new Date();\n};\n"],"names":[],"mappings":"AAOO,MAAM,UAAA,GAAa,CAAC,IAAA,KAAgC;AACzD,EAAA,OAAO,IAAI,IAAA,CAAK,IAAI,CAAA,CAAE,kBAAA,EAAmB;AAC3C;AAKO,MAAM,cAAA,GAAiB,CAAC,IAAA,KAAgC;AAC7D,EAAA,OAAO,IAAI,IAAA,CAAK,IAAI,CAAA,CAAE,cAAA,EAAe;AACvC;AAKO,MAAM,eAAA,GAAkB,CAAC,IAAA,KAAgC;AAC9D,EAAA,OAAO,IAAI,IAAA,CAAK,IAAI,CAAA,CAAE,mBAAmB,OAAA,EAAS;AAAA,IAChD,KAAA,EAAO,OAAA;AAAA,IACP,GAAA,EAAK;AAAA,GACN,CAAA;AACH;;;;"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { FEATURE_TYPES } from '../constants/index.esm.js';
|
|
2
|
-
|
|
3
|
-
const isDefined = (value) => {
|
|
4
|
-
return value !== null && value !== void 0;
|
|
5
|
-
};
|
|
6
|
-
const isMultivariateFeature = (feature) => {
|
|
7
|
-
return Boolean(
|
|
8
|
-
feature.multivariate_options && feature.multivariate_options.length > 0
|
|
9
|
-
);
|
|
10
|
-
};
|
|
11
|
-
const getFlagType = (feature) => {
|
|
12
|
-
if (isMultivariateFeature(feature)) return "Multivariate";
|
|
13
|
-
if (feature.type === FEATURE_TYPES.CONFIG) return "Remote Config";
|
|
14
|
-
return "Standard";
|
|
15
|
-
};
|
|
16
|
-
const getValueType = (feature) => {
|
|
17
|
-
if (isMultivariateFeature(feature) && feature.multivariate_options) {
|
|
18
|
-
const firstOption = feature.multivariate_options[0];
|
|
19
|
-
if (isDefined(firstOption.string_value)) return "String";
|
|
20
|
-
if (isDefined(firstOption.integer_value)) return "Number";
|
|
21
|
-
if (isDefined(firstOption.boolean_value)) return "Boolean";
|
|
22
|
-
}
|
|
23
|
-
if (feature.type === FEATURE_TYPES.CONFIG && isDefined(feature.initial_value)) {
|
|
24
|
-
const value = feature.initial_value;
|
|
25
|
-
if (value === "true" || value === "false") return "Boolean";
|
|
26
|
-
if (!isNaN(Number(value))) return "Number";
|
|
27
|
-
return "String";
|
|
28
|
-
}
|
|
29
|
-
return "Boolean";
|
|
30
|
-
};
|
|
31
|
-
const truncateText = (text, maxLength) => {
|
|
32
|
-
if (text.length <= maxLength) return text;
|
|
33
|
-
return `${text.substring(0, maxLength)}...`;
|
|
34
|
-
};
|
|
35
|
-
const getErrorMessage = (error, fallback) => {
|
|
36
|
-
if (error instanceof Error) return error.message;
|
|
37
|
-
if (typeof error === "string") return error;
|
|
38
|
-
return fallback;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export { getErrorMessage, getFlagType, getValueType, isDefined, isMultivariateFeature, truncateText };
|
|
42
|
-
//# sourceMappingURL=flagTypeHelpers.esm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"flagTypeHelpers.esm.js","sources":["../../src/utils/flagTypeHelpers.ts"],"sourcesContent":["import { FlagsmithFeature } from '../api/FlagsmithClient';\nimport { FEATURE_TYPES } from '../constants';\n\nexport type FlagType = 'Multivariate' | 'Remote Config' | 'Standard';\nexport type ValueType = 'Boolean' | 'String' | 'Number';\n\nexport interface FlagTypeInfo {\n flagType: FlagType;\n valueType: ValueType;\n isMultivariate: boolean;\n}\n\n/**\n * Check if a value is defined (not null or undefined)\n */\nexport const isDefined = <T>(value: T | null | undefined): value is T => {\n return value !== null && value !== undefined;\n};\n\n/**\n * Check if a feature is multivariate\n */\nexport const isMultivariateFeature = (feature: FlagsmithFeature): boolean => {\n return Boolean(\n feature.multivariate_options && feature.multivariate_options.length > 0\n );\n};\n\n/**\n * Determine the flag type for display\n */\nexport const getFlagType = (feature: FlagsmithFeature): FlagType => {\n if (isMultivariateFeature(feature)) return 'Multivariate';\n if (feature.type === FEATURE_TYPES.CONFIG) return 'Remote Config';\n return 'Standard';\n};\n\n/**\n * Determine the value type based on feature configuration\n */\nexport const getValueType = (feature: FlagsmithFeature): ValueType => {\n // Check multivariate options first\n if (isMultivariateFeature(feature) && feature.multivariate_options) {\n const firstOption = feature.multivariate_options[0];\n if (isDefined(firstOption.string_value)) return 'String';\n if (isDefined(firstOption.integer_value)) return 'Number';\n if (isDefined(firstOption.boolean_value)) return 'Boolean';\n }\n\n // Check CONFIG type with initial_value\n if (feature.type === FEATURE_TYPES.CONFIG && isDefined(feature.initial_value)) {\n const value = feature.initial_value;\n if (value === 'true' || value === 'false') return 'Boolean';\n if (!isNaN(Number(value))) return 'Number';\n return 'String';\n }\n\n // Default for FLAG type\n return 'Boolean';\n};\n\n/**\n * Get complete flag type information\n */\nexport const getFlagTypeInfo = (feature: FlagsmithFeature): FlagTypeInfo => ({\n flagType: getFlagType(feature),\n valueType: getValueType(feature),\n isMultivariate: isMultivariateFeature(feature),\n});\n\n/**\n * Truncate text to a maximum length with ellipsis\n */\nexport const truncateText = (text: string, maxLength: number): string => {\n if (text.length <= maxLength) return text;\n return `${text.substring(0, maxLength)}...`;\n};\n\n/**\n * Get error message from unknown error\n */\nexport const getErrorMessage = (error: unknown, fallback: string): string => {\n if (error instanceof Error) return error.message;\n if (typeof error === 'string') return error;\n return fallback;\n};\n"],"names":[],"mappings":";;AAeO,MAAM,SAAA,GAAY,CAAI,KAAA,KAA4C;AACvE,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAKO,MAAM,qBAAA,GAAwB,CAAC,OAAA,KAAuC;AAC3E,EAAA,OAAO,OAAA;AAAA,IACL,OAAA,CAAQ,oBAAA,IAAwB,OAAA,CAAQ,oBAAA,CAAqB,MAAA,GAAS;AAAA,GACxE;AACF;AAKO,MAAM,WAAA,GAAc,CAAC,OAAA,KAAwC;AAClE,EAAA,IAAI,qBAAA,CAAsB,OAAO,CAAA,EAAG,OAAO,cAAA;AAC3C,EAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,aAAA,CAAc,MAAA,EAAQ,OAAO,eAAA;AAClD,EAAA,OAAO,UAAA;AACT;AAKO,MAAM,YAAA,GAAe,CAAC,OAAA,KAAyC;AAEpE,EAAA,IAAI,qBAAA,CAAsB,OAAO,CAAA,IAAK,OAAA,CAAQ,oBAAA,EAAsB;AAClE,IAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,oBAAA,CAAqB,CAAC,CAAA;AAClD,IAAA,IAAI,SAAA,CAAU,WAAA,CAAY,YAAY,CAAA,EAAG,OAAO,QAAA;AAChD,IAAA,IAAI,SAAA,CAAU,WAAA,CAAY,aAAa,CAAA,EAAG,OAAO,QAAA;AACjD,IAAA,IAAI,SAAA,CAAU,WAAA,CAAY,aAAa,CAAA,EAAG,OAAO,SAAA;AAAA,EACnD;AAGA,EAAA,IAAI,QAAQ,IAAA,KAAS,aAAA,CAAc,UAAU,SAAA,CAAU,OAAA,CAAQ,aAAa,CAAA,EAAG;AAC7E,IAAA,MAAM,QAAQ,OAAA,CAAQ,aAAA;AACtB,IAAA,IAAI,KAAA,KAAU,MAAA,IAAU,KAAA,KAAU,OAAA,EAAS,OAAO,SAAA;AAClD,IAAA,IAAI,CAAC,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,GAAG,OAAO,QAAA;AAClC,IAAA,OAAO,QAAA;AAAA,EACT;AAGA,EAAA,OAAO,SAAA;AACT;AAcO,MAAM,YAAA,GAAe,CAAC,IAAA,EAAc,SAAA,KAA8B;AACvE,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,SAAA,EAAW,OAAO,IAAA;AACrC,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,CAAA,EAAG,SAAS,CAAC,CAAA,GAAA,CAAA;AACxC;AAKO,MAAM,eAAA,GAAkB,CAAC,KAAA,EAAgB,QAAA,KAA6B;AAC3E,EAAA,IAAI,KAAA,YAAiB,KAAA,EAAO,OAAO,KAAA,CAAM,OAAA;AACzC,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,OAAO,QAAA;AACT;;;;"}
|