import React, { useState, useRef } from 'react'; import { Switch, InteractiveTable, Tooltip, type CellProps, Button, ConfirmModal, type SortByFn } from '@grafana/ui'; import { FeatureToggle, getTogglesAPI } from './AdminFeatureTogglesAPI'; interface Props { featureToggles: FeatureToggle[]; allowEditing: boolean; onUpdateSuccess: () => void; } const sortByName: SortByFn = (a, b) => { return a.original.name.localeCompare(b.original.name); }; const sortByDescription: SortByFn = (a, b) => { if (!a.original.description && !b.original.description) { return 0; } else if (!a.original.description) { return 1; } else if (!b.original.description) { return -1; } return a.original.description.localeCompare(b.original.description); }; const sortByEnabled: SortByFn = (a, b) => { return a.original.enabled === b.original.enabled ? 0 : a.original.enabled ? 1 : -1; }; export function AdminFeatureTogglesTable({ featureToggles, allowEditing, onUpdateSuccess }: Props) { // sort manually, doesn't look like it can be automatically done in the table featureToggles.sort((a, b) => a.name.localeCompare(b.name)); const serverToggles = useRef(featureToggles); const [localToggles, setLocalToggles] = useState(featureToggles); const [isSaving, setIsSaving] = useState(false); const [showSaveModel, setShowSaveModal] = useState(false); const togglesApi = getTogglesAPI(); const handleToggleChange = (toggle: FeatureToggle, newValue: boolean) => { const updatedToggle = { ...toggle, enabled: newValue }; // Update the local state const updatedToggles = localToggles.map((t) => (t.name === toggle.name ? updatedToggle : t)); setLocalToggles(updatedToggles); }; const handleSaveChanges = async () => { setIsSaving(true); try { const modifiedToggles = getModifiedToggles(); await togglesApi.updateFeatureToggles(modifiedToggles); // Pretend the values came from a new request serverToggles.current = [...localToggles]; onUpdateSuccess(); // should trigger a new get } finally { setIsSaving(false); } }; const saveButtonRef = useRef(null); const showSaveChangesModal = (show: boolean) => () => { setShowSaveModal(show); if (!show && saveButtonRef.current) { saveButtonRef.current.focus(); } }; const getModifiedToggles = (): FeatureToggle[] => { return localToggles.filter((toggle, index) => toggle.enabled !== serverToggles.current[index].enabled); }; const hasModifications = () => { // Check if there are any differences between the original toggles and the local toggles return localToggles.some((toggle, index) => toggle.enabled !== serverToggles.current[index].enabled); }; const getToggleTooltipContent = (readOnlyToggle?: boolean) => { if (!allowEditing) { return 'Feature management is not configured for editing'; } if (readOnlyToggle) { return 'This is a non-editable feature'; } return ''; }; const getStageCell = (stage: string) => { switch (stage) { case 'GA': return (
GA
); case 'privatePreview': case 'preview': case 'experimental': return 'Beta'; case 'deprecated': return 'Deprecated'; default: return stage; } }; const columns = [ { id: 'name', header: 'Name', cell: ({ cell: { value } }: CellProps) =>
{value}
, sortType: sortByName, }, { id: 'description', header: 'Description', cell: ({ cell: { value } }: CellProps) =>
{value}
, sortType: sortByDescription, }, { id: 'stage', header: 'Stage', cell: ({ cell: { value } }: CellProps) =>
{getStageCell(value)}
, }, { id: 'enabled', header: 'State', cell: ({ row }: CellProps) => { const renderStateSwitch = (
handleToggleChange(row.original, e.currentTarget.checked)} transparent={row.original.readOnly} />
); return row.original.readOnly ? ( {renderStateSwitch} ) : ( renderStateSwitch ); }, sortType: sortByEnabled, }, ]; return ( <> {allowEditing && (

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

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

} confirmText="Save changes" onConfirm={async () => { showSaveChangesModal(false)(); handleSaveChanges(); }} onDismiss={showSaveChangesModal(false)} /> )} featureToggle.name} /> ); }