Skip to content

Commit 0165ad0

Browse files
committed
2 parents 9a03d57 + 687d336 commit 0165ad0

File tree

8 files changed

+434
-295
lines changed

8 files changed

+434
-295
lines changed

dqops/src/main/frontend/src/components/DefinitionLayout/DefinitionTree.tsx

+51-266
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,26 @@ import React from 'react';
22
import { useEffect } from 'react';
33
import { useSelector } from 'react-redux';
44
import {
5-
addFirstLevelTab,
65
getSensorFolderTree,
7-
toggleSensorFolderTree,
8-
openRuleFolderTree,
96
getRuleFolderTree,
10-
toggleRuleFolderTree,
117
toggleFirstLevelFolder,
12-
openSensorFolderTree,
13-
getdataQualityChecksFolderTree,
14-
toggledataQualityChecksFolderTree,
15-
opendataQualityChecksFolderTree
8+
getdataQualityChecksFolderTree
169
} from '../../redux/actions/definition.actions';
1710
import { useActionDispatch } from '../../hooks/useActionDispatch';
1811
import { IRootState } from '../../redux/reducers';
1912
import {
2013
CheckDefinitionFolderModel,
2114
RuleFolderModel,
22-
RuleListModel,
23-
SensorFolderModel,
24-
SensorListModel,
25-
CheckDefinitionListModel
15+
SensorFolderModel
2616
} from '../../api';
2717
import SvgIcon from '../SvgIcon';
2818
import clsx from 'clsx';
29-
import { ROUTES } from '../../shared/routes';
3019
import SensorContextMenu from './SensorContextMenu';
3120
import RuleContextMenu from './RuleContextMenu';
3221
import DataQualityContextMenu from './DataQualityContextMenu';
3322
import { urlencodeEncoder } from '../../utils';
3423
import { Tooltip } from '@material-tailwind/react';
24+
import { useDefinition } from '../../contexts/definitionContext';
3525

3626
const defaultChecks = [
3727
'Profiling checks',
@@ -56,6 +46,18 @@ export const DefinitionTree = () => {
5646
refreshSensorsTreeIndicator
5747
} = useSelector((state: IRootState) => state.definition);
5848

49+
const {
50+
openCheckDefaultFirstLevelTab,
51+
openCheckFirstLevelTab,
52+
openRuleFirstLevelTab,
53+
openSensorFirstLevelTab,
54+
toggleTree,
55+
nodes,
56+
toggleSensorFolder,
57+
toggleRuleFolder,
58+
toggleDataQualityChecksFolder
59+
} = useDefinition();
60+
5961
useEffect(() => {
6062
dispatch(getSensorFolderTree());
6163
}, [refreshSensorsTreeIndicator]);
@@ -68,209 +70,13 @@ export const DefinitionTree = () => {
6870
dispatch(getdataQualityChecksFolderTree());
6971
}, [refreshChecksTreeIndicator]);
7072

71-
const toggleSensorFolder = (key: string) => {
72-
dispatch(toggleSensorFolderTree(key));
73-
};
74-
75-
const openSensorFolder = (key: string) => {
76-
dispatch(openSensorFolderTree(key));
77-
};
78-
79-
const toggleRuleFolder = (key: string) => {
80-
dispatch(toggleRuleFolderTree(key));
81-
};
82-
83-
const openRuleFolder = (key: string) => {
84-
dispatch(openRuleFolderTree(key));
85-
};
86-
87-
const toggleDataQualityChecksFolder = (fullPath: string) => {
88-
dispatch(toggledataQualityChecksFolderTree(fullPath));
89-
};
90-
const openDataQualityChecksFolder = (fullPath: string) => {
91-
dispatch(opendataQualityChecksFolderTree(fullPath));
92-
};
93-
94-
const openSensorFirstLevelTab = (sensor: SensorListModel) => {
95-
dispatch(
96-
addFirstLevelTab({
97-
url: ROUTES.SENSOR_DETAIL(urlencodeEncoder(sensor.sensor_name) ?? ''),
98-
value: ROUTES.SENSOR_DETAIL_VALUE(
99-
urlencodeEncoder(sensor.sensor_name) ?? ''
100-
),
101-
state: {
102-
full_sensor_name: urlencodeEncoder(sensor.full_sensor_name)
103-
},
104-
label: urlencodeEncoder(sensor.sensor_name)
105-
})
106-
);
107-
};
108-
109-
const openRuleFirstLevelTab = (rule: RuleListModel) => {
110-
dispatch(
111-
addFirstLevelTab({
112-
url: ROUTES.RULE_DETAIL(urlencodeEncoder(rule.rule_name) ?? ''),
113-
value: ROUTES.RULE_DETAIL_VALUE(urlencodeEncoder(rule.rule_name) ?? ''),
114-
state: {
115-
full_rule_name: urlencodeEncoder(rule.full_rule_name)
116-
},
117-
label: urlencodeEncoder(rule.rule_name)
118-
})
119-
);
120-
};
121-
122-
const openCheckFirstLevelTab = (check: CheckDefinitionListModel) => {
123-
dispatch(
124-
addFirstLevelTab({
125-
url: ROUTES.CHECK_DETAIL(urlencodeEncoder(check.check_name) ?? ''),
126-
value: ROUTES.CHECK_DETAIL_VALUE(
127-
urlencodeEncoder(check.check_name) ?? ''
128-
),
129-
state: {
130-
full_check_name: urlencodeEncoder(check.full_check_name),
131-
custom: check.custom
132-
},
133-
label: urlencodeEncoder(check.check_name)
134-
})
135-
);
136-
};
137-
138-
const openCheckDefaultFirstLevelTab = (defaultCheck: string) => {
139-
dispatch(
140-
addFirstLevelTab({
141-
url: ROUTES.CHECK_DEFAULT_DETAIL(defaultCheck.replace(/\s/g, '_')),
142-
value: ROUTES.CHECK_DEFAULT_DETAIL_VALUE(
143-
defaultCheck.replace(/\s/g, '_')
144-
),
145-
state: {
146-
type: defaultCheck
147-
},
148-
label: defaultCheck
149-
})
150-
);
151-
};
152-
153-
const openAllUsersFirstLevelTab = () => {
154-
dispatch(
155-
addFirstLevelTab({
156-
url: ROUTES.USERS_LIST_DETAIL(),
157-
value: ROUTES.USERS_LIST_DETAIL_VALUE(),
158-
label: 'All users'
159-
})
160-
);
161-
};
162-
163-
const openDefaultSchedulesFirstLevelTab = () => {
164-
dispatch(
165-
addFirstLevelTab({
166-
url: ROUTES.SCHEDULES_DEFAULT_DETAIL(),
167-
value: ROUTES.SCHEDULES_DEFAULT_DETAIL_VALUE(),
168-
label: 'Default schedules'
169-
})
170-
);
171-
};
172-
173-
const openDefaultWebhooksFirstLevelTab = () => {
174-
dispatch(
175-
addFirstLevelTab({
176-
url: ROUTES.WEBHOOKS_DEFAULT_DETAIL(),
177-
value: ROUTES.WEBHOOKS_DEFAULT_DETAIL_VALUE(),
178-
label: 'Default webhooks'
179-
})
180-
);
181-
};
182-
183-
const openSharedCredentialsFirstLevelTab = () => {
184-
dispatch(
185-
addFirstLevelTab({
186-
url: ROUTES.SHARED_CREDENTIALS_LIST_DETAIL(),
187-
value: ROUTES.SHARED_CREDENTIALS_LIST_DETAIL_VALUE(),
188-
label: 'Shared credentials'
189-
})
190-
);
191-
};
192-
193-
const openDataDictionaryFirstLevelTab = () => {
194-
dispatch(
195-
addFirstLevelTab({
196-
url: ROUTES.DATA_DICTIONARY_LIST_DETAIL(),
197-
value: ROUTES.DATA_DICTIONARY_LIST_VALUE(),
198-
label: 'Data dictionaries'
199-
})
200-
);
201-
};
202-
203-
const toggleFolderRecursively = (
204-
elements: string[],
205-
index = 0,
206-
type: string
207-
) => {
208-
if (index >= elements.length - 1) {
209-
return;
210-
}
211-
const path = elements.slice(0, index + 1).join('/');
212-
if (index === 0) {
213-
if (type === 'checks') {
214-
openDataQualityChecksFolder('undefined/' + path);
215-
} else if (type === 'rules') {
216-
openRuleFolder('undefined/' + path);
217-
} else {
218-
openSensorFolder('undefined/' + path);
219-
}
220-
} else {
221-
if (type === 'checks') {
222-
openDataQualityChecksFolder(path);
223-
} else if (type === 'rules') {
224-
openRuleFolder(path);
225-
} else {
226-
openSensorFolder(path);
227-
}
228-
}
229-
toggleFolderRecursively(elements, index + 1, type);
230-
};
231-
23273
useEffect(() => {
233-
const configuration = [
234-
{ category: 'Sensors', isOpen: false },
235-
{ category: 'Rules', isOpen: false },
236-
{ category: 'Data quality checks', isOpen: false },
237-
{ category: 'Default checks configuration', isOpen: false }
238-
];
239-
if (tabs && tabs.length !== 0) {
240-
for (let i = 0; i < tabs.length; i++) {
241-
if (tabs[i].url?.includes('default_checks')) {
242-
configuration[3].isOpen = true;
243-
} else if (tabs[i]?.url?.includes('sensors')) {
244-
configuration[0].isOpen = true;
245-
const arrayOfElemsToToggle = (
246-
tabs[i].state.full_sensor_name as string
247-
)?.split('/');
248-
if (arrayOfElemsToToggle) {
249-
toggleFolderRecursively(arrayOfElemsToToggle, 0, 'sensors');
250-
}
251-
} else if (tabs[i]?.url?.includes('checks')) {
252-
configuration[2].isOpen = true;
253-
const arrayOfElemsToToggle = (
254-
tabs[i].state.fullCheckName as string
255-
)?.split('/');
256-
if (arrayOfElemsToToggle) {
257-
toggleFolderRecursively(arrayOfElemsToToggle, 0, 'checks');
258-
}
259-
} else if (tabs[i]?.url?.includes('rules')) {
260-
configuration[1].isOpen = true;
261-
const arrayOfElemsToToggle = (
262-
tabs[i].state.full_rule_name as string
263-
)?.split('/');
264-
if (arrayOfElemsToToggle) {
265-
toggleFolderRecursively(arrayOfElemsToToggle, 0, 'rules');
266-
}
267-
}
268-
dispatch(toggleFirstLevelFolder(configuration));
269-
}
270-
} else {
271-
dispatch(toggleFirstLevelFolder(configuration));
272-
}
273-
}, []);
74+
toggleTree(tabs);
75+
}, [activeTab]);
76+
77+
const highlightedNode = activeTab
78+
?.split('/')
79+
.at(activeTab?.split('/').length - 1);
27480

27581
const renderSensorFolderTree = (
27682
folder?: SensorFolderModel,
@@ -599,15 +405,36 @@ export const DefinitionTree = () => {
599405
);
600406
};
601407

408+
const NodeComponent = ({
409+
onClick,
410+
icon,
411+
text
412+
}: {
413+
onClick: () => void;
414+
icon: string;
415+
text: string;
416+
}) => (
417+
<div
418+
onClick={onClick}
419+
className={clsx(
420+
'cursor-pointer flex space-x-1 items-center mb-1 h-5 hover:bg-gray-300',
421+
highlightedNode === text.toLowerCase().replace(' ', '-') &&
422+
'bg-gray-300'
423+
)}
424+
>
425+
<SvgIcon name={icon} className="w-4 h-4 min-w-4 " />
426+
<div className="text-[14.5px] leading-1.5 whitespace-nowrap flex items-center justify-between">
427+
{text}
428+
</div>
429+
</div>
430+
);
431+
602432
return (
603-
<div className="fixed left-0 top-16 bottom-0 overflow-y-auto w-80 shadow border-r border-gray-300 p-4 pt-4 bg-white">
433+
<div className="overflow-hidden w-80 p-4 pt-4 bg-white">
604434
{definitionFirstLevelFolder?.map((x, index) => (
605-
<div
606-
key={index}
607-
className="mt-2 mb-2 text-sm font-regular cursor-pointer"
608-
>
435+
<div key={index} className="text-[13px] cursor-pointer">
609436
<div
610-
className="flex items-center mb-2"
437+
className="flex items-center mb-1 gap-x-1"
611438
onClick={() => {
612439
const updatedRootTree = [...definitionFirstLevelFolder];
613440
updatedRootTree[index].isOpen = !updatedRootTree[index].isOpen;
@@ -670,51 +497,9 @@ export const DefinitionTree = () => {
670497
)}
671498
</div>
672499
))}
673-
<div
674-
onClick={openAllUsersFirstLevelTab}
675-
className="cursor-pointer flex space-x-1 items-center mb-1 h-5 hover:bg-gray-300"
676-
>
677-
<SvgIcon name="userprofile" className="w-4 h-4 min-w-4 " />
678-
<div className="text-[14.5px] leading-1.5 whitespace-nowrap flex items-center justify-between">
679-
Manage users
680-
</div>
681-
</div>
682-
<div
683-
onClick={openDefaultSchedulesFirstLevelTab}
684-
className="cursor-pointer flex space-x-1 items-center mb-1 h-5 hover:bg-gray-300"
685-
>
686-
<SvgIcon name="clock" className="w-4 h-4 min-w-4 " />
687-
<div className="text-[14.5px] leading-1.5 whitespace-nowrap flex items-center justify-between">
688-
Default schedules
689-
</div>
690-
</div>
691-
<div
692-
onClick={openDefaultWebhooksFirstLevelTab}
693-
className="cursor-pointer flex space-x-1 items-center mb-1 h-5 hover:bg-gray-300"
694-
>
695-
<SvgIcon name="webhooks" className="w-4 h-4 min-w-4 " />
696-
<div className="text-[14.5px] leading-1.5 whitespace-nowrap flex items-center justify-between">
697-
Default webhooks
698-
</div>
699-
</div>
700-
<div
701-
onClick={openSharedCredentialsFirstLevelTab}
702-
className="cursor-pointer flex space-x-1 items-center mb-1 h-5 hover:bg-gray-300"
703-
>
704-
<SvgIcon name="definitionsrules" className="w-4 h-4 min-w-4 " />
705-
<div className="text-[14.5px] leading-1.5 whitespace-nowrap flex items-center justify-between">
706-
Shared credentials
707-
</div>
708-
</div>
709-
<div
710-
onClick={openDataDictionaryFirstLevelTab}
711-
className="cursor-pointer flex space-x-1 items-center mb-1 h-5 hover:bg-gray-300"
712-
>
713-
<SvgIcon name="datadictionary" className="w-4 h-4 min-w-4 " />
714-
<div className="text-[14.5px] leading-1.5 whitespace-nowrap flex items-center justify-between">
715-
Data dictionaries
716-
</div>
717-
</div>
500+
{(nodes as any[]).map((tab, index) => (
501+
<NodeComponent key={index} {...tab} />
502+
))}
718503
</div>
719504
);
720505
};

0 commit comments

Comments
 (0)