Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functionality for updating sections dynamically #542

Merged
merged 22 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
766 changes: 756 additions & 10 deletions provisioning/dashboards/server-based.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/components/ElementSections/ElementSections.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ describe('Form Elements', () => {
};

describe('Render elements', () => {
const sections = [
{ name: 'section1', id: 'section1', expanded: true },
{ name: 'section2', id: 'section2', expanded: true },
];
const options: PanelOptions = {
sync: true,
updateEnabled: UpdateEnabledMode.MANUAL,
Expand Down Expand Up @@ -82,6 +86,7 @@ describe('Form Elements', () => {
render(
getComponent({
options,
sections,
onChangeElement,
initial: { changed: 'bye' },
sectionsExpandedState: { section1: true },
Expand All @@ -98,6 +103,7 @@ describe('Form Elements', () => {
render(
getComponent({
options,
sections,
onChangeElement,
onChangeSectionExpandedState,
initial: { changed: 'bye' },
Expand Down
12 changes: 10 additions & 2 deletions src/components/ElementSections/ElementSections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CollapsableSection } from '@volkovlabs/components';
import React from 'react';

import { LayoutOrientation, SectionVariant, TEST_IDS } from '../../constants';
import { ExecuteCustomCodeParams, LocalFormElement, PanelOptions } from '../../types';
import { ExecuteCustomCodeParams, LayoutSection, LocalFormElement, PanelOptions } from '../../types';
import { FormElements } from '../FormElements';
import { getStyles } from './ElementSections.styles';

Expand Down Expand Up @@ -71,6 +71,13 @@ interface Props {
* @type {string}
*/
timeZone: string;

/**
* Sections
*
* @type {string}
*/
sections: LayoutSection[];
}

/**
Expand All @@ -87,6 +94,7 @@ export const ElementSections: React.FC<Props> = ({
onChangeSectionExpandedState,
executeCustomCode,
timeZone,
sections,
}) => {
/**
* Theme and Styles
Expand All @@ -100,7 +108,7 @@ export const ElementSections: React.FC<Props> = ({
vertical: options.layout.orientation === LayoutOrientation.VERTICAL,
})}
>
{options.layout?.sections?.map((section, id) => {
{sections?.map((section, id) => {
const isOpen = sectionsExpandedState[section.id];

const renderContainer = (children: React.ReactNode) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ describe('Form Elements Editor', () => {
});

/**
* Multi Select
* File
*/
it('Should find component with File', () => {
const elements = [
Expand Down
6 changes: 3 additions & 3 deletions src/components/FormElementsEditor/FormElementsEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Collapse } from '@volkovlabs/components';
import React, { useCallback, useMemo, useState } from 'react';

import { TEST_IDS } from '../../constants';
import { useFormElements } from '../../hooks';
import { useFormLayout } from '../../hooks';
import { FormElement, LayoutSection, LocalFormElement, PanelOptions } from '../../types';
import { getElementUniqueId, reorder } from '../../utils';
import { ElementEditor } from '../ElementEditor';
Expand Down Expand Up @@ -53,8 +53,8 @@ export const FormElementsEditor: React.FC<Props> = ({ value, onChange, context }
onChangeElement,
onChangeElementOption,
onElementRemove,
} = useFormElements({
onChange,
} = useFormLayout({
onChangeElementsOption: onChange,
value,
});

Expand Down
224 changes: 191 additions & 33 deletions src/components/FormPanel/FormPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,197 @@ describe('Panel', () => {
expect(fetchCalledOptions.headers.get('customHeader')).toEqual('123');
});

it('Should add section from the initial code', async () => {
/**
* Render
*/
const replaceVariables = jest.fn((code) => code);

const section = { id: 'section1', name: 'Section 1', expanded: false };

await act(async () =>
render(
getComponent({
props: {
replaceVariables,
},
options: {
sync: false,
initial: {
method: RequestMethod.NONE,
code: `
context.panel.addSections([{name:'Section 2', id:'section2'}]);
`,
},
layout: {
variant: LayoutVariant.SPLIT,
orientation: LayoutOrientation.VERTICAL,
sectionVariant: SectionVariant.COLLAPSABLE,
sections: [section],
},
},
})
)
);

expect(selectors.splitLayoutContent(false, 'Section 1')).toBeInTheDocument();
expect(selectors.splitLayoutContent(false, 'Section 2')).toBeInTheDocument();
});

it('Should remove section from the initial code', async () => {
/**
* Render
*/
const replaceVariables = jest.fn((code) => code);

const section = { id: 'section1', name: 'Section 1', expanded: false };
const section2 = { id: 'section2', name: 'Section 2', expanded: false };

await act(async () =>
render(
getComponent({
props: {
replaceVariables,
},
options: {
sync: false,
initial: {
method: RequestMethod.NONE,
code: `
context.panel.removeSection('section2');
`,
},
layout: {
variant: LayoutVariant.SPLIT,
orientation: LayoutOrientation.VERTICAL,
sectionVariant: SectionVariant.DEFAULT,
sections: [section, section2],
},
},
})
)
);

expect(selectors.splitLayoutContent(false, section.name)).toBeInTheDocument();
expect(selectors.splitLayoutContent(true, section2.name)).not.toBeInTheDocument();
});

it('Should change sections from the initial code', async () => {
/**
* Render
*/
const replaceVariables = jest.fn((code) => code);

const section = { id: 'section1', name: 'Section 1', expanded: false };
const section2 = { id: 'section2', name: 'Section 2', expanded: false };

await act(async () =>
render(
getComponent({
props: {
replaceVariables,
},
options: {
sync: false,
initial: {
method: RequestMethod.NONE,
code: `
context.panel.onChangeSections([{name:'Section 3', id:'section3'}]);
`,
},
layout: {
variant: LayoutVariant.SPLIT,
orientation: LayoutOrientation.VERTICAL,
sectionVariant: SectionVariant.DEFAULT,
sections: [section, section2],
},
},
})
)
);

expect(selectors.splitLayoutContent(true, section.name)).not.toBeInTheDocument();
expect(selectors.splitLayoutContent(true, section2.name)).not.toBeInTheDocument();
expect(selectors.splitLayoutContent(true, 'Section 3')).toBeInTheDocument();
});

it('Should change layout from the initial code', async () => {
/**
* Render
*/
const replaceVariables = jest.fn((code) => code);

const section = { id: 'section1', name: 'Section 1', expanded: false };
const section2 = { id: 'section2', name: 'Section 2', expanded: false };

await act(async () =>
render(
getComponent({
props: {
replaceVariables,
},
options: {
sync: false,
initial: {
method: RequestMethod.NONE,
code: `
context.panel.onChangeLayout([],[{name:'Section 3', id:'section3'}] );
`,
},
layout: {
variant: LayoutVariant.SPLIT,
orientation: LayoutOrientation.VERTICAL,
sectionVariant: SectionVariant.DEFAULT,
sections: [section, section2],
},
},
})
)
);

expect(selectors.splitLayoutContent(true, section.name)).not.toBeInTheDocument();
expect(selectors.splitLayoutContent(true, section2.name)).not.toBeInTheDocument();
expect(selectors.splitLayoutContent(true, 'Section 3')).toBeInTheDocument();
});

it('Should change layout from the initial code with empty elements and not specified sections', async () => {
/**
* Render
*/
const replaceVariables = jest.fn((code) => code);

const section = { id: 'section1', name: 'Section 1', expanded: false };
const section2 = { id: 'section2', name: 'Section 2', expanded: false };

await act(async () =>
render(
getComponent({
props: {
replaceVariables,
},
options: {
sync: false,
initial: {
method: RequestMethod.NONE,
code: `
context.panel.onChangeLayout([]);
`,
},
layout: {
variant: LayoutVariant.SPLIT,
orientation: LayoutOrientation.VERTICAL,
sectionVariant: SectionVariant.DEFAULT,
sections: [section, section2],
},
},
})
)
);

expect(selectors.splitLayoutContent(true, section.name)).not.toBeInTheDocument();
expect(selectors.splitLayoutContent(true, section2.name)).not.toBeInTheDocument();
});

it('Should make initial request once if sync disabled', async () => {
let fetchCalledOptions: any = {};
jest.mocked(fetch).mockImplementationOnce((url, options) => {
Expand Down Expand Up @@ -1285,39 +1476,6 @@ describe('Panel', () => {
expect(fetch).toHaveBeenCalledTimes(2);
});

it('Should make initial request once', async () => {
let fetchCalledOptions: any = {};
jest.mocked(fetch).mockImplementationOnce((url, options) => {
fetchCalledOptions = options;
return Promise.resolve({
json: Promise.resolve({}),
} as any);
});

/**
* Render
*/
await act(async () =>
render(
getComponent({
props: {},
})
)
);

/**
* Check if fetch is called
*/
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith(
'some-url',
expect.objectContaining({
method: RequestMethod.POST,
})
);
expect(fetchCalledOptions.headers.get('customHeader')).toEqual('123');
});

it('Should enable submit from code', async () => {
/**
* Render
Expand Down
Loading
Loading