@databiosphere/findable-ui 21.2.0 → 21.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +15 -0
- package/lib/common/entities.d.ts +33 -0
- package/lib/components/DataDictionary/common/utils.d.ts +38 -0
- package/lib/components/DataDictionary/common/utils.js +122 -0
- package/lib/components/Export/components/ExportForm/components/ExportButton/exportButton.js +6 -1
- package/lib/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestDownload/fileManifestDownload.js +5 -2
- package/lib/components/Filter/components/Filter/filter.js +1 -1
- package/lib/components/Filter/components/FilterLabel/filterLabel.d.ts +3 -1
- package/lib/components/Filter/components/FilterLabel/filterLabel.js +4 -2
- package/lib/components/Index/components/AzulFileDownload/azulFileDownload.js +10 -5
- package/lib/components/Index/components/Tabs/common/utils.js +2 -1
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenu/navigationMenu.js +1 -1
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenuItems/navigationMenuItems.js +20 -21
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/constants.d.ts +1 -0
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/constants.js +1 -0
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/navigation.d.ts +2 -1
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/navigation.js +16 -17
- package/lib/components/Layout/components/Header/header.js +2 -1
- package/lib/components/Login/components/Button/types.d.ts +1 -1
- package/lib/components/Login/components/Buttons/buttons.d.ts +2 -0
- package/lib/components/Login/components/Buttons/buttons.js +5 -0
- package/lib/components/Login/components/Buttons/types.d.ts +8 -0
- package/lib/components/Login/components/Buttons/types.js +1 -0
- package/lib/components/Login/components/Section/components/Consent/consent.d.ts +3 -0
- package/lib/components/Login/components/Section/components/Consent/consent.js +14 -0
- package/lib/components/Login/components/Section/components/Consent/consent.styles.d.ts +7 -0
- package/lib/components/Login/components/Section/components/Consent/consent.styles.js +14 -0
- package/lib/components/Login/components/Section/components/Consent/types.d.ts +6 -0
- package/lib/components/Login/components/Section/components/Consent/types.js +1 -0
- package/lib/components/Login/components/Section/components/Warning/warning.d.ts +3 -0
- package/lib/components/Login/components/Section/components/Warning/warning.js +9 -0
- package/lib/components/Login/hooks/useUserConsent/types.d.ts +10 -0
- package/lib/components/Login/hooks/useUserConsent/types.js +1 -0
- package/lib/components/Login/hooks/useUserConsent/useUserConsent.d.ts +2 -0
- package/lib/components/Login/hooks/useUserConsent/useUserConsent.js +24 -0
- package/lib/components/Login/hooks/useUserLogin/types.d.ts +6 -0
- package/lib/components/Login/hooks/useUserLogin/types.js +1 -0
- package/lib/components/Login/hooks/useUserLogin/useUserLogin.d.ts +2 -0
- package/lib/components/Login/hooks/useUserLogin/useUserLogin.js +21 -0
- package/lib/components/Table/components/TableHead/tableHead.js +4 -1
- package/lib/components/common/CustomIcon/components/CloseIcon/closeIcon.d.ts +2 -0
- package/lib/components/common/CustomIcon/components/CloseIcon/closeIcon.js +6 -0
- package/lib/components/common/LoginDialog/constants.d.ts +6 -0
- package/lib/components/common/LoginDialog/constants.js +21 -0
- package/lib/components/common/LoginDialog/loginDialog.d.ts +2 -0
- package/lib/components/common/LoginDialog/loginDialog.js +27 -0
- package/lib/components/common/LoginDialog/loginDialog.styles.d.ts +3 -0
- package/lib/components/common/LoginDialog/loginDialog.styles.js +50 -0
- package/lib/components/common/LoginDialog/types.d.ts +4 -0
- package/lib/components/common/LoginDialog/types.js +1 -0
- package/lib/components/common/Tabs/tabs.d.ts +2 -0
- package/lib/components/common/Tabs/tabs.js +14 -1
- package/lib/config/entities.d.ts +6 -1
- package/lib/hooks/useCategoryFilter.js +1 -0
- package/lib/providers/config.js +9 -2
- package/lib/providers/loginGuard/common/types.d.ts +18 -0
- package/lib/providers/loginGuard/common/types.js +1 -0
- package/lib/providers/loginGuard/context.d.ts +6 -0
- package/lib/providers/loginGuard/context.js +10 -0
- package/lib/providers/loginGuard/hook.d.ts +9 -0
- package/lib/providers/loginGuard/hook.js +12 -0
- package/lib/providers/loginGuard/provider.d.ts +11 -0
- package/lib/providers/loginGuard/provider.js +55 -0
- package/lib/styles/common/mui/typography.d.ts +1 -0
- package/lib/styles/common/mui/typography.js +7 -0
- package/package.json +1 -1
- package/src/common/entities.ts +37 -0
- package/src/components/DataDictionary/common/utils.ts +160 -0
- package/src/components/Export/components/ExportForm/components/ExportButton/exportButton.tsx +8 -1
- package/src/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestDownload/fileManifestDownload.tsx +11 -3
- package/src/components/Filter/components/Filter/filter.tsx +1 -0
- package/src/components/Filter/components/FilterLabel/filterLabel.tsx +16 -10
- package/src/components/Index/components/AzulFileDownload/azulFileDownload.tsx +12 -5
- package/src/components/Index/components/Tabs/common/utils.ts +2 -0
- package/src/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenu/navigationMenu.tsx +1 -1
- package/src/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenuItems/navigationMenuItems.tsx +16 -15
- package/src/components/Layout/components/Header/components/Content/components/Navigation/constants.ts +1 -0
- package/src/components/Layout/components/Header/components/Content/components/Navigation/navigation.tsx +26 -18
- package/src/components/Layout/components/Header/header.tsx +6 -1
- package/src/components/Login/components/Button/types.ts +1 -1
- package/src/components/Login/components/Buttons/buttons.tsx +22 -0
- package/src/components/Login/components/Buttons/types.ts +9 -0
- package/src/components/Login/components/Section/components/Consent/consent.styles.ts +15 -0
- package/src/components/Login/components/Section/components/Consent/consent.tsx +30 -0
- package/src/components/Login/components/Section/components/Consent/types.ts +10 -0
- package/src/components/Login/components/Section/components/Warning/warning.tsx +24 -0
- package/src/components/Login/hooks/useUserConsent/types.ts +11 -0
- package/src/components/Login/hooks/useUserConsent/useUserConsent.ts +32 -0
- package/src/components/Login/hooks/useUserLogin/types.ts +8 -0
- package/src/components/Login/hooks/useUserLogin/useUserLogin.ts +29 -0
- package/src/components/Table/components/TableHead/tableHead.tsx +26 -15
- package/src/components/common/CustomIcon/components/CloseIcon/closeIcon.tsx +17 -0
- package/src/components/common/LoginDialog/constants.ts +33 -0
- package/src/components/common/LoginDialog/loginDialog.styles.ts +51 -0
- package/src/components/common/LoginDialog/loginDialog.tsx +56 -0
- package/src/components/common/LoginDialog/types.ts +4 -0
- package/src/components/common/Tabs/tabs.tsx +33 -3
- package/src/config/entities.ts +11 -1
- package/src/hooks/useCategoryFilter.ts +1 -0
- package/src/providers/config.tsx +10 -2
- package/src/providers/loginGuard/common/types.ts +21 -0
- package/src/providers/loginGuard/context.ts +12 -0
- package/src/providers/loginGuard/hook.ts +14 -0
- package/src/providers/loginGuard/provider.tsx +76 -0
- package/src/styles/common/mui/typography.ts +8 -0
- package/tests/dataDictionary_utils.test.ts +153 -0
- package/tests/provider.test.tsx +191 -0
- package/types/data-explorer-ui.d.ts +2 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Attribute,
|
|
3
|
+
Class,
|
|
4
|
+
DataDictionary,
|
|
5
|
+
DataDictionaryAnnotation,
|
|
6
|
+
} from "../../../common/entities";
|
|
7
|
+
import { CategoryGroupConfig, SiteConfig } from "../../../config/entities";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Annotate each entity column configuration with data dictionary values. Specifically,
|
|
11
|
+
* look up label and description for each column key.
|
|
12
|
+
* @param siteConfig - Site configuration to annotate.
|
|
13
|
+
* @param annotationsByKey - Data dictionary annotations keyed by key.
|
|
14
|
+
*/
|
|
15
|
+
export function annotateColumnConfig(
|
|
16
|
+
siteConfig: SiteConfig,
|
|
17
|
+
annotationsByKey: Record<string, DataDictionaryAnnotation>
|
|
18
|
+
): void {
|
|
19
|
+
// Annotate every column in every entity.
|
|
20
|
+
siteConfig.entities.forEach((entity) => {
|
|
21
|
+
entity.list.columns.forEach((columnConfig) => {
|
|
22
|
+
// Find the annotation for the column key.
|
|
23
|
+
const annotation = annotationsByKey[columnConfig.id];
|
|
24
|
+
if (!annotation) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!columnConfig.meta) {
|
|
29
|
+
columnConfig.meta = {};
|
|
30
|
+
}
|
|
31
|
+
columnConfig.meta.annotation = annotation;
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Annotate filter and colummn configuration with data dictionary values. Note this
|
|
38
|
+
* functionality mutates the site config. A possible future improvement would be to
|
|
39
|
+
* create either a specific "raw" or "annotated" type to indicate clearly the point
|
|
40
|
+
* at which the config has been annotated.
|
|
41
|
+
* @param siteConfig - The site configuration to annotate.
|
|
42
|
+
*/
|
|
43
|
+
export function annotateSiteConfig(siteConfig: SiteConfig): void {
|
|
44
|
+
// Build and map data dictionary annotations by key.
|
|
45
|
+
const { dataDictionary } = siteConfig;
|
|
46
|
+
if (!dataDictionary) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const annotationsByKey = keyAnnotationsByKey(dataDictionary);
|
|
50
|
+
|
|
51
|
+
// Annotate elements of site config.
|
|
52
|
+
annotateEntityConfig(siteConfig, annotationsByKey);
|
|
53
|
+
annotateDefaultCategoryConfig(siteConfig, annotationsByKey);
|
|
54
|
+
annotateEntityCategoryConfig(siteConfig, annotationsByKey);
|
|
55
|
+
annotateColumnConfig(siteConfig, annotationsByKey);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Annotate entity configuration with data dictionary values. Specifically, look
|
|
60
|
+
* up label and description for each entity key.
|
|
61
|
+
* @param siteConfig - The site configuration to annotate.
|
|
62
|
+
* @param annotationsByKey - Data dictionary annotations keyed by key.
|
|
63
|
+
*/
|
|
64
|
+
export function annotateEntityConfig(
|
|
65
|
+
siteConfig: SiteConfig,
|
|
66
|
+
annotationsByKey: Record<string, DataDictionaryAnnotation>
|
|
67
|
+
): void {
|
|
68
|
+
// Annotate every entity.
|
|
69
|
+
siteConfig.entities.forEach((entityConfig) => {
|
|
70
|
+
// Check entity for a data dictionary key.
|
|
71
|
+
const { key } = entityConfig;
|
|
72
|
+
if (!key) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Find corresponding annotation for the key and set on entity config.
|
|
77
|
+
entityConfig.annotation = annotationsByKey[key];
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Annotate top-level (app-wide) category config with data dictionary values.
|
|
83
|
+
* Specifically, look up label and description for each filter key.
|
|
84
|
+
* @param siteConfig - Site configuration to annotate.
|
|
85
|
+
* @param annotationsByKey - Data dictionary annotations keyed by key.
|
|
86
|
+
*/
|
|
87
|
+
export function annotateDefaultCategoryConfig(
|
|
88
|
+
siteConfig: SiteConfig,
|
|
89
|
+
annotationsByKey: Record<string, DataDictionaryAnnotation>
|
|
90
|
+
): void {
|
|
91
|
+
const { categoryGroupConfig } = siteConfig;
|
|
92
|
+
if (categoryGroupConfig) {
|
|
93
|
+
annotateCategoryGroupConfig(categoryGroupConfig, annotationsByKey);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Annotate entity-specific category config with data dictionary values. Specifically,
|
|
99
|
+
* look up label and description for each category key.
|
|
100
|
+
* @param siteConfig - Site configuration to annotate.
|
|
101
|
+
* @param annotationsByKey - Data dictionary annotations keyed by key.
|
|
102
|
+
*/
|
|
103
|
+
export function annotateEntityCategoryConfig(
|
|
104
|
+
siteConfig: SiteConfig,
|
|
105
|
+
annotationsByKey: Record<string, DataDictionaryAnnotation>
|
|
106
|
+
): void {
|
|
107
|
+
// Annotate every category in every entity.
|
|
108
|
+
siteConfig.entities.forEach((entityConfig) => {
|
|
109
|
+
const { categoryGroupConfig } = entityConfig;
|
|
110
|
+
if (categoryGroupConfig) {
|
|
111
|
+
annotateCategoryGroupConfig(categoryGroupConfig, annotationsByKey);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Annonate category group configuration with data dictionary values.
|
|
118
|
+
* @param categoryGroupConfig - Category group to annotate.
|
|
119
|
+
* @param annotationsByKey - Data dictionary annotations keyed by key.
|
|
120
|
+
*/
|
|
121
|
+
function annotateCategoryGroupConfig(
|
|
122
|
+
categoryGroupConfig: CategoryGroupConfig,
|
|
123
|
+
annotationsByKey: Record<string, DataDictionaryAnnotation>
|
|
124
|
+
): void {
|
|
125
|
+
categoryGroupConfig.categoryGroups.forEach((categoryGroup) => {
|
|
126
|
+
categoryGroup.categoryConfigs.forEach((categorConfig) => {
|
|
127
|
+
categorConfig.annotation = annotationsByKey[categorConfig.key];
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Transform a data dictionary into a key-annotation map. Build annotations for both
|
|
134
|
+
* classes and attributes and add to map.
|
|
135
|
+
* @param dataDictionary - Data dictionary to transform into a key-annotation map.
|
|
136
|
+
* @returns Key-annotation map.
|
|
137
|
+
*/
|
|
138
|
+
function keyAnnotationsByKey(
|
|
139
|
+
dataDictionary: DataDictionary
|
|
140
|
+
): Record<string, DataDictionaryAnnotation> {
|
|
141
|
+
return dataDictionary.classes.reduce(
|
|
142
|
+
(acc: Record<string, DataDictionaryAnnotation>, cls: Class) => {
|
|
143
|
+
// Add class to map.
|
|
144
|
+
acc[cls.key] = {
|
|
145
|
+
description: cls.description,
|
|
146
|
+
label: cls.label,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Add each class attribute to the map.
|
|
150
|
+
cls.attributes.forEach((attribute: Attribute) => {
|
|
151
|
+
acc[attribute.key] = {
|
|
152
|
+
description: attribute.description,
|
|
153
|
+
label: attribute.label,
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
return acc;
|
|
157
|
+
},
|
|
158
|
+
{} as Record<string, DataDictionaryAnnotation>
|
|
159
|
+
);
|
|
160
|
+
}
|
package/src/components/Export/components/ExportForm/components/ExportButton/exportButton.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { Tooltip } from "@mui/material";
|
|
|
2
2
|
import React, { ElementType, ReactNode } from "react";
|
|
3
3
|
import { useDownloadStatus } from "../../../../../../hooks/useDownloadStatus";
|
|
4
4
|
import { useFileManifestState } from "../../../../../../hooks/useFileManifestState";
|
|
5
|
+
import { useLoginGuard } from "../../../../../../providers/loginGuard/hook";
|
|
5
6
|
import { ButtonPrimary } from "../../../../../common/Button/components/ButtonPrimary/buttonPrimary";
|
|
6
7
|
|
|
7
8
|
export interface ExportButtonProps {
|
|
@@ -19,6 +20,10 @@ export const ExportButton = ({
|
|
|
19
20
|
const {
|
|
20
21
|
fileManifestState: { isLoading },
|
|
21
22
|
} = useFileManifestState();
|
|
23
|
+
|
|
24
|
+
// Prompt user for login before export, if required.
|
|
25
|
+
const { requireLogin } = useLoginGuard();
|
|
26
|
+
|
|
22
27
|
return (
|
|
23
28
|
<Tooltip arrow title={isLoading ? null : downloadStatus.message}>
|
|
24
29
|
<span>
|
|
@@ -26,7 +31,9 @@ export const ExportButton = ({
|
|
|
26
31
|
disabled={
|
|
27
32
|
isLoading || downloadStatus.disabled || downloadStatus.isLoading
|
|
28
33
|
}
|
|
29
|
-
onClick={
|
|
34
|
+
onClick={() => {
|
|
35
|
+
requireLogin(onClick);
|
|
36
|
+
}}
|
|
30
37
|
>
|
|
31
38
|
<span>{children}</span>
|
|
32
39
|
</Button>
|
|
@@ -10,6 +10,7 @@ import React, { useRef } from "react";
|
|
|
10
10
|
import { Filters } from "../../../../../../../../common/entities";
|
|
11
11
|
import { useDownloadStatus } from "../../../../../../../../hooks/useDownloadStatus";
|
|
12
12
|
import { useFileManifestDownload } from "../../../../../../../../hooks/useFileManifest/useFileManifestDownload";
|
|
13
|
+
import { useLoginGuard } from "../../../../../../../../providers/loginGuard/hook";
|
|
13
14
|
import { ButtonGroup } from "../../../../../../../common/ButtonGroup/buttonGroup";
|
|
14
15
|
import { ButtonGroupButton } from "../../../../../../../common/ButtonGroup/components/ButtonGroupButton/buttonGroupButton";
|
|
15
16
|
import {
|
|
@@ -46,6 +47,9 @@ export const FileManifestDownload = ({
|
|
|
46
47
|
const isInProgress = (isIdle || isLoading) && !disabled;
|
|
47
48
|
const isReady = Boolean(manifestURL) || disabled;
|
|
48
49
|
|
|
50
|
+
// Prompt user for login before download and copy, if required.
|
|
51
|
+
const { requireLogin } = useLoginGuard();
|
|
52
|
+
|
|
49
53
|
// Copies file manifest.
|
|
50
54
|
const copyManifestURL = (url?: string): void => {
|
|
51
55
|
if (!url) return;
|
|
@@ -89,15 +93,19 @@ export const FileManifestDownload = ({
|
|
|
89
93
|
action="Download file manifest"
|
|
90
94
|
disabled={disabled}
|
|
91
95
|
label={<DownloadIconSmall />}
|
|
92
|
-
onClick={
|
|
96
|
+
onClick={() =>
|
|
97
|
+
requireLogin(downloadManifestURL)
|
|
98
|
+
}
|
|
93
99
|
/>,
|
|
94
100
|
<ButtonGroupButton
|
|
95
101
|
key="copy"
|
|
96
102
|
action="Copy file manifest"
|
|
97
103
|
disabled={disabled}
|
|
98
104
|
label={<ContentCopyIconSmall />}
|
|
99
|
-
onClick={()
|
|
100
|
-
|
|
105
|
+
onClick={() =>
|
|
106
|
+
requireLogin((): void =>
|
|
107
|
+
copyManifestURL(manifestURL)
|
|
108
|
+
)
|
|
101
109
|
}
|
|
102
110
|
/>,
|
|
103
111
|
]}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import ArrowDropDownRoundedIcon from "@mui/icons-material/ArrowDropDownRounded";
|
|
2
2
|
import React, { MouseEvent } from "react";
|
|
3
|
+
import { DataDictionaryAnnotation } from "../../../../common/entities";
|
|
4
|
+
import { Tooltip } from "../../../DataDictionary/components/Tooltip/tooltip";
|
|
3
5
|
import { FilterLabel as Label } from "./filterLabel.styles";
|
|
4
6
|
|
|
5
7
|
export interface FilterLabelProps {
|
|
8
|
+
annotation?: DataDictionaryAnnotation;
|
|
6
9
|
count?: number;
|
|
7
10
|
disabled?: boolean;
|
|
8
11
|
isOpen: boolean;
|
|
@@ -11,6 +14,7 @@ export interface FilterLabelProps {
|
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export const FilterLabel = ({
|
|
17
|
+
annotation,
|
|
14
18
|
count,
|
|
15
19
|
disabled = false,
|
|
16
20
|
isOpen,
|
|
@@ -19,15 +23,17 @@ export const FilterLabel = ({
|
|
|
19
23
|
}: FilterLabelProps): JSX.Element => {
|
|
20
24
|
const filterLabel = count ? `${label}\xa0(${count})` : label; // When the count is present, a non-breaking space is used to prevent it from being on its own line
|
|
21
25
|
return (
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
<Tooltip description={annotation?.description} title={annotation?.label}>
|
|
27
|
+
<Label
|
|
28
|
+
color="inherit"
|
|
29
|
+
disabled={disabled}
|
|
30
|
+
endIcon={<ArrowDropDownRoundedIcon fontSize="small" />}
|
|
31
|
+
fullWidth
|
|
32
|
+
isOpen={isOpen}
|
|
33
|
+
onClick={onClick}
|
|
34
|
+
>
|
|
35
|
+
{filterLabel}
|
|
36
|
+
</Label>
|
|
37
|
+
</Tooltip>
|
|
32
38
|
);
|
|
33
39
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Box } from "@mui/material";
|
|
2
2
|
import React, { Fragment, useEffect, useRef, useState } from "react";
|
|
3
3
|
import { useFileLocation } from "../../../../hooks/useFileLocation";
|
|
4
|
+
import { useLoginGuard } from "../../../../providers/loginGuard/hook";
|
|
4
5
|
import { DownloadIcon } from "../../../common/CustomIcon/components/DownloadIcon/downloadIcon";
|
|
5
6
|
import { LoadingIcon } from "../../../common/CustomIcon/components/LoadingIcon/loadingIcon";
|
|
6
7
|
import { IconButton } from "../../../common/IconButton/iconButton";
|
|
@@ -29,6 +30,9 @@ export const AzulFileDownload = ({
|
|
|
29
30
|
const downloadRef = useRef<HTMLAnchorElement>(null);
|
|
30
31
|
const [isRequestPending, setIsRequestPending] = useState(false);
|
|
31
32
|
|
|
33
|
+
// Prompt user for login before download, if required.
|
|
34
|
+
const { requireLogin } = useLoginGuard();
|
|
35
|
+
|
|
32
36
|
// Initiates file download when file location request is successful.
|
|
33
37
|
useEffect(() => {
|
|
34
38
|
if (!fileUrl) return;
|
|
@@ -39,6 +43,13 @@ export const AzulFileDownload = ({
|
|
|
39
43
|
setIsRequestPending(false);
|
|
40
44
|
}, [fileUrl]);
|
|
41
45
|
|
|
46
|
+
// Initiates file download when download button is clicked.
|
|
47
|
+
const handleDownloadClick = (): void => {
|
|
48
|
+
setIsRequestPending(true);
|
|
49
|
+
trackFileDownloaded(entityName, relatedEntityId, relatedEntityName);
|
|
50
|
+
run();
|
|
51
|
+
};
|
|
52
|
+
|
|
42
53
|
return (
|
|
43
54
|
<Fragment>
|
|
44
55
|
{isRequestPending ? (
|
|
@@ -54,11 +65,7 @@ export const AzulFileDownload = ({
|
|
|
54
65
|
data-testid={AZUL_FILE_REQUEST_DOWNLOAD_TEST_ID}
|
|
55
66
|
disabled={!url}
|
|
56
67
|
Icon={isLoading ? LoadingIcon : DownloadIcon}
|
|
57
|
-
onClick={()
|
|
58
|
-
setIsRequestPending(true);
|
|
59
|
-
trackFileDownloaded(entityName, relatedEntityId, relatedEntityName);
|
|
60
|
-
run();
|
|
61
|
-
}}
|
|
68
|
+
onClick={() => requireLogin(handleDownloadClick)}
|
|
62
69
|
size="medium"
|
|
63
70
|
/>
|
|
64
71
|
)}
|
|
@@ -11,6 +11,7 @@ export function getEntityListTabs(entities: EntityConfig[]): Tab[] {
|
|
|
11
11
|
(
|
|
12
12
|
acc: Tab[],
|
|
13
13
|
{
|
|
14
|
+
annotation,
|
|
14
15
|
label,
|
|
15
16
|
listView: { enableTab = true } = {},
|
|
16
17
|
route,
|
|
@@ -20,6 +21,7 @@ export function getEntityListTabs(entities: EntityConfig[]): Tab[] {
|
|
|
20
21
|
) => {
|
|
21
22
|
if (enableTab) {
|
|
22
23
|
acc.push({
|
|
24
|
+
annotation,
|
|
23
25
|
icon,
|
|
24
26
|
iconPosition,
|
|
25
27
|
label,
|
|
@@ -2,9 +2,10 @@ import {
|
|
|
2
2
|
Divider,
|
|
3
3
|
ListItemIcon,
|
|
4
4
|
ListItemText,
|
|
5
|
+
Link as MLink,
|
|
5
6
|
MenuItem as MMenuItem,
|
|
6
7
|
} from "@mui/material";
|
|
7
|
-
import
|
|
8
|
+
import Link from "next/link";
|
|
8
9
|
import React, { Fragment, ReactNode } from "react";
|
|
9
10
|
import {
|
|
10
11
|
TEXT_BODY_400,
|
|
@@ -38,7 +39,6 @@ export const NavigationMenuItems = ({
|
|
|
38
39
|
menuItems,
|
|
39
40
|
pathname,
|
|
40
41
|
}: NavLinkMenuProps): JSX.Element => {
|
|
41
|
-
const router = useRouter();
|
|
42
42
|
return (
|
|
43
43
|
<>
|
|
44
44
|
{menuItems.map(
|
|
@@ -54,8 +54,9 @@ export const NavigationMenuItems = ({
|
|
|
54
54
|
url,
|
|
55
55
|
},
|
|
56
56
|
i
|
|
57
|
-
) =>
|
|
58
|
-
|
|
57
|
+
) => {
|
|
58
|
+
const isClientSide = isClientSideNavigation(url);
|
|
59
|
+
return nestedMenuItems ? (
|
|
59
60
|
<NavigationMenu
|
|
60
61
|
key={i}
|
|
61
62
|
closeAncestor={closeMenu}
|
|
@@ -69,18 +70,17 @@ export const NavigationMenuItems = ({
|
|
|
69
70
|
) : (
|
|
70
71
|
<Fragment key={i}>
|
|
71
72
|
<MMenuItem
|
|
73
|
+
component={isClientSide ? Link : MLink}
|
|
72
74
|
disabled={!url}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
REL_ATTRIBUTE.NO_OPENER_NO_REFERRER
|
|
81
|
-
);
|
|
82
|
-
}}
|
|
75
|
+
href={url}
|
|
76
|
+
onClick={(): void => closeMenu()}
|
|
77
|
+
rel={
|
|
78
|
+
isClientSide
|
|
79
|
+
? REL_ATTRIBUTE.NO_OPENER
|
|
80
|
+
: REL_ATTRIBUTE.NO_OPENER_NO_REFERRER
|
|
81
|
+
}
|
|
83
82
|
selected={isNavigationLinkSelected(pathname, selectedPatterns)}
|
|
83
|
+
target={target}
|
|
84
84
|
>
|
|
85
85
|
{icon && <ListItemIcon>{icon}</ListItemIcon>}
|
|
86
86
|
<ListItemText
|
|
@@ -100,7 +100,8 @@ export const NavigationMenuItems = ({
|
|
|
100
100
|
</MMenuItem>
|
|
101
101
|
{divider && <Divider />}
|
|
102
102
|
</Fragment>
|
|
103
|
-
)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
104
105
|
)}
|
|
105
106
|
</>
|
|
106
107
|
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NAVIGATION_TEST_ID = "navigation";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Button, Divider } from "@mui/material";
|
|
2
|
-
import
|
|
1
|
+
import { Button, Divider, Link as MLink } from "@mui/material";
|
|
2
|
+
import Link from "next/link";
|
|
3
3
|
import React, { CSSProperties, forwardRef, Fragment, ReactNode } from "react";
|
|
4
4
|
import { BreakpointKey } from "../../../../../../../../hooks/useBreakpointHelper";
|
|
5
5
|
import {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
REL_ATTRIBUTE,
|
|
8
8
|
} from "../../../../../../../Links/common/entities";
|
|
9
9
|
import { isClientSideNavigation } from "../../../../../../../Links/common/utils";
|
|
10
|
+
import { TestIdProps } from "../../../../../../../types";
|
|
10
11
|
import { SelectedMatch } from "../../../../common/entities";
|
|
11
12
|
import { HeaderProps } from "../../../../header";
|
|
12
13
|
import { isNavigationLinkSelected } from "./common/utils";
|
|
@@ -28,7 +29,7 @@ export interface NavLinkItem {
|
|
|
28
29
|
visible?: Partial<Record<BreakpointKey, boolean>>;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
export interface NavigationProps {
|
|
32
|
+
export interface NavigationProps extends TestIdProps {
|
|
32
33
|
className?: string;
|
|
33
34
|
closeAncestor?: () => void;
|
|
34
35
|
headerProps?: HeaderProps;
|
|
@@ -48,12 +49,18 @@ export const Navigation = forwardRef<HTMLDivElement, NavigationProps>(
|
|
|
48
49
|
links,
|
|
49
50
|
pathname,
|
|
50
51
|
style,
|
|
52
|
+
testId,
|
|
51
53
|
}: NavigationProps,
|
|
52
54
|
ref
|
|
53
55
|
): JSX.Element {
|
|
54
|
-
const router = useRouter();
|
|
55
56
|
return (
|
|
56
|
-
<Links
|
|
57
|
+
<Links
|
|
58
|
+
ref={ref}
|
|
59
|
+
className={className}
|
|
60
|
+
data-testid={testId}
|
|
61
|
+
isMenuIn={isMenuIn}
|
|
62
|
+
style={style}
|
|
63
|
+
>
|
|
57
64
|
{links.map(
|
|
58
65
|
(
|
|
59
66
|
{
|
|
@@ -65,8 +72,9 @@ export const Navigation = forwardRef<HTMLDivElement, NavigationProps>(
|
|
|
65
72
|
url,
|
|
66
73
|
},
|
|
67
74
|
i
|
|
68
|
-
) =>
|
|
69
|
-
|
|
75
|
+
) => {
|
|
76
|
+
const isClientSide = isClientSideNavigation(url);
|
|
77
|
+
return menuItems ? (
|
|
70
78
|
<Fragment key={i}>
|
|
71
79
|
{isMenuIn ? (
|
|
72
80
|
<NavigationDrawer
|
|
@@ -98,17 +106,16 @@ export const Navigation = forwardRef<HTMLDivElement, NavigationProps>(
|
|
|
98
106
|
) : (
|
|
99
107
|
<Fragment key={i}>
|
|
100
108
|
<Button
|
|
109
|
+
component={isClientSide ? Link : MLink}
|
|
101
110
|
disabled={!url}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
);
|
|
111
|
-
}}
|
|
111
|
+
href={url}
|
|
112
|
+
onClick={(): void => closeAncestor?.()}
|
|
113
|
+
rel={
|
|
114
|
+
isClientSide
|
|
115
|
+
? REL_ATTRIBUTE.NO_OPENER
|
|
116
|
+
: REL_ATTRIBUTE.NO_OPENER_NO_REFERRER
|
|
117
|
+
}
|
|
118
|
+
target={target}
|
|
112
119
|
variant={
|
|
113
120
|
isNavigationLinkSelected(pathname, selectedPatterns)
|
|
114
121
|
? "activeNav"
|
|
@@ -119,7 +126,8 @@ export const Navigation = forwardRef<HTMLDivElement, NavigationProps>(
|
|
|
119
126
|
</Button>
|
|
120
127
|
{divider && <Divider />}
|
|
121
128
|
</Fragment>
|
|
122
|
-
)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
123
131
|
)}
|
|
124
132
|
</Links>
|
|
125
133
|
);
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
renderIconButton as renderSearchIconButton,
|
|
22
22
|
Search,
|
|
23
23
|
} from "./components/Content/components/Actions/components/Search/search";
|
|
24
|
+
import { NAVIGATION_TEST_ID } from "./components/Content/components/Navigation/constants";
|
|
24
25
|
import { Navigation as DXNavigation } from "./components/Content/components/Navigation/navigation";
|
|
25
26
|
import { Slogan } from "./components/Content/components/Slogan/slogan";
|
|
26
27
|
import { Divider } from "./components/Content/components/Slogan/slogan.styles";
|
|
@@ -92,7 +93,11 @@ export const Header = ({ ...headerProps }: HeaderProps): JSX.Element => {
|
|
|
92
93
|
<Center>
|
|
93
94
|
{/* Center navigation */}
|
|
94
95
|
{isIn.isCenterNavigationIn && (
|
|
95
|
-
<DXNavigation
|
|
96
|
+
<DXNavigation
|
|
97
|
+
{...navigationProps}
|
|
98
|
+
testId={NAVIGATION_TEST_ID}
|
|
99
|
+
links={navItemsC}
|
|
100
|
+
/>
|
|
96
101
|
)}
|
|
97
102
|
</Center>
|
|
98
103
|
</Fade>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Button } from "../Button/button";
|
|
3
|
+
import { Props } from "./types";
|
|
4
|
+
|
|
5
|
+
export const Buttons = <P,>({
|
|
6
|
+
className,
|
|
7
|
+
handleLogin,
|
|
8
|
+
providers = [],
|
|
9
|
+
...props /* Mui ButtonProps */
|
|
10
|
+
}: Props<P>): JSX.Element[] => {
|
|
11
|
+
return providers?.map((provider) => (
|
|
12
|
+
<Button
|
|
13
|
+
key={provider.id}
|
|
14
|
+
className={className}
|
|
15
|
+
endIcon={"icon" in provider && provider.icon}
|
|
16
|
+
onClick={() => handleLogin(provider.id)}
|
|
17
|
+
{...props}
|
|
18
|
+
>
|
|
19
|
+
{provider.name}
|
|
20
|
+
</Button>
|
|
21
|
+
));
|
|
22
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ButtonProps } from "@mui/material";
|
|
2
|
+
import { ClientSafeProvider } from "next-auth/react";
|
|
3
|
+
import { OAuthProvider } from "../../../../config/entities";
|
|
4
|
+
import { BaseComponentProps } from "../../../../theme/common/entities";
|
|
5
|
+
|
|
6
|
+
export interface Props<P> extends BaseComponentProps, ButtonProps {
|
|
7
|
+
handleLogin: (providerId: string) => void;
|
|
8
|
+
providers?: ClientSafeProvider[] | OAuthProvider<P>[];
|
|
9
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
import { Grid2 } from "@mui/material";
|
|
3
|
+
|
|
4
|
+
export const StyledGrid2 = styled(Grid2)`
|
|
5
|
+
align-items: center;
|
|
6
|
+
align-self: flex-start;
|
|
7
|
+
display: flex;
|
|
8
|
+
gap: 12px;
|
|
9
|
+
|
|
10
|
+
.MuiTypography-text-body-400 {
|
|
11
|
+
.MuiLink-root {
|
|
12
|
+
color: inherit;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Checkbox, Typography } from "@mui/material";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { TEXT_BODY_400 } from "../../../../../../theme/common/typography";
|
|
4
|
+
import { CheckedIcon } from "../../../../../common/CustomIcon/components/CheckedIcon/checkedIcon";
|
|
5
|
+
import { UncheckedErrorIcon } from "../../../../../common/CustomIcon/components/UncheckedErrorIcon/uncheckedErrorIcon";
|
|
6
|
+
import { UncheckedIcon } from "../../../../../common/CustomIcon/components/UncheckedIcon/uncheckedIcon";
|
|
7
|
+
import { BaseComponentProps } from "../../../../../types";
|
|
8
|
+
import { StyledGrid2 } from "./consent.styles";
|
|
9
|
+
import { ConsentProps } from "./types";
|
|
10
|
+
|
|
11
|
+
export const Consent = ({
|
|
12
|
+
children,
|
|
13
|
+
className,
|
|
14
|
+
handleConsent,
|
|
15
|
+
isDisabled,
|
|
16
|
+
isError,
|
|
17
|
+
...props /* Mui Grid2Props */
|
|
18
|
+
}: BaseComponentProps & ConsentProps): JSX.Element | null => {
|
|
19
|
+
if (isDisabled) return null;
|
|
20
|
+
return (
|
|
21
|
+
<StyledGrid2 className={className} {...props}>
|
|
22
|
+
<Checkbox
|
|
23
|
+
checkedIcon={<CheckedIcon />}
|
|
24
|
+
icon={isError ? <UncheckedErrorIcon /> : <UncheckedIcon />}
|
|
25
|
+
onChange={handleConsent}
|
|
26
|
+
/>
|
|
27
|
+
<Typography variant={TEXT_BODY_400}>{children}</Typography>
|
|
28
|
+
</StyledGrid2>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Grid2Props } from "@mui/material";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { UseUserConsent } from "../../../../hooks/useUserConsent/types";
|
|
4
|
+
|
|
5
|
+
export interface ConsentProps
|
|
6
|
+
extends Grid2Props,
|
|
7
|
+
Pick<UseUserConsent, "handleConsent">,
|
|
8
|
+
Pick<UseUserConsent["state"], "isDisabled" | "isError"> {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|