diff --git a/docs/inputs/index.md b/docs/inputs/index.md
index cd32f4b78..7abceb562 100644
--- a/docs/inputs/index.md
+++ b/docs/inputs/index.md
@@ -11,17 +11,18 @@ provided, a dropdown field will appear on the Inputs page. In contrast, a button
### Properties
-| Property | Type | Description |
-| ------------------------------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| title\* | string | - |
-| description | string | It provides a brief summary of an inputs page. |
-| [subDescription](../advanced/sub_description.md) | object | It provides broader description of an inputs page. |
-| menu | object | This property allows you to enable the [custom menu](../custom_ui_extensions/custom_menu.md) feature. |
-| [table](../table.md) | object | It displays input stanzas in a tabular format. |
-| groupsMenu | array | This property allows you to enable the [multi-level menu](./multilevel_menu.md) feature. |
-| [services](#services-properties)\* | array | It specifies a list of modular inputs. |
-| readonlyFieldId | string | A field of the boolean entity that UCC checks for each input. If the field's value is [truthful](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/ListOfDataTypes), the corresponding input cannot be edited from the UI. There is no way to change this from the UI; it is supposed to be changed via REST. |
-| hideFieldId | string | A field of the boolean entity that UCC checks for each input. If the field's value is [truthful](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/ListOfDataTypes), the corresponding input is hidden from the UI. There is no way to change this from the UI; it is supposed to be changed via REST. Check out an example below. |
+| Property | Type | Description |
+| ------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| title\* | string | - |
+| description | string | It provides a brief summary of an inputs page. |
+| [subDescription](../advanced/sub_description.md) | object | It provides broader description of an inputs page. |
+| menu | object | This property allows you to enable the [custom menu](../custom_ui_extensions/custom_menu.md) feature. |
+| [table](../table.md) | object | It displays input stanzas in a tabular format. |
+| groupsMenu | array | This property allows you to enable the [multi-level menu](./multilevel_menu.md) feature. |
+| [services](#services-properties)\* | array | It specifies a list of modular inputs. |
+| readonlyFieldId | string | A field of the boolean entity that UCC checks for each input. If the field's value is [truthful](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/ListOfDataTypes), the corresponding input cannot be edited from the UI. There is no way to change this from the UI; it is supposed to be changed via REST. |
+| hideFieldId | string | A field of the boolean entity that UCC checks for each input. If the field's value is [truthful](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/ListOfDataTypes), the corresponding input is hidden from the UI. There is no way to change this from the UI; it is supposed to be changed via REST. Check out an example below. |
+| useInputToggleConfirmation | boolean | When true, displays a confirmation modal before toggling an input's status between active and inactive. |
### Services Properties
diff --git a/splunk_add_on_ucc_framework/schema/schema.json b/splunk_add_on_ucc_framework/schema/schema.json
index a99243630..74271bbe4 100644
--- a/splunk_add_on_ucc_framework/schema/schema.json
+++ b/splunk_add_on_ucc_framework/schema/schema.json
@@ -3115,6 +3115,9 @@
},
"readonlyFieldId": {
"type": "string"
+ },
+ "useInputToggleConfirmation": {
+ "$ref": "#/definitions/useInputToggleConfirmation"
}
},
"required": [
@@ -3162,6 +3165,9 @@
"table": {
"$ref": "#/definitions/InputsTable"
},
+ "useInputToggleConfirmation": {
+ "$ref": "#/definitions/useInputToggleConfirmation"
+ },
"entity": {
"$ref": "#/definitions/AnyOfEntity"
},
@@ -3279,6 +3285,11 @@
"type": "string",
"description": "Text displayed next to entity field"
},
+ "useInputToggleConfirmation": {
+ "type": "boolean",
+ "description": "When true displays additional confirmation modal when toggling single input status.",
+ "default": false
+ },
"IntervalEntity": {
"type": "object",
"properties": {
diff --git a/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json b/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json
index 8002ac8db..b6393c616 100644
--- a/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json
+++ b/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json
@@ -387,63 +387,226 @@
"name": "example_input_one",
"description": "This is a description for Input One",
"title": "Example Input",
- "entity": [],
+ "entity": [
+ {
+ "type": "text",
+ "label": "Name",
+ "validators": [
+ {
+ "type": "regex",
+ "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.",
+ "pattern": "^[a-zA-Z]\\w*$"
+ },
+ {
+ "type": "string",
+ "errorMsg": "Length of input name should be between 1 and 100",
+ "minLength": 1,
+ "maxLength": 100
+ }
+ ],
+ "field": "name",
+ "help": "A unique name for the data input.",
+ "required": true
+ },
+ {
+ "type": "interval",
+ "field": "interval",
+ "label": "Interval",
+ "help": "Time interval of the data input, in seconds.",
+ "required": true
+ }
+ ],
"table": {
"actions": [
"edit",
"delete",
"clone"
],
- "header": [],
- "moreInfo": []
+ "header": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ],
+ "moreInfo": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ]
},
"warning": {
- "create": {
- "message": "Warning text for create mode"
- },
- "edit": {
- "message": "Warning text for edit mode"
- },
- "clone": {
- "message": "Warning text for clone mode"
- },
- "config": {
- "message": "Warning text for config mode"
- }
+ "create": {
+ "message": "Warning text for create mode"
+ },
+ "edit": {
+ "message": "Warning text for edit mode"
+ },
+ "clone": {
+ "message": "Warning text for clone mode"
+ },
+ "config": {
+ "message": "Warning text for config mode"
+ }
}
},
{
"name": "example_input_two",
"description": "This is a description for Input Two",
"title": "Example Input Two",
- "entity": [],
+ "entity": [
+ {
+ "type": "text",
+ "label": "Name",
+ "validators": [
+ {
+ "type": "regex",
+ "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.",
+ "pattern": "^[a-zA-Z]\\w*$"
+ },
+ {
+ "type": "string",
+ "errorMsg": "Length of input name should be between 1 and 100",
+ "minLength": 1,
+ "maxLength": 100
+ }
+ ],
+ "field": "name",
+ "help": "A unique name for the data input.",
+ "required": true
+ },
+ {
+ "type": "interval",
+ "field": "interval",
+ "label": "Interval",
+ "help": "Time interval of the data input, in seconds.",
+ "required": true
+ }
+ ],
"table": {
"actions": [
"edit",
"delete",
"clone"
],
- "header": [],
- "moreInfo": [],
+ "header": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ],
+ "moreInfo": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ],
"customRow": {
"type": "external",
"src": "custom_row"
}
- }
+ },
+ "useInputToggleConfirmation": true
},
{
"name": "example_input_three",
"description": "Input hidden for cloud",
"title": "Example Input Three Hidden Cloud",
- "entity": [],
+ "entity": [
+ {
+ "type": "text",
+ "label": "Name",
+ "validators": [
+ {
+ "type": "regex",
+ "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.",
+ "pattern": "^[a-zA-Z]\\w*$"
+ },
+ {
+ "type": "string",
+ "errorMsg": "Length of input name should be between 1 and 100",
+ "minLength": 1,
+ "maxLength": 100
+ }
+ ],
+ "field": "name",
+ "help": "A unique name for the data input.",
+ "required": true
+ },
+ {
+ "type": "interval",
+ "field": "interval",
+ "label": "Interval",
+ "help": "Time interval of the data input, in seconds.",
+ "required": true
+ }
+ ],
"table": {
"actions": [
"edit",
"delete",
"clone"
],
- "header": [],
- "moreInfo": [],
+ "header": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ],
+ "moreInfo": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ],
"customRow": {
"type": "external",
"src": "custom_row"
@@ -455,15 +618,69 @@
"name": "example_input_four",
"description": "Input hidden for enterprise",
"title": "Example Input Four Hidden Enterprise",
- "entity": [],
+ "entity": [
+ {
+ "type": "text",
+ "label": "Name",
+ "validators": [
+ {
+ "type": "regex",
+ "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.",
+ "pattern": "^[a-zA-Z]\\w*$"
+ },
+ {
+ "type": "string",
+ "errorMsg": "Length of input name should be between 1 and 100",
+ "minLength": 1,
+ "maxLength": 100
+ }
+ ],
+ "field": "name",
+ "help": "A unique name for the data input.",
+ "required": true
+ },
+ {
+ "type": "interval",
+ "field": "interval",
+ "label": "Interval",
+ "help": "Time interval of the data input, in seconds.",
+ "required": true
+ }
+ ],
"table": {
"actions": [
"edit",
"delete",
"clone"
],
- "header": [],
- "moreInfo": [],
+ "header": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ],
+ "moreInfo": [
+ {
+ "label": "Name",
+ "field": "name"
+ },
+ {
+ "label": "Interval",
+ "field": "interval"
+ },
+ {
+ "label": "Status",
+ "field": "disabled"
+ }
+ ],
"customRow": {
"type": "external",
"src": "custom_row"
@@ -477,9 +694,9 @@
"meta": {
"name": "Splunk_TA_UCCExample",
"restRoot": "splunk_ta_uccexample",
- "version": "5.50.1+099cf36c",
+ "version": "5.52.0+2e44cba94",
"displayName": "Splunk UCC test Add-on",
- "schemaVersion": "0.0.8",
- "_uccVersion": "5.50.1"
+ "schemaVersion": "0.0.9",
+ "_uccVersion": "5.52.0"
}
}
diff --git a/ui/src/components/table/CustomTable.tsx b/ui/src/components/table/CustomTable.tsx
index 5ac928783..233461fbf 100644
--- a/ui/src/components/table/CustomTable.tsx
+++ b/ui/src/components/table/CustomTable.tsx
@@ -29,6 +29,7 @@ interface CustomTableProps {
sortDir: SortDirection;
sortKey?: string;
tableConfig: ITableConfig;
+ useInputToggleConfirmation?: boolean;
}
interface IEntityModal {
@@ -63,6 +64,7 @@ const CustomTable: React.FC = ({
sortDir,
sortKey,
tableConfig,
+ useInputToggleConfirmation,
}) => {
const unifiedConfigs: GlobalConfig = getUnifiedConfigs();
const [entityModal, setEntityModal] = useState({ open: false });
@@ -263,6 +265,7 @@ const CustomTable: React.FC = ({
rowActions={actions}
headerMapping={headerMapping}
readonly={isReadonlyRow(readonlyFieldId, row)}
+ useInputToggleConfirmation={useInputToggleConfirmation}
{...{
handleEditActionClick,
handleCloneActionClick,
diff --git a/ui/src/components/table/CustomTableRow.tsx b/ui/src/components/table/CustomTableRow.tsx
index bc4511485..daa6a1c5e 100644
--- a/ui/src/components/table/CustomTableRow.tsx
+++ b/ui/src/components/table/CustomTableRow.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement, useCallback } from 'react';
+import React, { ReactElement, useCallback, useState } from 'react';
import WaitSpinner from '@splunk/react-ui/WaitSpinner';
import Switch from '@splunk/react-ui/Switch';
@@ -15,6 +15,7 @@ import { _ } from '@splunk/ui-utils/i18n';
import CustomTableControl from './CustomTableControl';
import { ActionButtonComponent } from './CustomTableStyle';
import { getTableCellValue } from './table.utils';
+import AcceptModal from '../AcceptModal/AcceptModal';
import { RowDataFields } from '../../context/TableContext';
const TableCellWrapper = styled(Table.Cell)`
@@ -40,6 +41,7 @@ interface CustomTableRowProps {
handleEditActionClick: (row: RowDataFields) => void;
handleCloneActionClick: (row: RowDataFields) => void;
handleDeleteActionClick: (row: RowDataFields) => void;
+ useInputToggleConfirmation?: boolean;
}
interface CellHeader {
@@ -57,8 +59,11 @@ function CustomTableRow(props: CustomTableRowProps) {
handleEditActionClick,
handleCloneActionClick,
handleDeleteActionClick,
+ useInputToggleConfirmation,
} = props;
+ const [displayAcceptToggling, setDisplayAcceptToggling] = useState(false);
+
const getCustomCell = (customRow: RowDataFields, header: CellHeader) =>
header.customCell?.src &&
header.customCell?.type &&
@@ -133,6 +138,17 @@ function CustomTableRow(props: CustomTableRowProps) {
[handleEditActionClick, handleCloneActionClick, handleDeleteActionClick]
);
+ const handleAcceptModal = (accepted: boolean) => {
+ if (accepted) {
+ handleToggleActionClick(row);
+ }
+ setDisplayAcceptToggling(false);
+ };
+
+ const verifyToggleActionClick = () => {
+ setDisplayAcceptToggling(true);
+ };
+
let statusContent: string | ReactElement = row.disabled ? 'Inactive' : 'Active';
// eslint-disable-next-line no-underscore-dangle
if (row.__toggleShowSpinner) {
@@ -159,13 +175,25 @@ function CustomTableRow(props: CustomTableRowProps) {
);
} else if (header.field === 'disabled') {
+ const activeText = headerMapping?.disabled?.false
+ ? headerMapping.disabled.false
+ : 'Active';
+
+ const inactiveText = headerMapping?.disabled?.true
+ ? headerMapping.disabled.true
+ : 'Inactive';
+
cellHTML = (
handleToggleActionClick(row)}
+ onClick={() =>
+ useInputToggleConfirmation
+ ? verifyToggleActionClick()
+ : handleToggleActionClick(row)
+ }
selected={!row.disabled}
disabled={
// eslint-disable-next-line no-underscore-dangle
@@ -185,6 +213,20 @@ function CustomTableRow(props: CustomTableRowProps) {
)}
/>
{statusContent}
+ {displayAcceptToggling && (
+
+ )}
);
diff --git a/ui/src/components/table/TableWrapper.tsx b/ui/src/components/table/TableWrapper.tsx
index b2f7c39b4..4abb0f880 100644
--- a/ui/src/components/table/TableWrapper.tsx
+++ b/ui/src/components/table/TableWrapper.tsx
@@ -49,9 +49,9 @@ const getTableConfigAndServices = (
tableConfig: unifiedConfigs.pages.inputs.table,
readonlyFieldId: unifiedConfigs.pages.inputs.readonlyFieldId,
hideFieldId: unifiedConfigs.pages.inputs.hideFieldId,
+ useInputToggleConfirmation: unifiedConfigs.pages.inputs.useInputToggleConfirmation,
};
}
-
const serviceWithTable = services?.find((x) => x.name === serviceName);
const tableData = serviceWithTable && 'table' in serviceWithTable && serviceWithTable.table;
@@ -62,6 +62,10 @@ const getTableConfigAndServices = (
},
readonlyFieldId: undefined,
hideFieldId: undefined,
+ useInputToggleConfirmation:
+ serviceWithTable &&
+ 'useInputToggleConfirmation' in serviceWithTable &&
+ Boolean(serviceWithTable.useInputToggleConfirmation),
};
}
@@ -120,10 +124,11 @@ const TableWrapper: React.FC = ({
useTableContext()!;
const unifiedConfigs = getUnifiedConfigs();
- const { services, tableConfig, readonlyFieldId, hideFieldId } = useMemo(
- () => getTableConfigAndServices(page, unifiedConfigs, serviceName),
- [page, unifiedConfigs, serviceName]
- );
+ const { services, tableConfig, readonlyFieldId, hideFieldId, useInputToggleConfirmation } =
+ useMemo(
+ () => getTableConfigAndServices(page, unifiedConfigs, serviceName),
+ [page, unifiedConfigs, serviceName]
+ );
const moreInfo = tableConfig && 'moreInfo' in tableConfig ? tableConfig?.moreInfo : null;
const headers = tableConfig && 'header' in tableConfig ? tableConfig?.header : null;
@@ -135,6 +140,7 @@ const TableWrapper: React.FC = ({
isComponentMounted.current = false;
};
}, []);
+
useEffect(() => {
const abortController = new AbortController();
@@ -365,6 +371,7 @@ const TableWrapper: React.FC = ({
sortKey={sortKey}
handleOpenPageStyleDialog={handleOpenPageStyleDialog}
tableConfig={tableConfig}
+ useInputToggleConfirmation={useInputToggleConfirmation}
/>
>
);
diff --git a/ui/src/components/table/stories/configMockups.ts b/ui/src/components/table/stories/configMockups.ts
index 507032372..ad514b95f 100644
--- a/ui/src/components/table/stories/configMockups.ts
+++ b/ui/src/components/table/stories/configMockups.ts
@@ -376,3 +376,119 @@ export const getSimpleConfigStylePage = () => {
const configCp = JSON.parse(JSON.stringify(SIMPLE_TABLE_MOCK_DATA_STYLE_PAGE));
return configCp;
};
+
+export const SIMPLE_NAME_TABLE_MOCK_DATA_WITH_STATUS_TOGGLE_CONFIRMATION = {
+ pages: {
+ configuration: {
+ tabs: [
+ {
+ name: 'account',
+ table: {
+ actions: ['edit', 'delete', 'clone'],
+ header: [
+ {
+ label: 'Name',
+ field: 'name',
+ },
+ ],
+ },
+ entity: [
+ {
+ type: 'text',
+ label: 'Name',
+ validators: [
+ {
+ type: 'string',
+ errorMsg: 'Length of ID should be between 1 and 50',
+ minLength: 1,
+ maxLength: 50,
+ },
+ {
+ type: 'regex',
+ errorMsg:
+ 'Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.',
+ pattern: '^[a-zA-Z]\\w*$',
+ },
+ ],
+ field: 'name',
+ help: 'Enter a unique name for this account.',
+ required: true,
+ },
+ ],
+ title: 'Account',
+ restHandlerModule: 'splunk_ta_uccexample_validate_account_rh',
+ restHandlerClass: 'CustomAccountValidator',
+ },
+ ],
+ title: 'Configuration',
+ description: 'Set up your add-on',
+ },
+ inputs: {
+ services: [
+ {
+ name: 'example_input_one',
+ entity: [
+ {
+ type: 'text',
+ label: 'Name',
+ validators: [
+ {
+ type: 'regex',
+ errorMsg:
+ 'Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.',
+ pattern: '^[a-zA-Z]\\w*$',
+ },
+ {
+ type: 'string',
+ errorMsg: 'Length of input name should be between 1 and 100',
+ minLength: 1,
+ maxLength: 100,
+ },
+ ],
+ field: 'name',
+ help: 'A unique name for the data input.',
+ required: true,
+ },
+ {
+ type: 'checkbox',
+ label: 'Example Checkbox',
+ field: 'input_one_checkbox',
+ help: 'This is an example checkbox for the input one entity',
+ defaultValue: true,
+ },
+ ],
+ title: 'Example Input One',
+ },
+ ],
+ title: 'Inputs',
+ description: 'Manage your data inputs',
+ useInputToggleConfirmation: true,
+ table: {
+ actions: ['edit', 'delete', 'search', 'clone'],
+ header: [
+ {
+ label: 'Name',
+ field: 'name',
+ },
+ {
+ label: 'Status',
+ field: 'disabled',
+ },
+ ],
+ moreInfo: [
+ {
+ label: 'Name',
+ field: 'name',
+ },
+ ],
+ },
+ },
+ },
+ meta: {
+ name: 'Splunk_TA_UCCExample',
+ restRoot: 'splunk_ta_uccexample',
+ version: '5.41.0R9c5fbfe0',
+ displayName: 'Splunk UCC test Add-on',
+ schemaVersion: '0.0.3',
+ },
+} satisfies GlobalConfig;
diff --git a/ui/src/components/table/stories/rowDataMockup.ts b/ui/src/components/table/stories/rowDataMockup.ts
index fa52b2a25..1a811c3c1 100644
--- a/ui/src/components/table/stories/rowDataMockup.ts
+++ b/ui/src/components/table/stories/rowDataMockup.ts
@@ -503,6 +503,14 @@ export const MockRowDataForStatusCount = {
messages: [],
};
+export const MockRowDataTogglingResponseDisableTrue = {
+ entry: [{ content: { disabled: true } }],
+};
+
+export const MockRowDataTogglingResponseDisableFalse = {
+ entry: [{ content: { disabled: false } }],
+};
+
export const ServerHandlers = [
http.get(`/servicesNS/nobody/-/splunk_ta_uccexample_account`, () =>
HttpResponse.json(MockRowData)
diff --git a/ui/src/components/table/tests/CustomTableRowConfirmation.test.tsx b/ui/src/components/table/tests/CustomTableRowConfirmation.test.tsx
new file mode 100644
index 000000000..1d63bd705
--- /dev/null
+++ b/ui/src/components/table/tests/CustomTableRowConfirmation.test.tsx
@@ -0,0 +1,152 @@
+import { render, screen, within } from '@testing-library/react';
+import React from 'react';
+import userEvent from '@testing-library/user-event';
+
+import { BrowserRouter } from 'react-router-dom';
+import { http, HttpResponse } from 'msw';
+import { TableContextProvider } from '../../../context/TableContext';
+import { server } from '../../../mocks/server';
+import { setUnifiedConfig } from '../../../util/util';
+import { SIMPLE_NAME_TABLE_MOCK_DATA_WITH_STATUS_TOGGLE_CONFIRMATION } from '../stories/configMockups';
+import {
+ MockRowData,
+ MockRowDataTogglingResponseDisableFalse,
+ MockRowDataTogglingResponseDisableTrue,
+} from '../stories/rowDataMockup';
+import TableWrapper, { ITableWrapperProps } from '../TableWrapper';
+import { invariant } from '../../../util/invariant';
+
+beforeEach(() => {
+ const props = {
+ page: 'inputs',
+ serviceName: 'example_input_one',
+ handleRequestModalOpen: jest.fn(),
+ handleOpenPageStyleDialog: jest.fn(),
+ displayActionBtnAllRows: false,
+ } satisfies ITableWrapperProps;
+
+ server.use(
+ http.get('/servicesNS/nobody/-/splunk_ta_uccexample_example_input_one', () =>
+ HttpResponse.json(MockRowData)
+ )
+ );
+
+ setUnifiedConfig(SIMPLE_NAME_TABLE_MOCK_DATA_WITH_STATUS_TOGGLE_CONFIRMATION);
+
+ render(
+
+
+ ,
+ { wrapper: BrowserRouter }
+ );
+});
+
+const getRowData = (isDisabled: boolean) => {
+ const active = MockRowData.entry.find(
+ (entry) => entry.content.disabled === isDisabled // api mocks are created for aaaaaa entity
+ );
+ return active;
+};
+
+const serverUseDisabledForEntity = (entity: string, isDisabledTrue: boolean) => {
+ server.use(
+ http.post(`/servicesNS/nobody/-/splunk_ta_uccexample_example_input_one/${entity}`, () =>
+ HttpResponse.json(
+ isDisabledTrue
+ ? MockRowDataTogglingResponseDisableTrue
+ : MockRowDataTogglingResponseDisableFalse
+ )
+ )
+ );
+};
+
+const getRowElements = async (isDisabled: boolean) => {
+ const activeRowData = getRowData(isDisabled);
+ invariant(activeRowData, 'Active row not found');
+ const activeRow = await screen.findByLabelText(`row-${activeRowData?.name}`);
+
+ const statusCell = within(activeRow).getByTestId('status');
+
+ const statusToggle = within(activeRow).getByRole('switch');
+
+ return { activeRowData, activeRow, statusCell, statusToggle };
+};
+
+it('Status toggling with acceptance model - displayed correctly', async () => {
+ const { activeRowData, statusToggle } = await getRowElements(false);
+
+ await userEvent.click(statusToggle);
+
+ const acceptModal = await screen.findByRole('dialog', { name: /Make input Inactive?/i });
+
+ screen.getByText(`Do you want to make ${activeRowData?.name} input Inactive?`);
+
+ screen.getByRole('button', { name: 'Yes' });
+ const noBtn = screen.getByRole('button', { name: 'No' });
+
+ await userEvent.click(noBtn);
+
+ expect(acceptModal).not.toBeInTheDocument();
+});
+
+it('Status toggling with acceptance model - toggles state', async () => {
+ const { activeRowData, statusCell, statusToggle } = await getRowElements(false);
+
+ expect(statusCell).toHaveTextContent('Active');
+
+ serverUseDisabledForEntity(activeRowData.name, true);
+
+ await userEvent.click(statusToggle);
+
+ await screen.findByRole('dialog', { name: 'Make input Inactive?' });
+
+ const yesBtn = await screen.findByRole('button', { name: 'Yes' });
+ await userEvent.click(yesBtn);
+
+ expect(statusCell).toHaveTextContent('Inactive');
+
+ serverUseDisabledForEntity(activeRowData.name, false);
+
+ await userEvent.click(statusToggle);
+
+ await screen.findByRole('dialog', { name: 'Make input Active?' });
+
+ const yesBtn2 = await screen.findByRole('button', { name: 'Yes' });
+ await userEvent.click(yesBtn2);
+
+ expect(statusCell).toHaveTextContent('Active');
+});
+
+it('Status toggling with acceptance model - decline modal still Active', async () => {
+ const { activeRowData, statusCell, statusToggle } = await getRowElements(false);
+
+ expect(statusCell).toHaveTextContent('Active');
+
+ serverUseDisabledForEntity(activeRowData.name, true);
+
+ await userEvent.click(statusToggle);
+
+ await screen.findByRole('dialog', { name: 'Make input Inactive?' });
+
+ const noBtn = await screen.findByRole('button', { name: 'No' });
+ await userEvent.click(noBtn);
+
+ expect(statusCell).toHaveTextContent('Active');
+});
+
+it('Status toggling with acceptance model - decline modal still Inactive', async () => {
+ const { activeRowData, statusCell, statusToggle } = await getRowElements(true);
+
+ expect(statusCell).toHaveTextContent('Inactive');
+
+ serverUseDisabledForEntity(activeRowData.name, true);
+
+ await userEvent.click(statusToggle);
+
+ await screen.findByRole('dialog', { name: 'Make input Active?' });
+
+ const noBtn = await screen.findByRole('button', { name: 'No' });
+ await userEvent.click(noBtn);
+
+ expect(statusCell).toHaveTextContent('Inactive');
+});
diff --git a/ui/src/context/TableContext.tsx b/ui/src/context/TableContext.tsx
index 027fa333c..1416aa047 100644
--- a/ui/src/context/TableContext.tsx
+++ b/ui/src/context/TableContext.tsx
@@ -8,6 +8,7 @@ export type RowDataFields = {
disabled?: boolean;
id?: string;
index?: string;
+ __toggleShowSpinner?: boolean;
} & AcceptableFormRecord;
// serviceName > specificRowName > dataForRow
diff --git a/ui/src/types/globalConfig/pages.ts b/ui/src/types/globalConfig/pages.ts
index b8539d2e1..5fdf3bc84 100644
--- a/ui/src/types/globalConfig/pages.ts
+++ b/ui/src/types/globalConfig/pages.ts
@@ -96,10 +96,13 @@ export const TableLessServiceSchema = z.object({
inputHelperModule: z.string().optional(),
hideForPlatform: z.enum(['cloud', 'enterprise']).optional(),
});
+
export const TableFullServiceSchema = TableLessServiceSchema.extend({
description: z.string().optional(),
table: TableSchema,
+ useInputToggleConfirmation: z.boolean().optional(),
});
+
export const InputsPageRegular = z
.object({
title: z.string(),
@@ -149,6 +152,7 @@ export const InputsPageTableSchema = z
services: z.array(TableLessServiceSchema.strict()),
hideFieldId: z.string().optional(),
readonlyFieldId: z.string().optional(),
+ useInputToggleConfirmation: z.boolean().optional(),
})
.strict();