From e228debe08e4819627aec50609460e3481cc5957 Mon Sep 17 00:00:00 2001 From: Jan-Gerke Salomon Date: Tue, 3 Aug 2021 11:22:23 +0200 Subject: [PATCH] docs(organisation unit tree): add story for custom request data --- .../src/__stories__/collapsed.js | 9 + .../src/__stories__/custom-node-label.js | 23 + .../src/__stories__/custom-requests.js | 107 ++++ .../src/__stories__/customData.js | 107 ++++ .../src/__stories__/dx-multi-selection.js | 5 + .../src/__stories__/dx-no-selection.js | 5 + .../src/__stories__/dx-single-selection.js | 5 + .../src/__stories__/dx-with-real-backend.js | 42 ++ .../src/__stories__/dx-wrapper.js | 40 ++ .../src/__stories__/expanded.js | 10 + .../src/__stories__/filtered-root.js | 13 + .../src/__stories__/filtered.js | 11 + .../src/__stories__/force-reload-all.js | 44 ++ .../src/__stories__/force-reload-one-unit.js | 35 ++ .../src/__stories__/highlighted.js | 11 + .../src/__stories__/indeterminate.js | 11 + .../__stories__/loading-error-grandchild.js | 29 + .../src/__stories__/loading.js | 26 + .../src/__stories__/multiple-roots.js | 12 + .../src/__stories__/no-selection.js | 14 + .../src/__stories__/replace-roots.js | 28 + .../src/__stories__/root-error.js | 35 ++ .../src/__stories__/root-loading.js | 33 + .../src/__stories__/selected-multiple.js | 16 + .../src/__stories__/single-selection.js | 14 + .../organisation-unit-tree/src/index.js | 2 + .../organisation-unit-tree-connected/index.js | 2 + .../src/organisation-unit-tree.stories.js | 583 ++---------------- 28 files changed, 736 insertions(+), 536 deletions(-) create mode 100644 components/organisation-unit-tree/src/__stories__/collapsed.js create mode 100644 components/organisation-unit-tree/src/__stories__/custom-node-label.js create mode 100644 components/organisation-unit-tree/src/__stories__/custom-requests.js create mode 100644 components/organisation-unit-tree/src/__stories__/customData.js create mode 100644 components/organisation-unit-tree/src/__stories__/dx-multi-selection.js create mode 100644 components/organisation-unit-tree/src/__stories__/dx-no-selection.js create mode 100644 components/organisation-unit-tree/src/__stories__/dx-single-selection.js create mode 100644 components/organisation-unit-tree/src/__stories__/dx-with-real-backend.js create mode 100644 components/organisation-unit-tree/src/__stories__/dx-wrapper.js create mode 100644 components/organisation-unit-tree/src/__stories__/expanded.js create mode 100644 components/organisation-unit-tree/src/__stories__/filtered-root.js create mode 100644 components/organisation-unit-tree/src/__stories__/filtered.js create mode 100644 components/organisation-unit-tree/src/__stories__/force-reload-all.js create mode 100644 components/organisation-unit-tree/src/__stories__/force-reload-one-unit.js create mode 100644 components/organisation-unit-tree/src/__stories__/highlighted.js create mode 100644 components/organisation-unit-tree/src/__stories__/indeterminate.js create mode 100644 components/organisation-unit-tree/src/__stories__/loading-error-grandchild.js create mode 100644 components/organisation-unit-tree/src/__stories__/loading.js create mode 100644 components/organisation-unit-tree/src/__stories__/multiple-roots.js create mode 100644 components/organisation-unit-tree/src/__stories__/no-selection.js create mode 100644 components/organisation-unit-tree/src/__stories__/replace-roots.js create mode 100644 components/organisation-unit-tree/src/__stories__/root-error.js create mode 100644 components/organisation-unit-tree/src/__stories__/root-loading.js create mode 100644 components/organisation-unit-tree/src/__stories__/selected-multiple.js create mode 100644 components/organisation-unit-tree/src/__stories__/single-selection.js diff --git a/components/organisation-unit-tree/src/__stories__/collapsed.js b/components/organisation-unit-tree/src/__stories__/collapsed.js new file mode 100644 index 0000000000..a66db8af92 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/collapsed.js @@ -0,0 +1,9 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const Collapsed = () => ( + +) diff --git a/components/organisation-unit-tree/src/__stories__/custom-node-label.js b/components/organisation-unit-tree/src/__stories__/custom-node-label.js new file mode 100644 index 0000000000..6f6f06c42f --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/custom-node-label.js @@ -0,0 +1,23 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const CustomNodeLabel = () => ( + { + if (data.node.path !== '/A0000000000/A0000000001') { + return OrganisationUnitTree.defaultProps.renderNodeLabel(data) + } + + return OrganisationUnitTree.defaultProps.renderNodeLabel({ + ...data, + node: { + ...data.node, + displayName: --- {data.node.displayName}, + }, + }) + }} + /> +) diff --git a/components/organisation-unit-tree/src/__stories__/custom-requests.js b/components/organisation-unit-tree/src/__stories__/custom-requests.js new file mode 100644 index 0000000000..57d05761b6 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/custom-requests.js @@ -0,0 +1,107 @@ +/* eslint-disable react/no-unescaped-entities */ +import { CustomDataProvider, useDataEngine } from '@dhis2/app-runtime' +import React from 'react' +import { + OrganisationUnitTreeControllable, + useFetchOrgData, + useFetchRootOrgData, +} from '../index.js' +import { customData } from './customData.js' + +const customDataWithApprovals = { + ...customData, + 'dataApprovals/approvals': (type, { params }) => { + return [ + { + wf: params.wf, + pe: params.pe, + ou: params.ou, + aoc: "aocUID", + state: "ACCEPTED_HERE", + level: "KaTJLhGmU95", + permissions: { + mayApprove: true, + mayUnapprove: true, + mayAccept: false, + mayUnaccept: true, + mayReadData: true + } + } + ] + }, +} + +export const CustomRequests = () => { + const engine = useDataEngine() + const fetchOrgData = useFetchOrgData() + const fetchRootOrgData = useFetchRootOrgData() + + const fetchOrgDataWithApprovalStatus = async args => { + const { id } = args + + const [approvalStatusResponse, origResponse] = await Promise.all([ + await engine.query({ + approvalStatuses: { + resource: 'dataApprovals/approvals', + params: { + wf: 'rIUL4hYOjJc', + pe: '202101', + ou: id, + } + } + }), + await fetchOrgData(args), + ]) + + const nextData = { ...approvalStatusResponse, ...origResponse } + return nextData + } + + return ( + { + if (data.loading) { + return OrganisationUnitTreeControllable + .defaultProps + .renderNodeLabel(data) + } + + const { approvalStatuses } = data.additional + const [approvalStatus] = approvalStatuses + const { permissions } = approvalStatus + const { mayApprove } = permissions + + const formatted = { + ...data, + node: { + ...data.node, + displayName: ( + + {data.node.displayName} + {' '} + (mayApprove: {' '}{mayApprove.toString()}) + + ) + } + } + + return OrganisationUnitTreeControllable + .defaultProps + .renderNodeLabel(formatted) + }} + /> + ) +} + +CustomRequests.decorators = [ + Story => ( + + + + ), +] diff --git a/components/organisation-unit-tree/src/__stories__/customData.js b/components/organisation-unit-tree/src/__stories__/customData.js new file mode 100644 index 0000000000..5d382b49fd --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/customData.js @@ -0,0 +1,107 @@ +export const customData = { + organisationUnits: (...args) => { + const [, { id }] = args + + let data, + delay = 0 + + if (id === 'A0000000000') { + delay = 1000 + data = { + id: 'A0000000000', + path: '/A0000000000', + displayName: 'Org Unit 1', + children: [ + { + id: 'A0000000001', + path: '/A0000000000/A0000000001', + children: [ + { id: 'A0000000003' }, + { id: 'A0000000004' }, + ], + displayName: 'Org Unit 2', + }, + { + id: 'A0000000002', + path: '/A0000000000/A0000000002', + children: [], + displayName: 'Org Unit 3', + }, + { + id: 'A0000000006', + path: '/A0000000000/A0000000006', + children: [], + displayName: 'Org Unit 7', + }, + ], + } + } + + if (id === 'A0000000001') { + data = { + id: 'A0000000001', + path: '/A0000000000/A0000000001', + displayName: 'Org Unit 2', + children: [ + { + id: 'A0000000003', + path: '/A0000000000/A0000000001/A0000000003', + children: [], + displayName: 'Org Unit 4', + }, + { + id: 'A0000000004', + path: '/A0000000000/A0000000001/A0000000004', + children: [], + displayName: 'Org Unit 5', + }, + ], + } + } + + if (id === 'A0000000002') { + delay = 1000 + data = { + displayName: 'Org Unit 3', + id: 'A0000000002', + path: '/A0000000000/A0000000002', + children: [], + } + } + + if (id === 'A0000000003') { + data = { + displayName: 'Org Unit 4', + id: 'A0000000003', + path: '/A0000000000/A0000000001/A0000000003', + children: [], + } + } + + if (id === 'A0000000004') { + data = { + displayName: 'Org Unit 5', + id: 'A0000000004', + path: '/A0000000000/A0000000001/A0000000004', + children: [], + } + } + + if (id === 'A0000000006') { + data = { + displayName: 'Org Unit 7', + id: 'A0000000006', + path: '/A0000000000/A0000000006', + children: [], + } + } + + if (!data) { + return Promise.reject(new Error('404 - Org unit not found')) + } + + return new Promise(resolve => { + setTimeout(() => resolve(data), delay) + }) + }, +} diff --git a/components/organisation-unit-tree/src/__stories__/dx-multi-selection.js b/components/organisation-unit-tree/src/__stories__/dx-multi-selection.js new file mode 100644 index 0000000000..4d4770eca3 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/dx-multi-selection.js @@ -0,0 +1,5 @@ +import React from 'react' +import { Wrapper } from './dx-wrapper.js' + +export const DxMultiSelection = () => +DxMultiSelection.storyName = 'DX: Multi selection' diff --git a/components/organisation-unit-tree/src/__stories__/dx-no-selection.js b/components/organisation-unit-tree/src/__stories__/dx-no-selection.js new file mode 100644 index 0000000000..b92e511cb9 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/dx-no-selection.js @@ -0,0 +1,5 @@ +import React from 'react' +import { Wrapper } from './dx-wrapper.js' + +export const DxNoSelection = () => +DxNoSelection.storyName = 'DX: No selection' diff --git a/components/organisation-unit-tree/src/__stories__/dx-single-selection.js b/components/organisation-unit-tree/src/__stories__/dx-single-selection.js new file mode 100644 index 0000000000..0bfad6c43f --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/dx-single-selection.js @@ -0,0 +1,5 @@ +import React from 'react' +import { Wrapper } from './dx-wrapper.js' + +export const DxSingleSelection = () => +DxSingleSelection.storyName = 'DX: Single selection' diff --git a/components/organisation-unit-tree/src/__stories__/dx-with-real-backend.js b/components/organisation-unit-tree/src/__stories__/dx-with-real-backend.js new file mode 100644 index 0000000000..fe602e175a --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/dx-with-real-backend.js @@ -0,0 +1,42 @@ +import { DataProvider } from '@dhis2/app-runtime' +import React from 'react' +import { Wrapper } from './dx-wrapper.js' + +export const DxWithRealBackend = () => ( +
+
+ + This story doesn't work on netlify for some reason, just + run it locally. + +
+ You need to log in to{' '} + + https://debug.dhis2.org/dev + +
+ Make sure the{' '} + localhost:[PORT] is part + of the accepted list:{' '} + + Settings app / Access + +
+ + + +
+) +DxWithRealBackend.storyName = 'DX: With real backend' diff --git a/components/organisation-unit-tree/src/__stories__/dx-wrapper.js b/components/organisation-unit-tree/src/__stories__/dx-wrapper.js new file mode 100644 index 0000000000..07b7e526c2 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/dx-wrapper.js @@ -0,0 +1,40 @@ +/* eslint-disable react/no-unescaped-entities,react/prop-types */ +import React, { useState } from 'react' +import { OrganisationUnitTree } from '../index.js' + +const DX_onChange = (selected, setSelected, singleSelection) => ({ + id, + path, + checked, +}) => { + console.log('onChange', { path, id, checked }) + const pathIndex = selected.indexOf(path) + + if (checked) { + setSelected(singleSelection ? [path] : [...selected, path]) + } else { + setSelected( + singleSelection + ? [] + : [ + ...selected.slice(0, pathIndex), + ...selected.slice(pathIndex + 1), + ] + ) + } +} + +export const Wrapper = props => { + const [selected, setSelected] = useState([]) + + return ( + + ) +} diff --git a/components/organisation-unit-tree/src/__stories__/expanded.js b/components/organisation-unit-tree/src/__stories__/expanded.js new file mode 100644 index 0000000000..751f786423 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/expanded.js @@ -0,0 +1,10 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const Expanded = () => ( + +) diff --git a/components/organisation-unit-tree/src/__stories__/filtered-root.js b/components/organisation-unit-tree/src/__stories__/filtered-root.js new file mode 100644 index 0000000000..11b575f534 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/filtered-root.js @@ -0,0 +1,13 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const FilteredRoot = () => ( + +) + +FilteredRoot.storyName = 'Filtered (root)' diff --git a/components/organisation-unit-tree/src/__stories__/filtered.js b/components/organisation-unit-tree/src/__stories__/filtered.js new file mode 100644 index 0000000000..bc36fd0c1d --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/filtered.js @@ -0,0 +1,11 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const Filtered = () => ( + +) diff --git a/components/organisation-unit-tree/src/__stories__/force-reload-all.js b/components/organisation-unit-tree/src/__stories__/force-reload-all.js new file mode 100644 index 0000000000..bb55e817ed --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/force-reload-all.js @@ -0,0 +1,44 @@ +import { Button } from '@dhis2-ui/button' +import React, { useState } from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const ForceReloadAll = () => { + const [forceReload, _setForceReload] = useState(false) + const setForceReload = v => + console.log('setForceReload', v) || _setForceReload(v) + + return ( + <> + {' '} + (Force reload: {forceReload ? 'true' : 'false'}) +
+ { + const { id } = data + if (id === 'A0000000000') { + setForceReload(false) + } + }} + /> +
+ + + ) +} + +ForceReloadAll.storyName = 'Force reload all' diff --git a/components/organisation-unit-tree/src/__stories__/force-reload-one-unit.js b/components/organisation-unit-tree/src/__stories__/force-reload-one-unit.js new file mode 100644 index 0000000000..f269d94c59 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/force-reload-one-unit.js @@ -0,0 +1,35 @@ +import React from 'react' + +export const ForceReloadOneUnit = () => { + return ( +

+ This is currently not working due to limitations of the data engine + in the app runtime. +

+ ) + + //const [idsThatShouldBeReloaded, setIdsThatShouldBeReloaded] = useState([]) + + //useEffect(() => { + // setTimeout(() => setIdsThatShouldBeReloaded(['A0000000001']), delay) + //}, []) + + //return ( + // + // console.log( + // `Unit with path "${path}" loaded, was forced: ${ + // forced ? 'yes' : 'no' + // }` + // ) + // } + // /> + //) +} +ForceReloadOneUnit.storyName = 'Force reload one unit' diff --git a/components/organisation-unit-tree/src/__stories__/highlighted.js b/components/organisation-unit-tree/src/__stories__/highlighted.js new file mode 100644 index 0000000000..f9a13538fc --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/highlighted.js @@ -0,0 +1,11 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const Highlighted = () => ( + +) diff --git a/components/organisation-unit-tree/src/__stories__/indeterminate.js b/components/organisation-unit-tree/src/__stories__/indeterminate.js new file mode 100644 index 0000000000..81a0f5beee --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/indeterminate.js @@ -0,0 +1,11 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const Indeterminate = () => ( + +) diff --git a/components/organisation-unit-tree/src/__stories__/loading-error-grandchild.js b/components/organisation-unit-tree/src/__stories__/loading-error-grandchild.js new file mode 100644 index 0000000000..de74c129eb --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/loading-error-grandchild.js @@ -0,0 +1,29 @@ +import { CustomDataProvider } from '@dhis2/app-runtime' +import React from 'react' +import { OrganisationUnitTree } from '../index.js' +import { customData } from './customData.js' + +export const LoadingErrorGrandchild = () => ( + { + const [, { id }] = args + if (id === 'A0000000003') { + return Promise.reject('Loading org unit 4 and 5 failed') + } + + return customData.organisationUnits(...args) + }, + }} + > + + +) + +LoadingErrorGrandchild.storyName = 'Loading error grandchild' diff --git a/components/organisation-unit-tree/src/__stories__/loading.js b/components/organisation-unit-tree/src/__stories__/loading.js new file mode 100644 index 0000000000..38b37ccd06 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/loading.js @@ -0,0 +1,26 @@ +import { CustomDataProvider } from '@dhis2/app-runtime' +import React from 'react' +import { OrganisationUnitTree } from '../index.js' +import { customData } from './customData.js' + +export const Loading = () => ( + { + const [, { id }] = args + if (id === 'A0000000001') { + return new Promise(() => null) + } + + return customData.organisationUnits(...args) + }, + }} + > + + +) diff --git a/components/organisation-unit-tree/src/__stories__/multiple-roots.js b/components/organisation-unit-tree/src/__stories__/multiple-roots.js new file mode 100644 index 0000000000..09b5553658 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/multiple-roots.js @@ -0,0 +1,12 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const MultipleRoots = () => ( + +) + +MultipleRoots.storyName = 'Multiple roots' diff --git a/components/organisation-unit-tree/src/__stories__/no-selection.js b/components/organisation-unit-tree/src/__stories__/no-selection.js new file mode 100644 index 0000000000..e374d9bd49 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/no-selection.js @@ -0,0 +1,14 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const NoSelection = () => ( + +) + +NoSelection.storyName = 'No selection' diff --git a/components/organisation-unit-tree/src/__stories__/replace-roots.js b/components/organisation-unit-tree/src/__stories__/replace-roots.js new file mode 100644 index 0000000000..4fb37d5d24 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/replace-roots.js @@ -0,0 +1,28 @@ +import React from 'react' + +export const ReplaceRoots = () => { + return ( +

+ This is currently not working due to limitations of the data engine + in the app runtime. Normally the root unit would've been replaced + after 2000 milliseconds. +

+ ) + + //const [roots, setRoots] = useState(['A0000000000']) + + //useEffect(() => { + // setTimeout(() => setRoots(['A0000000001']), 2000) + //}, []) + + //return ( + // + //) +} + +ReplaceRoots.storyName = 'Replace roots' diff --git a/components/organisation-unit-tree/src/__stories__/root-error.js b/components/organisation-unit-tree/src/__stories__/root-error.js new file mode 100644 index 0000000000..711f2fdb56 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/root-error.js @@ -0,0 +1,35 @@ +import { CustomDataProvider } from '@dhis2/app-runtime' +import React from 'react' +import { OrganisationUnitTree } from '../index.js' +import { customData } from './customData.js' + +export const RootError = () => ( + { + const [, { id }] = args + if (id === 'A0000000000') { + return Promise.reject( + 'This is a custom error message, it could be anything' + ) + } + + return customData.organisationUnits(...args) + }, + }} + > +
+ + Custom container (max-width: 600px) + + +
+
+) + +RootError.storyName = 'Root error' diff --git a/components/organisation-unit-tree/src/__stories__/root-loading.js b/components/organisation-unit-tree/src/__stories__/root-loading.js new file mode 100644 index 0000000000..354286cba7 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/root-loading.js @@ -0,0 +1,33 @@ +import { CustomDataProvider } from '@dhis2/app-runtime' +import React from 'react' +import { OrganisationUnitTree } from '../index.js' +import { customData } from './customData.js' + +export const RootLoading = () => ( + { + const [, { id }] = args + if (id === 'A0000000000') { + return new Promise(() => null) + } + + return customData.organisationUnits(...args) + }, + }} + > +
+ + Custom container (max-width: 600px) + + +
+
+) + +RootLoading.storyName = 'Root loading' diff --git a/components/organisation-unit-tree/src/__stories__/selected-multiple.js b/components/organisation-unit-tree/src/__stories__/selected-multiple.js new file mode 100644 index 0000000000..2bccb3b1bf --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/selected-multiple.js @@ -0,0 +1,16 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const SelectedMultiple = () => ( + +) + +SelectedMultiple.storyName = 'Selected multiple' diff --git a/components/organisation-unit-tree/src/__stories__/single-selection.js b/components/organisation-unit-tree/src/__stories__/single-selection.js new file mode 100644 index 0000000000..ec6e0d7fe2 --- /dev/null +++ b/components/organisation-unit-tree/src/__stories__/single-selection.js @@ -0,0 +1,14 @@ +import React from 'react' +import { OrganisationUnitTree } from '../index.js' + +export const SingleSelection = () => ( + +) + +SingleSelection.storyName = 'Single selection' diff --git a/components/organisation-unit-tree/src/index.js b/components/organisation-unit-tree/src/index.js index 1a276b6bae..6070e8b4a0 100644 --- a/components/organisation-unit-tree/src/index.js +++ b/components/organisation-unit-tree/src/index.js @@ -3,4 +3,6 @@ export { } from './organisation-unit-tree/index.js' export { OrganisationUnitTreeConnected as OrganisationUnitTree, + useFetchOrgData, + useFetchRootOrgData, } from './organisation-unit-tree-connected/index.js' diff --git a/components/organisation-unit-tree/src/organisation-unit-tree-connected/index.js b/components/organisation-unit-tree/src/organisation-unit-tree-connected/index.js index c4524cd400..c16a32dfe0 100644 --- a/components/organisation-unit-tree/src/organisation-unit-tree-connected/index.js +++ b/components/organisation-unit-tree/src/organisation-unit-tree-connected/index.js @@ -1 +1,3 @@ export { OrganisationUnitTreeConnected } from './organisation-unit-tree-connected.js' +export { useFetchOrgData } from './use-fetch-org-data/use-fetch-org-data.js' +export { useFetchRootOrgData } from './use-fetch-root-org-data/use-fetch-root-org-data.js' diff --git a/components/organisation-unit-tree/src/organisation-unit-tree.stories.js b/components/organisation-unit-tree/src/organisation-unit-tree.stories.js index 17f0824d1d..9acb984972 100644 --- a/components/organisation-unit-tree/src/organisation-unit-tree.stories.js +++ b/components/organisation-unit-tree/src/organisation-unit-tree.stories.js @@ -1,8 +1,9 @@ /* eslint-disable react/no-unescaped-entities */ -import { Button } from '@dhis2-ui/button' -import { CustomDataProvider, DataProvider } from '@dhis2/app-runtime' -import React, { useState } from 'react' -import { OrganisationUnitTree } from './index.js' +import { CustomDataProvider } from '@dhis2/app-runtime' +import PropTypes from 'prop-types' +import React from 'react' +import { customData } from './__stories__/customData.js' +import { OrganisationUnitTree, OrganisationUnitTreeControllable } from './index.js' const subtitle = 'Display, manipulate and select organization units displayed in a hierarchical tree' @@ -34,218 +35,29 @@ const orgUnitTree = ( ` -const log = true +const log = false + const onChange = (...args) => log && console.log('onChange', ...args) +OrganisationUnitTree.propTypes.onChange = PropTypes.func +OrganisationUnitTree.defaultProps.onChange = onChange +OrganisationUnitTreeControllable.propTypes.onChange = PropTypes.func +OrganisationUnitTreeControllable.defaultProps.onChange = onChange + const onExpand = (...args) => log && console.log('onExpand', ...args) +OrganisationUnitTree.defaultProps.onExpand = onExpand +OrganisationUnitTreeControllable.propTypes.onExpand = PropTypes.func +OrganisationUnitTreeControllable.defaultProps.onExpand = onExpand + const onCollapse = (...args) => log && console.log('onCollapse', ...args) +OrganisationUnitTree.defaultProps.onCollapse = onCollapse +OrganisationUnitTreeControllable.propTypes.onCollapse = PropTypes.func +OrganisationUnitTreeControllable.defaultProps.onCollapse = onCollapse + const onChildrenLoaded = (...args) => log && console.log('onChildrenLoaded', ...args) - -const customData = { - organisationUnits: (...args) => { - const [, { id }] = args - - let data, - delay = 0 - - if (id === 'A0000000000') { - delay = 1000 - data = { - id: 'A0000000000', - path: '/A0000000000', - displayName: 'Org Unit 1', - children: [ - { - id: 'A0000000001', - path: '/A0000000000/A0000000001', - children: [ - { id: 'A0000000003' }, - { id: 'A0000000004' }, - ], - displayName: 'Org Unit 2', - }, - { - id: 'A0000000002', - path: '/A0000000000/A0000000002', - children: [], - displayName: 'Org Unit 3', - }, - { - id: 'A0000000006', - path: '/A0000000000/A0000000006', - children: [], - displayName: 'Org Unit 7', - }, - ], - } - } - - if (id === 'A0000000001') { - data = { - id: 'A0000000001', - path: '/A0000000000/A0000000001', - displayName: 'Org Unit 2', - children: [ - { - id: 'A0000000003', - path: '/A0000000000/A0000000001/A0000000003', - children: [], - displayName: 'Org Unit 4', - }, - { - id: 'A0000000004', - path: '/A0000000000/A0000000001/A0000000004', - children: [], - displayName: 'Org Unit 5', - }, - ], - } - } - - if (id === 'A0000000002') { - delay = 1000 - data = { - displayName: 'Org Unit 3', - id: 'A0000000002', - path: '/A0000000000/A0000000002', - children: [], - } - } - - if (id === 'A0000000003') { - data = { - displayName: 'Org Unit 4', - id: 'A0000000003', - path: '/A0000000000/A0000000001/A0000000003', - children: [], - } - } - - if (id === 'A0000000004') { - data = { - displayName: 'Org Unit 5', - id: 'A0000000004', - path: '/A0000000000/A0000000001/A0000000004', - children: [], - } - } - - if (id === 'A0000000006') { - data = { - displayName: 'Org Unit 7', - id: 'A0000000006', - path: '/A0000000000/A0000000006', - children: [], - } - } - - if (!data) { - return Promise.reject(new Error('404 - Org unit not found')) - } - - return new Promise(resolve => { - setTimeout(() => resolve(data), delay) - }) - }, -} - -const ForceReloadAll = () => { - const [forceReload, _setForceReload] = useState(false) - const setForceReload = v => - console.log('setForceReload', v) || _setForceReload(v) - - return ( - <> - {' '} - (Force reload: {forceReload ? 'true' : 'false'}) -
- { - const { id } = data - if (id === 'A0000000000') { - setForceReload(false) - } - }} - /> -
- - - ) -} - -const ForceReloadIds = () => { - return ( -

- This is currently not working due to limitations of the data engine - in the app runtime. -

- ) - - //const [idsThatShouldBeReloaded, setIdsThatShouldBeReloaded] = useState([]) - - //useEffect(() => { - // setTimeout(() => setIdsThatShouldBeReloaded(['A0000000001']), delay) - //}, []) - - //return ( - // - // console.log( - // `Unit with path "${path}" loaded, was forced: ${ - // forced ? 'yes' : 'no' - // }` - // ) - // } - // /> - //) -} - -const ReplaceRoots = ({ delay }) => { - return ( -

- This is currently not working due to limitations of the data engine - in the app runtime. Normally the root unit would've been replaced - after {` ${delay} `} milliseconds. -

- ) - - //const [roots, setRoots] = useState(['A0000000000']) - - //useEffect(() => { - // setTimeout(() => setRoots(['A0000000001']), delay) - //}, []) - - //return ( - // - //) -} +OrganisationUnitTree.defaultProps.onChildrenLoaded = onChildrenLoaded +OrganisationUnitTreeControllable.propTypes.onChildrenLoaded = PropTypes.func +OrganisationUnitTreeControllable.defaultProps.onChildrenLoaded = onChildrenLoaded export default { title: 'Forms/Organisation Unit Tree', @@ -259,334 +71,33 @@ export default { }, } -export const Collapsed = args => -Collapsed.args = { - onChange: onChange, - name: 'Root org unit', - roots: ['A0000000000'], -} - -export const Expanded = () => ( - -) - -export const MultipleRoots = () => ( - -) -MultipleRoots.storyName = 'Multiple roots' - -export const CustomNodeLabel = () => ( - { - if (data.node.path !== '/A0000000000/A0000000001') { - return OrganisationUnitTree.defaultProps.renderNodeLabel(data) - } - - return OrganisationUnitTree.defaultProps.renderNodeLabel({ - ...data, - node: { - ...data.node, - displayName: --- {data.node.displayName}, - }, - }) - }} - onChange={onChange} - /> -) - -export const FilteredRoot = () => ( - -) -FilteredRoot.storyName = 'Filtered (root)' - -export const Filtered = () => ( +export const Collapsed = () => ( -) - -export const SelectedMultiple = () => ( - -) -SelectedMultiple.storyName = 'Selected multiple' - -export const Indeterminate = () => ( - -) - -export const SingleSelection = () => ( - -) -SingleSelection.storyName = 'Single selection' - -export const NoSelection = () => ( - -) -NoSelection.storyName = 'No selection' - -export const Highlighted = () => ( - ) -export const _ForceReloadAll = () => -_ForceReloadAll.storyName = 'Force reload all' - -export const ForceReloadOneUnit = () => -ForceReloadOneUnit.storyName = 'Force reload one unit' - -export const _ReplaceRoots = () => -_ReplaceRoots.storyName = 'Replace roots' - -export const Loading = () => ( - { - const [, { id }] = args - if (id === 'A0000000001') { - return new Promise(() => null) - } - - return customData.organisationUnits(...args) - }, - }} - > - - -) - -export const RootLoading = () => ( - { - const [, { id }] = args - if (id === 'A0000000000') { - return new Promise(() => null) - } - - return customData.organisationUnits(...args) - }, - }} - > -
- - Custom container (max-width: 600px) - - -
-
-) -RootLoading.storyName = 'Root loading' - -export const RootError = () => ( - { - const [, { id }] = args - if (id === 'A0000000000') { - return Promise.reject( - 'This is a custom error message, it could be anything' - ) - } - - return customData.organisationUnits(...args) - }, - }} - > -
- - Custom container (max-width: 600px) - - -
-
-) -RootError.storyName = 'Root error' - -export const LoadingErrorGrandchild = () => ( - { - const [, { id }] = args - if (id === 'A0000000003') { - return Promise.reject('Loading org unit 4 and 5 failed') - } - - return customData.organisationUnits(...args) - }, - }} - > - - -) -LoadingErrorGrandchild.storyName = 'Loading error grandchild' - -const DX_onChange = (selected, setSelected, singleSelection) => ({ - id, - path, - checked, -}) => { - console.log('onChange', { path, id, checked }) - const pathIndex = selected.indexOf(path) - - if (checked) { - setSelected(singleSelection ? [path] : [...selected, path]) - } else { - setSelected( - singleSelection - ? [] - : [ - ...selected.slice(0, pathIndex), - ...selected.slice(pathIndex + 1), - ] - ) - } -} - -const Wrapper = props => { - const [selected, setSelected] = useState([]) - - return ( - - ) -} - -export const DxMultiSelection = () => -DxMultiSelection.storyName = 'DX: Multi selection' - -export const DxSingleSelection = () => -DxSingleSelection.storyName = 'DX: Single selection' - -export const DxNoSelection = () => -DxNoSelection.storyName = 'DX: No selection' - -export const DxWithRealBackend = () => ( -
-
- - This story doesn't work on netlify for some reason, just run it - locally. - -
- You need to log in to{' '} - - https://debug.dhis2.org/dev - -
- Make sure the{' '} - localhost:[PORT] is part - of the accepted list:{' '} - - Settings app / Access - -
- - - -
-) -DxWithRealBackend.storyName = 'DX: With real backend' +export { Expanded } from './__stories__/expanded.js' +export { MultipleRoots } from './__stories__/multiple-roots.js' +export { CustomNodeLabel } from './__stories__/custom-node-label.js' +export { CustomRequests } from './__stories__/custom-requests.js' +export { FilteredRoot } from './__stories__/filtered-root.js' +export { Filtered } from './__stories__/filtered.js' +export { SelectedMultiple } from './__stories__/selected-multiple.js' +export { Indeterminate } from './__stories__/indeterminate.js' +export { SingleSelection } from './__stories__/single-selection.js' +export { NoSelection } from './__stories__/no-selection.js' +export { Highlighted } from './__stories__/highlighted.js' +export { ForceReloadAll } from './__stories__/force-reload-all.js' +export { ForceReloadOneUnit } from './__stories__/force-reload-one-unit.js' +export { ReplaceRoots } from './__stories__/replace-roots.js' +export { Loading } from './__stories__/loading.js' +export { RootLoading } from './__stories__/root-loading.js' +export { RootError } from './__stories__/root-error.js' +export { LoadingErrorGrandchild } from './__stories__/loading-error-grandchild.js' +export { AdditionalRequestResources } from './__stories__/additional-request-resources.js' +export { DxMultiSelection } from './__stories__/dx-multi-selection.js' +export { DxSingleSelection } from './__stories__/dx-single-selection.js' +export { DxNoSelection } from './__stories__/dx-no-selection.js' +export { DxWithRealBackend } from './__stories__/dx-with-real-backend.js'