{"version":3,"file":"AdminFeatureTogglesPage.22157fe31f358f1c4f09.js","mappings":"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","sources":["webpack://grafana/./public/app/features/admin/AdminFeatureTogglesAPI.ts","webpack://grafana/./public/app/features/admin/AdminFeatureTogglesTable.tsx","webpack://grafana/./public/app/features/admin/AdminFeatureTogglesPage.tsx"],"sourcesContent":["import { getBackendSrv } from '@grafana/runtime';\n\nexport type FeatureToggle = {\n name: string;\n description?: string;\n enabled: boolean;\n stage: string;\n readOnly?: boolean;\n hidden?: boolean;\n};\n\nexport type CurrentTogglesState = {\n restartRequired: boolean;\n allowEditing: boolean;\n toggles: FeatureToggle[];\n};\n\ninterface ResolvedToggleState {\n kind: 'ResolvedToggleState';\n restartRequired?: boolean;\n allowEditing?: boolean;\n toggles?: K8sToggleSpec[]; // not used in patch\n enabled: { [key: string]: boolean };\n}\n\ninterface K8sToggleSpec {\n name: string;\n description: string;\n enabled: boolean;\n writeable: boolean;\n source: K8sToggleSource;\n stage: string;\n}\n\ninterface K8sToggleSource {\n namespace: string;\n name: string;\n}\n\ninterface FeatureTogglesAPI {\n getFeatureToggles(): Promise;\n updateFeatureToggles(toggles: FeatureToggle[]): Promise;\n}\n\nclass K8sAPI implements FeatureTogglesAPI {\n baseURL = '/apis/featuretoggle.grafana.app/v0alpha1';\n\n async getFeatureToggles(): Promise {\n const current = await getBackendSrv().get(this.baseURL + '/current');\n return {\n restartRequired: Boolean(current.restartRequired),\n allowEditing: Boolean(current.allowEditing),\n toggles: current.toggles!.map((t) => ({\n name: t.name,\n description: t.description!,\n enabled: t.enabled,\n readOnly: !Boolean(t.writeable),\n stage: t.stage,\n hidden: false, // only return visible things\n })),\n };\n }\n updateFeatureToggles(toggles: FeatureToggle[]): Promise {\n const patchBody: ResolvedToggleState = {\n kind: 'ResolvedToggleState',\n enabled: {},\n };\n toggles.forEach((t) => {\n patchBody.enabled[t.name] = t.enabled;\n });\n return getBackendSrv().patch(this.baseURL + '/current', patchBody);\n }\n}\n\nexport const getTogglesAPI = (): FeatureTogglesAPI => {\n return new K8sAPI();\n};\n","import React, { useState, useRef } from 'react';\n\nimport { Switch, InteractiveTable, Tooltip, type CellProps, Button, ConfirmModal, type SortByFn } from '@grafana/ui';\n\nimport { FeatureToggle, getTogglesAPI } from './AdminFeatureTogglesAPI';\n\ninterface Props {\n featureToggles: FeatureToggle[];\n allowEditing: boolean;\n onUpdateSuccess: () => void;\n}\n\nconst sortByName: SortByFn = (a, b) => {\n return a.original.name.localeCompare(b.original.name);\n};\n\nconst sortByDescription: SortByFn = (a, b) => {\n if (!a.original.description && !b.original.description) {\n return 0;\n } else if (!a.original.description) {\n return 1;\n } else if (!b.original.description) {\n return -1;\n }\n return a.original.description.localeCompare(b.original.description);\n};\n\nconst sortByEnabled: SortByFn = (a, b) => {\n return a.original.enabled === b.original.enabled ? 0 : a.original.enabled ? 1 : -1;\n};\n\nexport function AdminFeatureTogglesTable({ featureToggles, allowEditing, onUpdateSuccess }: Props) {\n // sort manually, doesn't look like it can be automatically done in the table\n featureToggles.sort((a, b) => a.name.localeCompare(b.name));\n const serverToggles = useRef(featureToggles);\n const [localToggles, setLocalToggles] = useState(featureToggles);\n const [isSaving, setIsSaving] = useState(false);\n const [showSaveModel, setShowSaveModal] = useState(false);\n const togglesApi = getTogglesAPI();\n\n const handleToggleChange = (toggle: FeatureToggle, newValue: boolean) => {\n const updatedToggle = { ...toggle, enabled: newValue };\n\n // Update the local state\n const updatedToggles = localToggles.map((t) => (t.name === toggle.name ? updatedToggle : t));\n setLocalToggles(updatedToggles);\n };\n\n const handleSaveChanges = async () => {\n setIsSaving(true);\n try {\n const modifiedToggles = getModifiedToggles();\n await togglesApi.updateFeatureToggles(modifiedToggles);\n // Pretend the values came from a new request\n serverToggles.current = [...localToggles];\n onUpdateSuccess(); // should trigger a new get\n } finally {\n setIsSaving(false);\n }\n };\n\n const saveButtonRef = useRef(null);\n const showSaveChangesModal = (show: boolean) => () => {\n setShowSaveModal(show);\n if (!show && saveButtonRef.current) {\n saveButtonRef.current.focus();\n }\n };\n\n const getModifiedToggles = (): FeatureToggle[] => {\n return localToggles.filter((toggle, index) => toggle.enabled !== serverToggles.current[index].enabled);\n };\n\n const hasModifications = () => {\n // Check if there are any differences between the original toggles and the local toggles\n return localToggles.some((toggle, index) => toggle.enabled !== serverToggles.current[index].enabled);\n };\n\n const getToggleTooltipContent = (readOnlyToggle?: boolean) => {\n if (!allowEditing) {\n return 'Feature management is not configured for editing';\n }\n if (readOnlyToggle) {\n return 'This is a non-editable feature';\n }\n return '';\n };\n\n const getStageCell = (stage: string) => {\n switch (stage) {\n case 'GA':\n return (\n \n
GA
\n
\n );\n case 'privatePreview':\n case 'preview':\n case 'experimental':\n return 'Beta';\n case 'deprecated':\n return 'Deprecated';\n default:\n return stage;\n }\n };\n\n const columns = [\n {\n id: 'name',\n header: 'Name',\n cell: ({ cell: { value } }: CellProps) =>
{value}
,\n sortType: sortByName,\n },\n {\n id: 'description',\n header: 'Description',\n cell: ({ cell: { value } }: CellProps) =>
{value}
,\n sortType: sortByDescription,\n },\n {\n id: 'stage',\n header: 'Stage',\n cell: ({ cell: { value } }: CellProps) =>
{getStageCell(value)}
,\n },\n {\n id: 'enabled',\n header: 'State',\n cell: ({ row }: CellProps) => {\n const renderStateSwitch = (\n
\n handleToggleChange(row.original, e.currentTarget.checked)}\n transparent={row.original.readOnly}\n />\n
\n );\n\n return row.original.readOnly ? (\n {renderStateSwitch}\n ) : (\n renderStateSwitch\n );\n },\n sortType: sortByEnabled,\n },\n ];\n\n return (\n <>\n {allowEditing && (\n
\n \n \n

\n Some features are stable (GA) and enabled by default, whereas some are currently in their preliminary\n Beta phase, available for early adoption.\n

\n

We advise understanding the implications of each feature change before making modifications.

\n
\n }\n confirmText=\"Save changes\"\n onConfirm={async () => {\n showSaveChangesModal(false)();\n handleSaveChanges();\n }}\n onDismiss={showSaveChangesModal(false)}\n />\n \n )}\n featureToggle.name} />\n \n );\n}\n","import { css } from '@emotion/css';\nimport React, { useState } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2, Icon } from '@grafana/ui';\nimport { Page } from 'app/core/components/Page/Page';\n\nimport { getTogglesAPI } from './AdminFeatureTogglesAPI';\nimport { AdminFeatureTogglesTable } from './AdminFeatureTogglesTable';\n\nexport default function AdminFeatureTogglesPage() {\n const [reload, setReload] = useState(1);\n const togglesApi = getTogglesAPI();\n const featureState = useAsync(() => togglesApi.getFeatureToggles(), [reload]);\n const styles = useStyles2(getStyles);\n\n const handleUpdateSuccess = () => {\n setReload(reload + 1);\n };\n\n const EditingAlert = () => {\n return (\n
\n
\n \n
\n \n {featureState.value?.restartRequired\n ? 'A restart is pending for your Grafana instance to apply the latest feature toggle changes'\n : 'Saving feature toggle changes will prompt a restart of the instance, which may take a few minutes'}\n \n
\n );\n };\n\n const subTitle = (\n
\n View and edit feature toggles. Read more about feature toggles at{' '}\n \n grafana.com\n \n .\n
\n );\n\n return (\n \n \n <>\n {featureState.error}\n {featureState.loading && 'Fetching feature toggles'}\n\n \n {featureState.value && (\n \n )}\n \n \n \n );\n}\n\nfunction getStyles(theme: GrafanaTheme2) {\n return {\n warning: css({\n display: 'flex',\n marginTop: theme.spacing(0.25),\n marginBottom: theme.spacing(0.25),\n }),\n icon: css({\n color: theme.colors.warning.main,\n paddingRight: theme.spacing(),\n }),\n message: css({\n color: theme.colors.text.secondary,\n marginTop: theme.spacing(0.25),\n }),\n };\n}\n"],"names":["K8sAPI","current","t","toggles","patchBody","getTogglesAPI","sortByName","a","b","sortByDescription","sortByEnabled","AdminFeatureTogglesTable","featureToggles","allowEditing","onUpdateSuccess","serverToggles","localToggles","setLocalToggles","isSaving","setIsSaving","showSaveModel","setShowSaveModal","togglesApi","handleToggleChange","toggle","newValue","updatedToggle","updatedToggles","handleSaveChanges","modifiedToggles","getModifiedToggles","saveButtonRef","showSaveChangesModal","show","index","hasModifications","getToggleTooltipContent","readOnlyToggle","getStageCell","stage","Tooltip","columns","value","row","renderStateSwitch","Switch","e","Button","ConfirmModal","InteractiveTable","featureToggle","AdminFeatureTogglesPage","reload","setReload","featureState","useAsync","styles","getStyles","handleUpdateSuccess","EditingAlert","Icon","subTitle","Page","theme"],"sourceRoot":""}