From c16337d9a2d365e8ea2450ae34180e987d440424 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:51:24 +1200 Subject: [PATCH 01/27] fix(centralServer): Handle request access without project code --- .../central-server/src/apiV2/requestCountryAccess.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/central-server/src/apiV2/requestCountryAccess.js b/packages/central-server/src/apiV2/requestCountryAccess.js index 6c13db3472..701c6f36b0 100644 --- a/packages/central-server/src/apiV2/requestCountryAccess.js +++ b/packages/central-server/src/apiV2/requestCountryAccess.js @@ -32,10 +32,12 @@ const sendRequest = async (userId, models, countries, message, project) => { }, countries, message, - project: { - code: project.code, - permissionGroups: project.permission_groups.join(', '), - }, + project: project + ? { + code: project.code, + permissionGroups: project.permission_groups.join(', '), + } + : null, user, }, }); From a8f97ea33f75d2268589bb84d6ae0065b2743543 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:56:48 +1200 Subject: [PATCH 02/27] fix(tupaiaWeb): Fix button styling --- packages/ui-components/src/components/Button.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-components/src/components/Button.tsx b/packages/ui-components/src/components/Button.tsx index 43179a2cf2..c88e616b33 100644 --- a/packages/ui-components/src/components/Button.tsx +++ b/packages/ui-components/src/components/Button.tsx @@ -11,7 +11,7 @@ import { OverrideableComponentProps } from '../types'; const StyledButton = styled(MuiButton)` line-height: 1.75; letter-spacing: 0; - padding: 0.5rem 1.75rem; + padding: 0.5rem 1.2rem; box-shadow: none; min-width: 3rem; From afacbdf2155e994c4eb2e5e45abe23027583014a Mon Sep 17 00:00:00 2001 From: Salman <114740396+hrazasalman@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:53:09 +1000 Subject: [PATCH 03/27] fix(centralServer): Disable automatic cell conversion --- .../import/importEntities/extractEntitiesByCountryName.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js b/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js index 0e61976aac..7fd089ec8e 100644 --- a/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js +++ b/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js @@ -50,12 +50,12 @@ const processXlsxRow = (row, { countryName }) => { }; const xlsxParser = filePath => { - const workbook = xlsx.readFile(filePath); + const workbook = xlsx.readFile(filePath, { raw: false }); return Object.entries(workbook.Sheets).reduce( (entitiesByCountry, [countryName, sheet]) => ({ ...entitiesByCountry, [countryName]: xlsx.utils - .sheet_to_json(sheet) + .sheet_to_json(sheet, { raw: false }) .map(row => processXlsxRow(row, { countryName })), }), {}, From 88f89dd7c4f36d7eb6433339f0a2706476cb3343 Mon Sep 17 00:00:00 2001 From: Salman <114740396+hrazasalman@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:32:26 +1000 Subject: [PATCH 04/27] fix(lesmis): Fix blank dashboard --- packages/lesmis/src/views/DashboardView.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lesmis/src/views/DashboardView.jsx b/packages/lesmis/src/views/DashboardView.jsx index b41b9e5575..171913fccd 100644 --- a/packages/lesmis/src/views/DashboardView.jsx +++ b/packages/lesmis/src/views/DashboardView.jsx @@ -68,7 +68,7 @@ const getTabComponent = tabViewType => { }; export const DashboardView = React.memo(({ isOpen, setIsOpen }) => { - const isFetching = useIsFetching('dashboardReport'); + const isFetching = useIsFetching(['dashboardReport']); const { entityCode } = useUrlParams(); const { data: entityData } = useEntityData(entityCode); // eslint-disable-next-line no-unused-vars From 22ce0a5c785d2a495f0bbd5247dc4a9aa21f4da2 Mon Sep 17 00:00:00 2001 From: Salman <114740396+hrazasalman@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:13:35 +1000 Subject: [PATCH 05/27] fix(lesmis): fix blank dashboard --- packages/lesmis/src/api/queries/useVitalsData.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lesmis/src/api/queries/useVitalsData.js b/packages/lesmis/src/api/queries/useVitalsData.js index f2630dd76f..6d7b6f59c8 100644 --- a/packages/lesmis/src/api/queries/useVitalsData.js +++ b/packages/lesmis/src/api/queries/useVitalsData.js @@ -84,7 +84,7 @@ const useEntityReport = entity => ); const useEntityVitals = entity => { - const { data: results, isLoading } = useEntityReport(entity); + const { data: results, isInitialLoading: isLoading } = useEntityReport(entity); return { data: results?.data?.[0], From 40444a4377f52e5591421f14e5924751be33b24a Mon Sep 17 00:00:00 2001 From: Salman <114740396+hrazasalman@users.noreply.github.com> Date: Thu, 19 Sep 2024 19:56:43 +1000 Subject: [PATCH 06/27] fix project detail loader --- packages/tupaia-web/src/api/queries/useMapOverlays.ts | 7 ++++++- .../src/features/DashboardItem/DashboardItem.tsx | 2 +- .../Map/MapOverlaySelector/MapOverlaySelectorTitle.tsx | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/tupaia-web/src/api/queries/useMapOverlays.ts b/packages/tupaia-web/src/api/queries/useMapOverlays.ts index d341cb8711..fb288a6916 100644 --- a/packages/tupaia-web/src/api/queries/useMapOverlays.ts +++ b/packages/tupaia-web/src/api/queries/useMapOverlays.ts @@ -49,7 +49,12 @@ const mapOverlayByCode = ( */ export const useMapOverlays = (projectCode?: ProjectCode, entityCode?: EntityCode) => { const [urlSearchParams] = useSearchParams(); - const { data, isLoading, error, isFetched } = useQuery( + const { + data, + isInitialLoading: isLoading, + error, + isFetched, + } = useQuery( ['mapOverlays', projectCode, entityCode], (): Promise => get(`mapOverlays/${projectCode}/${entityCode}`), { diff --git a/packages/tupaia-web/src/features/DashboardItem/DashboardItem.tsx b/packages/tupaia-web/src/features/DashboardItem/DashboardItem.tsx index 7fb166635a..94cbbf6d5e 100644 --- a/packages/tupaia-web/src/features/DashboardItem/DashboardItem.tsx +++ b/packages/tupaia-web/src/features/DashboardItem/DashboardItem.tsx @@ -85,7 +85,7 @@ export const DashboardItem = ({ dashboardItem }: { dashboardItem: DashboardItemT const { data: report, - isLoading, + isInitialLoading: isLoading, error, refetch, } = useReport( diff --git a/packages/tupaia-web/src/features/Map/MapOverlaySelector/MapOverlaySelectorTitle.tsx b/packages/tupaia-web/src/features/Map/MapOverlaySelector/MapOverlaySelectorTitle.tsx index a64370505b..42005a3ff6 100644 --- a/packages/tupaia-web/src/features/Map/MapOverlaySelector/MapOverlaySelectorTitle.tsx +++ b/packages/tupaia-web/src/features/Map/MapOverlaySelector/MapOverlaySelectorTitle.tsx @@ -70,7 +70,7 @@ export const MapOverlaySelectorTitle = () => { projectCode, entityCode, ); - const { isLoading: isLoadingOverlayData, error, refetch } = useMapOverlayMapData(); + const { isInitialLoading: isLoadingOverlayData, error, refetch } = useMapOverlayMapData(); const { data: entity } = useEntity(projectCode, entityCode); const isLoading = From b8ff7edb406acfc4770fd15ab632502cb6bb41b8 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:29:06 +1200 Subject: [PATCH 07/27] fix(adminPanel): Fix colours in admin panel filter tables --- .../src/components/FilterableTable/FilterCell.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/ui-components/src/components/FilterableTable/FilterCell.tsx b/packages/ui-components/src/components/FilterableTable/FilterCell.tsx index 0524f22f7d..a0618cacf7 100644 --- a/packages/ui-components/src/components/FilterableTable/FilterCell.tsx +++ b/packages/ui-components/src/components/FilterableTable/FilterCell.tsx @@ -45,7 +45,10 @@ const FilterWrapper = styled.div` padding-block: 0.5rem; } .MuiInputBase-input::-webkit-input-placeholder { - color: ${({ theme }) => theme.palette.text.secondary}; + color: #b8b8b8; + } + .MuiInputBase-adornedStart .MuiSvgIcon-root { + color: #b8b8b8; } `; From 876e996175eeb5eed32ec581d29721e2c9372be4 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:46:05 +1200 Subject: [PATCH 08/27] fix(adminPanel): Fix import modal in viz builder --- .../components/PreviewOptions/ImportModal.jsx | 190 ++++++++++++++++++ .../PreviewOptions/PreviewOptions.jsx | 3 +- 2 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/ImportModal.jsx diff --git a/packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/ImportModal.jsx b/packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/ImportModal.jsx new file mode 100644 index 0000000000..d83e3645fb --- /dev/null +++ b/packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/ImportModal.jsx @@ -0,0 +1,190 @@ +/* + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ + +import Typography from '@material-ui/core/Typography'; +import PropTypes from 'prop-types'; +import React, { useCallback, useState } from 'react'; +import styled from 'styled-components'; + +import { + SmallAlert, + Button, + OutlinedButton, + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + FileUploadField, + LoadingContainer, +} from '@tupaia/ui-components'; + +const STATUS = { + IDLE: 'idle', + LOADING: 'loading', + SUCCESS: 'success', + ERROR: 'error', +}; + +const Content = styled(DialogContent)` + text-align: left; + min-height: 220px; +`; + +const Heading = styled(Typography)` + margin-bottom: 18px; +`; + +export const ImportModal = ({ + isOpen, + title, + subtitle, + actionText, + loadingText, + loadingHeading, + showLoadingContainer, + onSubmit, + onClose, +}) => { + const [status, setStatus] = useState(STATUS.IDLE); + const [errorMessage, setErrorMessage] = useState(null); + const [successMessage, setSuccessMessage] = useState(null); + const [file, setFile] = useState(null); + + const handleSubmit = async event => { + event.preventDefault(); + setErrorMessage(null); + setStatus(STATUS.LOADING); + + try { + const { message } = await onSubmit(file); + if (showLoadingContainer && message) { + setStatus(STATUS.SUCCESS); + setSuccessMessage(message); + } else { + handleClose(); + } + } catch (error) { + setStatus(STATUS.ERROR); + setErrorMessage(error.message); + } + }; + + const handleClose = async () => { + onClose(); + + setStatus(STATUS.IDLE); + setErrorMessage(null); + setSuccessMessage(null); + setFile(null); + }; + + const handleDismiss = () => { + setStatus(STATUS.IDLE); + setErrorMessage(null); + setSuccessMessage(null); + // Deselect file when dismissing an error, this avoids an error when editing selected files + // @see https://github.com/beyondessential/tupaia-backlog/issues/1211 + setFile(null); + }; + + const ContentContainer = showLoadingContainer + ? ({ children }) => ( + + {children} + + ) + : React.Fragment; + + const renderContent = useCallback(() => { + switch (status) { + case STATUS.SUCCESS: + return

{successMessage}

; + case STATUS.ERROR: + return ( + <> + An error has occurred. + + {errorMessage} + + + ); + default: + return ( + <> +

{subtitle}

+
+ setFile(files[0])} name="file-upload" /> + + + ); + } + }, [status, successMessage, errorMessage, subtitle]); + + const renderButtons = useCallback(() => { + switch (status) { + case STATUS.SUCCESS: + return ; + case STATUS.ERROR: + return ( + <> + Dismiss + + + ); + default: + return ( + <> + + + + ); + } + }, [status, file, handleDismiss, handleClose, handleSubmit]); + + return ( + + + + {renderContent()} + + {renderButtons()} + + ); +}; + +ImportModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + title: PropTypes.string, + subtitle: PropTypes.string, + actionText: PropTypes.string, + loadingText: PropTypes.string, + loadingHeading: PropTypes.string, + showLoadingContainer: PropTypes.bool, + onSubmit: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, +}; + +ImportModal.defaultProps = { + title: 'Import', + subtitle: '', + actionText: 'Import', + loadingText: 'Importing', + loadingHeading: 'Importing data', + showLoadingContainer: false, +}; diff --git a/packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/PreviewOptions.jsx b/packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/PreviewOptions.jsx index af20a122eb..bcdf62a9b2 100644 --- a/packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/PreviewOptions.jsx +++ b/packages/admin-panel/src/VizBuilderApp/components/PreviewOptions/PreviewOptions.jsx @@ -13,7 +13,7 @@ import { useUploadTestData } from '../../api'; import { ProjectField } from './ProjectField'; import { LocationField } from './LocationField'; import { DateRangeField } from './DateRangeField'; -import { ImportModal } from '../../../importExport'; +import { ImportModal } from './ImportModal'; const Container = styled(FlexSpaceBetween)` padding: 24px 0; @@ -58,6 +58,7 @@ const UploadDataModal = ({ isOpen, onSubmit, onClose }) => ( actionText="Upload" loadingText="Uploading" showLoadingContainer={false} + hasCustomButton={true} /> ); From 4a737f4845cc10cc0a0b066432befc4346547ad4 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:08:46 +1200 Subject: [PATCH 09/27] fix(adminPanel): Fix entity type for measure level --- packages/types/src/schemas/schemas.ts | 475 ++++-------------- .../src/types/models-extra/mapOverlay.ts | 3 +- 2 files changed, 97 insertions(+), 381 deletions(-) diff --git a/packages/types/src/schemas/schemas.ts b/packages/types/src/schemas/schemas.ts index 36de1737fa..ac6adde0af 100644 --- a/packages/types/src/schemas/schemas.ts +++ b/packages/types/src/schemas/schemas.ts @@ -31481,10 +31481,7 @@ export const MeasureConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -31629,10 +31626,7 @@ export const DisplayedValueTypeSchema = { } export const EntityLevelSchema = { - "type": "array", - "items": { - "type": "string" - } + "type": "string" } export const MeasureValueTypeSchema = { @@ -31928,10 +31922,7 @@ export const BaseMapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -32029,10 +32020,7 @@ export const BaseMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -32120,10 +32108,7 @@ export const BaseMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -32502,10 +32487,7 @@ export const SpectrumMapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -32603,10 +32585,7 @@ export const SpectrumMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -32694,10 +32673,7 @@ export const SpectrumMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -33181,10 +33157,7 @@ export const IconMapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -33282,10 +33255,7 @@ export const IconMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -33373,10 +33343,7 @@ export const IconMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -33785,10 +33752,7 @@ export const RadiusMapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -33886,10 +33850,7 @@ export const RadiusMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -33977,10 +33938,7 @@ export const RadiusMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -34363,10 +34321,7 @@ export const ColorMapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -34464,10 +34419,7 @@ export const ColorMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -34555,10 +34507,7 @@ export const ColorMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -34955,10 +34904,7 @@ export const ShadingMapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -35056,10 +35002,7 @@ export const ShadingMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -35147,10 +35090,7 @@ export const ShadingMapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -35539,10 +35479,7 @@ export const MapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -35640,10 +35577,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -35731,10 +35665,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -36217,10 +36148,7 @@ export const MapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -36318,10 +36246,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -36409,10 +36334,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -36820,10 +36742,7 @@ export const MapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -36921,10 +36840,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -37012,10 +36928,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -37397,10 +37310,7 @@ export const MapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -37498,10 +37408,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -37589,10 +37496,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -37988,10 +37892,7 @@ export const MapOverlayConfigSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -38089,10 +37990,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -38180,10 +38078,7 @@ export const MapOverlayConfigSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -69719,10 +69614,7 @@ export const MapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -69820,10 +69712,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -69911,10 +69800,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -70397,10 +70283,7 @@ export const MapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -70498,10 +70381,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -70589,10 +70469,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -71000,10 +70877,7 @@ export const MapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -71101,10 +70975,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -71192,10 +71063,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -71577,10 +71445,7 @@ export const MapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -71678,10 +71543,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -71769,10 +71631,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -72168,10 +72027,7 @@ export const MapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -72269,10 +72125,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -72360,10 +72213,7 @@ export const MapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -72813,10 +72663,7 @@ export const MapOverlayCreateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -72914,10 +72761,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -73005,10 +72849,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -73491,10 +73332,7 @@ export const MapOverlayCreateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -73592,10 +73430,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -73683,10 +73518,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -74094,10 +73926,7 @@ export const MapOverlayCreateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -74195,10 +74024,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -74286,10 +74112,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -74671,10 +74494,7 @@ export const MapOverlayCreateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -74772,10 +74592,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -74863,10 +74680,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -75262,10 +75076,7 @@ export const MapOverlayCreateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -75363,10 +75174,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -75454,10 +75262,7 @@ export const MapOverlayCreateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -75900,10 +75705,7 @@ export const MapOverlayUpdateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -76001,10 +75803,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -76092,10 +75891,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -76578,10 +76374,7 @@ export const MapOverlayUpdateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -76679,10 +76472,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -76770,10 +76560,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -77181,10 +76968,7 @@ export const MapOverlayUpdateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -77282,10 +77066,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -77373,10 +77154,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -77758,10 +77536,7 @@ export const MapOverlayUpdateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -77859,10 +77634,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -77950,10 +77722,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -78349,10 +78118,7 @@ export const MapOverlayUpdateSchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -78450,10 +78216,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -78541,10 +78304,7 @@ export const MapOverlayUpdateSchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -93025,10 +92785,7 @@ export const TranslatedMapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -93126,10 +92883,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -93217,10 +92971,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -93726,10 +93477,7 @@ export const TranslatedMapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -93827,10 +93575,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -93918,10 +93663,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -94352,10 +94094,7 @@ export const TranslatedMapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -94453,10 +94192,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -94544,10 +94280,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -94952,10 +94685,7 @@ export const TranslatedMapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -95053,10 +94783,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -95144,10 +94871,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", @@ -95566,10 +95290,7 @@ export const TranslatedMapOverlaySchema = { }, "displayOnLevel": { "description": "This setting defines the level of the entity hierarchy from where we start rendering the map overlay.\nUse this if we want to only render the map overlay below a certain level.\neg. If rendering the map overlay at the country level causes performance issues, set displayOnLevel: SubDistrict to only start rendering at Sub District", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "displayedValueKey": { "description": "Use to override the default column of data that we display", @@ -95667,10 +95388,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "values": { "description": "Level of the entity hierarchy that this map overlay has data for", @@ -95758,10 +95476,7 @@ export const TranslatedMapOverlaySchema = { }, "measureLevel": { "description": "Level of the entity hierarchy that this map overlay has data for", - "type": "array", - "items": { - "type": "string" - } + "type": "string" }, "noDataColour": { "description": "The colour to use when there is no data", diff --git a/packages/types/src/types/models-extra/mapOverlay.ts b/packages/types/src/types/models-extra/mapOverlay.ts index b20253a751..3bd773dca9 100644 --- a/packages/types/src/types/models-extra/mapOverlay.ts +++ b/packages/types/src/types/models-extra/mapOverlay.ts @@ -7,6 +7,7 @@ import { PascalCase } from '../../utils'; import { CssColor } from '../css'; import { EntityType } from './entityType'; import { DateOffsetSpec, DefaultTimePeriod, ReferenceProps, VizPeriodGranularity } from './common'; +import { EntityTypeEnum } from '../models'; /** * @description A key that can be used to reference a value in a measureConfig, or to reference all values @@ -123,7 +124,7 @@ enum DisplayedValueType { FACILITY_TYPE_NAME = 'facilityTypeName', } -type EntityLevel = PascalCase; +type EntityLevel = PascalCase | EntityType; enum MeasureValueType { BOOLEAN = 'boolean', From abfda678e27227f2fdfb804525aea1e0c9d75c87 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:17:54 +1200 Subject: [PATCH 10/27] fix(datatrakWeb): Fix report survey filtering --- .../datatrak-web-server/src/routes/SurveysRoute.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/datatrak-web-server/src/routes/SurveysRoute.ts b/packages/datatrak-web-server/src/routes/SurveysRoute.ts index 46fbd2937a..5b372cc2ba 100644 --- a/packages/datatrak-web-server/src/routes/SurveysRoute.ts +++ b/packages/datatrak-web-server/src/routes/SurveysRoute.ts @@ -25,11 +25,17 @@ export class SurveysRoute extends Route { const { fields = [], projectId, countryCode } = query; const country = await models.country.findOne({ code: countryCode }); - const surveys = await ctx.services.central.fetchResources(`countries/${country.id}/surveys`, { + const queryUrl = countryCode ? `countries/${country.id}/surveys` : 'surveys'; + + const filter: Record = {}; + + if (projectId) { + filter.project_id = projectId; + } + + const surveys = await ctx.services.central.fetchResources(queryUrl, { ...query, - filter: { - project_id: projectId, - }, + filter, columns: fields, pageSize: 'ALL', // Override default page size of 100 }); From 9c6d75771fc9150c10f63dce2e84ed64e4fe4f7c Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:31:18 +1200 Subject: [PATCH 11/27] fix(datatrakWeb): Fix changing search value --- .../src/features/Reports/Inputs/EntitySelectorInput.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/datatrak-web/src/features/Reports/Inputs/EntitySelectorInput.tsx b/packages/datatrak-web/src/features/Reports/Inputs/EntitySelectorInput.tsx index 9d5db0a339..9b1c8532a3 100644 --- a/packages/datatrak-web/src/features/Reports/Inputs/EntitySelectorInput.tsx +++ b/packages/datatrak-web/src/features/Reports/Inputs/EntitySelectorInput.tsx @@ -72,7 +72,8 @@ export const EntitySelectorInput = ({ selectedEntityLevel }: EntitySelectorInput } getOptionLabel={option => option.label} placeholder={`Select ${label.toLowerCase()}...`} - onInputChange={throttle((_, newValue) => { + onInputChange={throttle((e, newValue) => { + if (!e?.target) return; setSearchText(newValue); }, 200)} required From 798e313eefd85c36b54d409179dee0a07b4e2c18 Mon Sep 17 00:00:00 2001 From: Tom Caiger Date: Fri, 20 Sep 2024 17:15:27 +1200 Subject: [PATCH 12/27] Update buildDeployablePackages.sh --- .../devops/scripts/deployment-aws/buildDeployablePackages.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/devops/scripts/deployment-aws/buildDeployablePackages.sh b/packages/devops/scripts/deployment-aws/buildDeployablePackages.sh index 1500eceb2b..3fdd54f77e 100755 --- a/packages/devops/scripts/deployment-aws/buildDeployablePackages.sh +++ b/packages/devops/scripts/deployment-aws/buildDeployablePackages.sh @@ -13,6 +13,7 @@ PACKAGES=$(${TUPAIA_DIR}/scripts/bash/getDeployablePackages.sh) # Install external dependencies and build internal dependencies cd ${TUPAIA_DIR} yarn install --immutable +chmod 755 node_modules/@babel/cli/bin/babel.js # "postinstall" hook may only fire if the dependency tree changes. This may not happen on feature branches based off dev, # because our AMI performs a yarn install already. In this case we can end up in a situation where "internal-depenednecies" From 5c062473760869977064b670e5177f26fa6283ee Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:58:42 +1200 Subject: [PATCH 13/27] feat(tupaiaWeb): RN-1413: Enable projects search by country (#5890) * Projects search * Sorting * remove debug * Fix colours * Update country handling to always show all countries * Hide unneeded countries * No results message --------- Co-authored-by: Andrew --- .../tupaia-web-server/src/app/createApp.ts | 1 + .../src/routes/CountriesRoute.ts | 38 ++++++++ .../tupaia-web-server/src/routes/index.ts | 2 + packages/tupaia-web/src/api/queries/index.ts | 1 + .../src/api/queries/useCountries.ts | 12 +++ .../ProjectCardList/ProjectCardList.tsx | 73 ++++++++++---- .../tupaia-web/src/views/ProjectsModal.tsx | 96 +++++++++++++++++-- 7 files changed, 198 insertions(+), 25 deletions(-) create mode 100644 packages/tupaia-web-server/src/routes/CountriesRoute.ts create mode 100644 packages/tupaia-web/src/api/queries/useCountries.ts diff --git a/packages/tupaia-web-server/src/app/createApp.ts b/packages/tupaia-web-server/src/app/createApp.ts index aa6cbd3dc7..36e2626598 100644 --- a/packages/tupaia-web-server/src/app/createApp.ts +++ b/packages/tupaia-web-server/src/app/createApp.ts @@ -47,6 +47,7 @@ export async function createApp(db: TupaiaDatabase = new TupaiaDatabase()) { 'dashboards/:projectCode/:entityCode', handleWith(routes.DashboardsRoute), ) + .get('countries', handleWith(routes.CountriesRoute)) .post( 'dashboards/:projectCode/:entityCode/:dashboardCode/export', handleWith(routes.ExportDashboardRoute), diff --git a/packages/tupaia-web-server/src/routes/CountriesRoute.ts b/packages/tupaia-web-server/src/routes/CountriesRoute.ts new file mode 100644 index 0000000000..0996b68b06 --- /dev/null +++ b/packages/tupaia-web-server/src/routes/CountriesRoute.ts @@ -0,0 +1,38 @@ +/** + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ + +import { Request } from 'express'; +import { Route } from '@tupaia/server-boilerplate'; +import { Entity } from '@tupaia/types'; + +export type CountriesRequest = Request< + Record, + Partial[], + Record, + Record +>; + +export class CountriesRoute extends Route { + public async buildResponse() { + const { models } = this.req; + + const countries = await models.entity.find( + { + code: { + comparator: 'not in', + // Hide TL and UNFPA Warehouse from the search results + comparisonValue: ['TL', 'UW'], + }, + type: 'country', + }, + { + columns: ['code', 'name'], + sort: ['name ASC'], + }, + ); + + return Promise.all(countries.map(country => country.getData())); + } +} diff --git a/packages/tupaia-web-server/src/routes/index.ts b/packages/tupaia-web-server/src/routes/index.ts index 9b90788b87..ee95acce3d 100644 --- a/packages/tupaia-web-server/src/routes/index.ts +++ b/packages/tupaia-web-server/src/routes/index.ts @@ -38,3 +38,5 @@ export { } from './UnsubscribeDashboardMailingListRoute'; export { ExportMapOverlayRequest, ExportMapOverlayRoute } from './ExportMapOverlayRoute'; + +export { CountriesRequest, CountriesRoute } from './CountriesRoute'; diff --git a/packages/tupaia-web/src/api/queries/index.ts b/packages/tupaia-web/src/api/queries/index.ts index 6ea04804c1..e533737a99 100644 --- a/packages/tupaia-web/src/api/queries/index.ts +++ b/packages/tupaia-web/src/api/queries/index.ts @@ -16,3 +16,4 @@ export { useReport } from './useReport'; export { useMapOverlayReport } from './useMapOverlayReport'; export { useMapOverlays } from './useMapOverlays'; export { useEntitySearch } from './useEntitySearch'; +export { useCountries } from './useCountries'; diff --git a/packages/tupaia-web/src/api/queries/useCountries.ts b/packages/tupaia-web/src/api/queries/useCountries.ts new file mode 100644 index 0000000000..f280808da4 --- /dev/null +++ b/packages/tupaia-web/src/api/queries/useCountries.ts @@ -0,0 +1,12 @@ +/* + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ + +import { useQuery } from '@tanstack/react-query'; +import { Country } from '@tupaia/types'; +import { get } from '../api'; + +export const useCountries = () => { + return useQuery(['countries'], (): Promise[]> => get('countries')); +}; diff --git a/packages/tupaia-web/src/layout/ProjectCardList/ProjectCardList.tsx b/packages/tupaia-web/src/layout/ProjectCardList/ProjectCardList.tsx index 38ef62204d..da01ee6bcd 100644 --- a/packages/tupaia-web/src/layout/ProjectCardList/ProjectCardList.tsx +++ b/packages/tupaia-web/src/layout/ProjectCardList/ProjectCardList.tsx @@ -8,15 +8,22 @@ import { ProjectCard as ProjectCardComponent } from './ProjectCard'; import { PROJECT_ACCESS_TYPES } from '../../constants'; import { getProjectAccessType } from '../../utils'; import { SingleProject } from '../../types'; +import { Typography } from '@material-ui/core'; +import styled from 'styled-components'; const EXPLORE_CODE = 'explore'; +const NoResultsMessage = styled(Typography)` + font-size: 0.875rem; +`; + interface ProjectCardListProps { projects: SingleProject[]; actions: { [key: string]: (props: any) => JSX.Element; }; ProjectCard?: (props: any) => JSX.Element; // this is to allow for legacy project cards to be used, e.g. in the projects modal + selectedCountry?: string; } type SortedProject = SingleProject & { @@ -27,27 +34,61 @@ export const ProjectCardList = ({ projects, actions, ProjectCard = ProjectCardComponent, + selectedCountry, }: ProjectCardListProps) => { - const sortedProjects = Object.keys(PROJECT_ACCESS_TYPES).reduce((result, accessType) => { - const action = actions[PROJECT_ACCESS_TYPES[accessType as keyof typeof PROJECT_ACCESS_TYPES]]; - // If there is no action passed in for this access type, then the project card is useless, so ignore it so that nothing breaks - if (!action) return result; - const accessTypeProjects = projects.filter(project => { - const projectAccessType = getProjectAccessType(project); - return project.code !== EXPLORE_CODE && projectAccessType === accessType; - }); - return [ - ...result, - ...accessTypeProjects - .sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)) + const getActionButton = (project: SingleProject) => { + const projectAccessType = getProjectAccessType(project); + if (!projectAccessType) { + return () => <>; + } + const action = actions[PROJECT_ACCESS_TYPES[projectAccessType]]; + if (!action) { + return () => <>; + } + return action; + }; + const getSortedProjects = () => { + const exploreProjectRemoved = projects.filter(project => project.code !== EXPLORE_CODE); + if (selectedCountry) { + return exploreProjectRemoved + .filter(project => { + return project.names.includes(selectedCountry); + }) + .sort((a, b) => a.name.localeCompare(b.name)) .map(project => ({ ...project, - ActionButton: actions[accessType], - })), - ]; - }, [] as SortedProject[]); + ActionButton: getActionButton(project), + })); + } + + // when no country is selected, order by access type and then by sortOrder + return Object.keys(PROJECT_ACCESS_TYPES).reduce((result, accessType) => { + const action = actions[PROJECT_ACCESS_TYPES[accessType as keyof typeof PROJECT_ACCESS_TYPES]]; + // If there is no action passed in for this access type, then the project card is useless, so ignore it so that nothing breaks + if (!action) return result; + const accessTypeProjects = exploreProjectRemoved.filter(project => { + const projectAccessType = getProjectAccessType(project); + return projectAccessType === accessType; + }); + return [ + ...result, + ...accessTypeProjects + .sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)) + .map(project => ({ + ...project, + ActionButton: actions[accessType], + })), + ]; + }, [] as SortedProject[]); + }; + + const sortedProjects = getSortedProjects(); // Have to wrap this in a fragment so that consuming components don't throw a TS error about type of component not being valid + + if (sortedProjects.length === 0) { + return No results found; + } return ( <> {sortedProjects.map(project => { diff --git a/packages/tupaia-web/src/views/ProjectsModal.tsx b/packages/tupaia-web/src/views/ProjectsModal.tsx index cd3ae32f28..9655409fd4 100644 --- a/packages/tupaia-web/src/views/ProjectsModal.tsx +++ b/packages/tupaia-web/src/views/ProjectsModal.tsx @@ -3,10 +3,10 @@ * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd */ -import React from 'react'; +import React, { useState } from 'react'; import styled from 'styled-components'; import { useLocation } from 'react-router'; -import { SpinningLoader } from '@tupaia/ui-components'; +import { Autocomplete, SpinningLoader } from '@tupaia/ui-components'; import { Typography } from '@material-ui/core'; import { MODAL_ROUTES, @@ -16,7 +16,7 @@ import { URL_SEARCH_PARAMS, MOBILE_BREAKPOINT, } from '../constants'; -import { useProjects, useUser } from '../api/queries'; +import { useCountries, useProjects, useUser } from '../api/queries'; import { ProjectAllowedLink, ProjectCardList, @@ -28,6 +28,8 @@ import { Modal, RouterButton } from '../components'; import { SingleProject } from '../types'; import { useModal } from '../utils'; +const OFF_WHITE = '#B8B8B8'; + const Wrapper = styled.div` display: flex; flex-direction: column; @@ -87,17 +89,24 @@ const ExploreButton = styled(RouterButton).attrs({ `; const Line = styled.div` - background-color: #9ba0a6; + background-color: ${({ theme }) => theme.palette.text.secondary}; height: 1px; margin-top: 0.7rem; `; -const ProjectsTitle = styled(Typography)` +const ProjectsTitle = styled(Typography).attrs({ + variant: 'h1', +})` color: ${({ theme }) => theme.palette.text.primary}; - font-size: 1.5rem; + font-size: 1.3rem; font-weight: 500; - margin-top: 1.8rem; - margin-left: 0.4rem; +`; + +const ProjectsTitleWrapper = styled.div` + display: flex; + align-items: center; + margin-block-start: 1rem; + margin-inline-start: 0.4rem; `; const Logo = styled.img` @@ -113,14 +122,57 @@ const Loader = styled.div` align-items: center; `; +const AutoCompleteWrapper = styled.div` + border-left: 1px solid ${({ theme }) => theme.palette.text.secondary}; + margin-inline-start: 0.9rem; + padding-inline-start: 1.3rem; + width: 100%; + max-width: 19rem; +`; + +const SearchAutocomplete = styled(Autocomplete)` + .MuiInputBase-root { + background-color: ${({ theme }) => theme.palette.background.paper}; + } + .MuiFormControl-root { + margin-block-end: 0; + } + .MuiOutlinedInput-notchedOutline { + border-color: ${OFF_WHITE}; + } + .MuiInputBase-input::placeholder { + color: ${OFF_WHITE}; + font-size: 0.875rem; + } + .MuiInputBase-input { + font-size: 0.875rem; + } + .MuiAutocomplete-endAdornment { + top: initial; + } + .MuiSvgIcon-root { + color: ${OFF_WHITE}; + } +`; + +const Option = styled.span` + font-size: 0.875rem; +`; + /** * This is the projects view that is shown when the projects modal is open */ export const ProjectsModal = () => { + const [searchTerm, setSearchTerm] = useState(''); + const [selectedCountry, setSelectedCountry] = useState<{ + label: string; + value: string; + } | null>(null); const { closeModal } = useModal(); const { data, isFetching } = useProjects(); const { isLoggedIn } = useUser(); const location = useLocation(); + const { data: countries, isLoading } = useCountries(); return ( @@ -134,7 +186,32 @@ export const ProjectsModal = () => {
Explore tupaia.org - Projects + + Projects + + ({ label: name, value: name })) ?? []} + loading={isLoading} + placeholder="Search country..." + onInputChange={(_, newValue) => setSearchTerm(newValue)} + getOptionLabel={option => option.label} + value={selectedCountry} + onChange={(_, newValue) => { + return setSelectedCountry(newValue); + }} + renderOption={({ label }) => } + muiProps={{ + filterOptions: options => { + if (!searchTerm) return options; + return options.filter(option => + option.label.toLowerCase().startsWith(searchTerm.toLowerCase()), + ); + }, + }} + getOptionSelected={(option, value) => option.value === value} + /> + + {isFetching ? ( @@ -142,6 +219,7 @@ export const ProjectsModal = () => { ) : ( Date: Thu, 26 Sep 2024 16:24:58 +1200 Subject: [PATCH 14/27] feat(tupaiaWeb): RN-1304: Date offsets for year granularities (#5695) * Update periodGranularities.js * Update types * Back and forward buttons working * Single years * WIP year ranges * range year picker * Fix labels * Naming and labeling * working period offsets * Working date ranges * Remove unsued var * Generate types * Fix issues with other single dates * Update types descriptions * Fix default date and year handling * handle offsets in utils * Add dateOffset types * Update types * tupaia web * Update useDateRanges.ts * Display correct values * Working picker * Single period change via arrows * Tidy ups * Fix merge conflicts * Update DatePickerDialog.tsx * Fix rounding of start dates * Update to only support quarters and months * Update types export * Fix types * Update periodGranularities.js * Handle dates in the future --------- Co-authored-by: Andrew --- .../src/components/DateRangePicker.tsx | 8 +- .../EnlargedDashboardVisual.tsx | 2 + .../tupaia-web/src/utils/useDateRanges.ts | 7 +- packages/types/src/schemas/schemas.ts | 3096 +++++++++++++++++ packages/types/src/types/index.ts | 2 + .../models-extra/dashboard-item/common.ts | 17 + .../models-extra/dashboard-item/index.ts | 2 +- .../types/src/types/models-extra/index.ts | 5 +- .../DateRangePicker/DateRangePicker.test.jsx | 92 +- .../components/DateRangePicker/DatePicker.tsx | 2 +- .../DateRangePicker/DatePickerDialog.tsx | 76 +- .../DateRangePicker/DateRangePicker.tsx | 9 + .../components/DateRangePicker/YearPicker.tsx | 164 +- .../DateRangePicker/useDateRangePicker.tsx | 132 +- .../src/types/date-picker-types.ts | 7 +- .../period/periodGranularities.test.js | 101 + .../utils/src/period/periodGranularities.js | 101 +- 17 files changed, 3716 insertions(+), 107 deletions(-) diff --git a/packages/tupaia-web/src/components/DateRangePicker.tsx b/packages/tupaia-web/src/components/DateRangePicker.tsx index 0d388d6f0d..8f7293f56a 100644 --- a/packages/tupaia-web/src/components/DateRangePicker.tsx +++ b/packages/tupaia-web/src/components/DateRangePicker.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { Moment } from 'moment'; -import { VizPeriodGranularity } from '@tupaia/types'; +import { DatePickerOffsetSpec, VizPeriodGranularity } from '@tupaia/types'; import { DateRangePicker as DateRangePickerComponent, TextButton } from '@tupaia/ui-components'; import styled from 'styled-components'; @@ -84,6 +84,8 @@ interface DateRangePickerProps { maxDate?: string; onResetDate?: () => void; weekDisplayFormat?: string; + dateOffset?: DatePickerOffsetSpec; + dateRangeDelimiter?: string; } export const DateRangePicker = ({ @@ -95,6 +97,8 @@ export const DateRangePicker = ({ onSetDates, onResetDate, weekDisplayFormat, + dateOffset, + dateRangeDelimiter, }: DateRangePickerProps) => { return ( @@ -109,6 +113,8 @@ export const DateRangePicker = ({ dialogProps={{ PaperComponent: DialogPaperComponent, }} + dateOffset={dateOffset} + dateRangeDelimiter={dateRangeDelimiter} /> Reset to default diff --git a/packages/tupaia-web/src/features/EnlargedDashboardItem/EnlargedDashboardVisual.tsx b/packages/tupaia-web/src/features/EnlargedDashboardItem/EnlargedDashboardVisual.tsx index 15eea67c30..3e4e93e000 100644 --- a/packages/tupaia-web/src/features/EnlargedDashboardItem/EnlargedDashboardVisual.tsx +++ b/packages/tupaia-web/src/features/EnlargedDashboardItem/EnlargedDashboardVisual.tsx @@ -164,6 +164,8 @@ export const EnlargedDashboardVisual = ({ maxDate={maxEndDate} weekDisplayFormat={weekDisplayFormat} onResetDate={onResetDate} + dateOffset={config?.dateOffset} + dateRangeDelimiter={config?.dateRangeDelimiter} /> )} diff --git a/packages/tupaia-web/src/utils/useDateRanges.ts b/packages/tupaia-web/src/utils/useDateRanges.ts index f1f7f1c2e6..baf6c99e55 100644 --- a/packages/tupaia-web/src/utils/useDateRanges.ts +++ b/packages/tupaia-web/src/utils/useDateRanges.ts @@ -94,6 +94,8 @@ export const useDateRanges = ( // this only applies to dashboard items, not map overlays const weekDisplayFormat = 'weekDisplayFormat' in selectedItem ? selectedItem.weekDisplayFormat : undefined; + // this only applies to dashboard items, not map overlays + const dateOffset = 'dateOffset' in selectedItem ? selectedItem.dateOffset : undefined; // this only applies to map overlays const isTimePeriodEditable = @@ -137,10 +139,13 @@ export const useDateRanges = ( const endDate = urlEndDate || itemEndDate || defaultEndDate; const setDates = (_startDate: string, _endDate: string) => { - const period = GRANULARITY_CONFIG[periodGranularity as keyof typeof GRANULARITY_CONFIG] + const selectedGranularity = dateOffset ? dateOffset.unit : periodGranularity; + const period = GRANULARITY_CONFIG[selectedGranularity as keyof typeof GRANULARITY_CONFIG] .momentUnit as moment.unitOfTime.StartOf; + const periodStartDate = moment(_startDate).startOf(period); const periodEndDate = moment(_endDate).endOf(period); + const urlPeriodString = convertDateRangeToUrlPeriodString({ startDate: periodStartDate, endDate: periodEndDate, diff --git a/packages/types/src/schemas/schemas.ts b/packages/types/src/schemas/schemas.ts index edee453110..2e15614c2b 100644 --- a/packages/types/src/schemas/schemas.ts +++ b/packages/types/src/schemas/schemas.ts @@ -340,6 +340,27 @@ export const CssColorSchema = { "type": "string" } +export const DatePickerOffsetSpecSchema = { + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] +} + export const BaseConfigSchema = { "type": "object", "properties": { @@ -367,6 +388,27 @@ export const BaseConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -720,6 +762,10 @@ export const BaseConfigSchema = { "WEEK_ENDING_ABBR" ], "type": "string" + }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" } }, "additionalProperties": false, @@ -803,6 +849,27 @@ export const MatrixConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -1157,6 +1224,10 @@ export const MatrixConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -1504,6 +1575,27 @@ export const MatrixVizBuilderConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -1858,6 +1950,10 @@ export const MatrixVizBuilderConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -2700,6 +2796,27 @@ export const ComponentConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -3054,6 +3171,10 @@ export const ComponentConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -3222,6 +3343,27 @@ export const BaseChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -3576,6 +3718,10 @@ export const BaseChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -4087,6 +4233,27 @@ export const CartesianChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -4441,6 +4608,10 @@ export const CartesianChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -4897,6 +5068,27 @@ export const PieChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -5251,6 +5443,10 @@ export const PieChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -5447,6 +5643,27 @@ export const BarChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -5801,6 +6018,10 @@ export const BarChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -6393,6 +6614,27 @@ export const LineChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -6743,6 +6985,10 @@ export const LineChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -7331,6 +7577,27 @@ export const ComposedChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -7681,6 +7948,10 @@ export const ComposedChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -8085,6 +8356,27 @@ export const GaugeChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -8439,6 +8731,10 @@ export const GaugeChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -8542,6 +8838,27 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -8896,6 +9213,10 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -9032,6 +9353,27 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -9386,6 +9728,10 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -9802,6 +10148,27 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -10152,6 +10519,10 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -10566,6 +10937,27 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -10916,6 +11308,10 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -11319,6 +11715,27 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -11673,6 +12090,10 @@ export const ChartConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -11906,6 +12327,27 @@ export const BaseViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -12260,6 +12702,10 @@ export const BaseViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -12358,6 +12804,27 @@ export const MultiValueViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -12712,6 +13179,10 @@ export const MultiValueViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -12918,6 +13389,27 @@ export const MultiValueRowViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -13272,6 +13764,10 @@ export const MultiValueRowViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -13429,6 +13925,27 @@ export const SingleValueViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -13783,6 +14300,10 @@ export const SingleValueViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -13854,6 +14375,27 @@ export const MultiPhotographViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -14208,6 +14750,10 @@ export const MultiPhotographViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -14275,6 +14821,27 @@ export const MultiSingleValueViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -14629,6 +15196,10 @@ export const MultiSingleValueViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -14696,6 +15267,27 @@ export const SingleDownloadLinkViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -15050,6 +15642,10 @@ export const SingleDownloadLinkViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -15117,6 +15713,27 @@ export const DataDownloadViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -15471,6 +16088,10 @@ export const DataDownloadViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -15538,6 +16159,27 @@ export const DataDownloadViewVizBuilderConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -15892,6 +16534,10 @@ export const DataDownloadViewVizBuilderConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -15975,6 +16621,27 @@ export const SingleDateViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -16329,6 +16996,10 @@ export const SingleDateViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -16396,6 +17067,27 @@ export const DownloadFilesViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -16750,6 +17442,10 @@ export const DownloadFilesViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -16817,6 +17513,27 @@ export const QRCodeViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -17171,6 +17888,10 @@ export const QRCodeViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -17240,6 +17961,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -17594,6 +18336,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -17673,6 +18419,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -18027,6 +18794,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -18183,6 +18954,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -18537,6 +19329,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -18607,6 +19403,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -18961,6 +19778,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -19027,6 +19848,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -19381,6 +20223,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -19447,6 +20293,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -19801,6 +20668,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -19867,6 +20738,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -20221,6 +21113,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -20287,6 +21183,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -20641,6 +21558,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -20707,6 +21628,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -21061,6 +22003,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -21127,6 +22073,27 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -21481,6 +22448,10 @@ export const ViewConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -21662,6 +22633,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -22016,6 +23008,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -22363,6 +23359,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -22717,6 +23734,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -22767,6 +23788,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -23121,6 +24163,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -23257,6 +24303,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -23611,6 +24678,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -24027,6 +25098,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -24377,6 +25469,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -24791,6 +25887,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -25141,6 +26258,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -25544,6 +26665,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -25898,6 +27040,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -25997,6 +27143,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -26351,6 +27518,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -26430,6 +27601,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -26784,6 +27976,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -26940,6 +28136,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -27294,6 +28511,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -27364,6 +28585,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -27718,6 +28960,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -27784,6 +29030,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -28138,6 +29405,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -28204,6 +29475,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -28558,6 +29850,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -28624,6 +29920,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -28978,6 +30295,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -29044,6 +30365,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -29398,6 +30740,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -29464,6 +30810,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -29818,6 +31185,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -29884,6 +31255,27 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -30238,6 +31630,10 @@ export const DashboardItemConfigSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -40903,6 +42299,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -41257,6 +42674,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -41604,6 +43025,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -41958,6 +43400,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -42008,6 +43454,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -42362,6 +43829,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -42498,6 +43969,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -42852,6 +44344,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -43268,6 +44764,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -43618,6 +45135,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -44032,6 +45553,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -44382,6 +45924,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -44785,6 +46331,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -45139,6 +46706,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -45238,6 +46809,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -45592,6 +47184,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -45671,6 +47267,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -46025,6 +47642,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -46181,6 +47802,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -46535,6 +48177,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -46605,6 +48251,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -46959,6 +48626,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -47025,6 +48696,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -47379,6 +49071,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -47445,6 +49141,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -47799,6 +49516,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -47865,6 +49586,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -48219,6 +49961,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -48285,6 +50031,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -48639,6 +50406,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -48705,6 +50476,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -49059,6 +50851,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -49125,6 +50921,27 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -49479,6 +51296,10 @@ export const DashboardItemSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -49582,6 +51403,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -49936,6 +51778,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -50283,6 +52129,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -50637,6 +52504,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -50687,6 +52558,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -51041,6 +52933,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -51177,6 +53073,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -51531,6 +53448,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -51947,6 +53868,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -52297,6 +54239,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -52711,6 +54657,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -53061,6 +55028,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -53464,6 +55435,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -53818,6 +55810,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -53917,6 +55913,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -54271,6 +56288,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -54350,6 +56371,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -54704,6 +56746,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -54860,6 +56906,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -55214,6 +57281,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -55284,6 +57355,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -55638,6 +57730,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -55704,6 +57800,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -56058,6 +58175,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -56124,6 +58245,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -56478,6 +58620,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -56544,6 +58690,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -56898,6 +59065,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -56964,6 +59135,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -57318,6 +59510,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -57384,6 +59580,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -57738,6 +59955,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -57804,6 +60025,27 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -58158,6 +60400,10 @@ export const DashboardItemCreateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -58255,6 +60501,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -58609,6 +60876,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -58956,6 +61227,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -59310,6 +61602,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -59360,6 +61656,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -59714,6 +62031,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -59850,6 +62171,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -60204,6 +62546,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -60620,6 +62966,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -60970,6 +63337,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -61384,6 +63755,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -61734,6 +64126,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -62137,6 +64533,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -62491,6 +64908,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -62590,6 +65011,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -62944,6 +65386,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -63023,6 +65469,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -63377,6 +65844,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -63533,6 +66004,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -63887,6 +66379,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -63957,6 +66453,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -64311,6 +66828,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -64377,6 +66898,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -64731,6 +67273,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -64797,6 +67343,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -65151,6 +67718,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -65217,6 +67788,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -65571,6 +68163,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -65637,6 +68233,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -65991,6 +68608,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -66057,6 +68678,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -66411,6 +69053,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -66477,6 +69123,27 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -66831,6 +69498,10 @@ export const DashboardItemUpdateSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -83811,6 +86482,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -84165,6 +86857,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -84512,6 +87208,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -84866,6 +87583,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -84916,6 +87637,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -85270,6 +88012,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -85406,6 +88152,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -85760,6 +88527,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -86176,6 +88947,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -86526,6 +89318,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -86940,6 +89736,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -87290,6 +90107,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -87693,6 +90514,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -88047,6 +90889,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -88146,6 +90992,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -88500,6 +91367,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -88579,6 +91450,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -88933,6 +91825,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -89089,6 +91985,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -89443,6 +92360,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -89513,6 +92434,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -89867,6 +92809,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -89933,6 +92879,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -90287,6 +93254,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -90353,6 +93324,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -90707,6 +93699,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -90773,6 +93769,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -91127,6 +94144,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -91193,6 +94214,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -91547,6 +94589,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -91613,6 +94659,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -91967,6 +95034,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ @@ -92033,6 +95104,27 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateOffset": { + "description": "The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported.\nCurrently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected.", + "type": "object", + "properties": { + "unit": { + "enum": [ + "month", + "quarter" + ], + "type": "string" + }, + "offset": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "offset", + "unit" + ] + }, "defaultTimePeriod": { "description": "Initial date range for this viz.\nEither a single offset, or an ISO string / offset for start/end date\neg.\n// Single offset\n\"defaultTimePeriod\": {\n \"unit\": \"week\",\n \"offset\": 7\n}\n\n// Explicit start/end dates\n\"defaultTimePeriod\": {\n \"start\": \"2022-10-01\",\n \"end\": \"2023-06-30\"\n}\n\n// Start/end date offsets\n\"defaultTimePeriod\": {\n \"start\": {\n \"unit\": \"week\",\n \"offset\": -52\n },\n \"end\": {\n \"unit\": \"week\",\n \"offset\": 3\n }\n}", "anyOf": [ @@ -92387,6 +95479,10 @@ export const DashboardWithMetadataSchema = { ], "type": "string" }, + "dateRangeDelimiter": { + "description": "If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023'", + "type": "string" + }, "type": { "type": "string", "enum": [ diff --git a/packages/types/src/types/index.ts b/packages/types/src/types/index.ts index 1206c042a3..fa6b9258c1 100644 --- a/packages/types/src/types/index.ts +++ b/packages/types/src/types/index.ts @@ -104,6 +104,8 @@ export { TaskCommentTemplateVariables, RepeatSchedule, EntityType, + DateOffsetSpec, + DatePickerOffsetSpec, } from './models-extra'; export * from './requests'; export * from './css'; diff --git a/packages/types/src/types/models-extra/dashboard-item/common.ts b/packages/types/src/types/models-extra/dashboard-item/common.ts index 7fbb6386ba..e2b2bac75c 100644 --- a/packages/types/src/types/models-extra/dashboard-item/common.ts +++ b/packages/types/src/types/models-extra/dashboard-item/common.ts @@ -5,6 +5,11 @@ import { DateOffsetSpec, DefaultTimePeriod, ReferenceProps, VizPeriodGranularity } from '../common'; +export type DatePickerOffsetSpec = { + unit: 'month' | 'quarter'; + offset: number; +}; + export type BaseConfig = { /** * @description The title of the viz @@ -21,6 +26,12 @@ export type BaseConfig = { */ periodGranularity?: `${VizPeriodGranularity}`; + /** + * @description The number of periods to offset the date range by, for single date period granularities. E.g. if the period granularity is 'one_year_at_a_time' and the date offset is 6 months, the year will run from July-June. Only months and quarter offsets are supported. + * Currently only works for 'one_year_at_a_time' and 'year' granularities - assume that any other granularities used with this will not work as expected. + */ + dateOffset?: DatePickerOffsetSpec; + /** * @description * Initial date range for this viz. @@ -124,6 +135,12 @@ export type BaseConfig = { * @default 'WEEK_COMMENCING_ABBR' */ weekDisplayFormat?: WeekDisplayFormat; + + /** + * @description If specified, this delimiter will be used to separate the start and end dates in the date range picker. Defaults to '-'. This only applies to dates when the type is a single date but has an offset. E.g. offset of 6 months with a date range delimiter of '/' will show 'Jul 2022/June 2023' + */ + + dateRangeDelimiter?: string; }; export type ValueType = diff --git a/packages/types/src/types/models-extra/dashboard-item/index.ts b/packages/types/src/types/models-extra/dashboard-item/index.ts index c2fe73f9b7..db9779653e 100644 --- a/packages/types/src/types/models-extra/dashboard-item/index.ts +++ b/packages/types/src/types/models-extra/dashboard-item/index.ts @@ -59,7 +59,7 @@ export { */ export type DashboardItemConfig = ChartConfig | ComponentConfig | MatrixConfig | ViewConfig; -export { ValueType, ExportPresentationOptions } from './common'; +export { ValueType, ExportPresentationOptions, DatePickerOffsetSpec } from './common'; export type { MatrixConfig, PresentationOptionCondition, diff --git a/packages/types/src/types/models-extra/index.ts b/packages/types/src/types/models-extra/index.ts index bb7484a22f..97270a8f69 100644 --- a/packages/types/src/types/models-extra/index.ts +++ b/packages/types/src/types/models-extra/index.ts @@ -8,6 +8,9 @@ export { PlaintextReferenceProps, LinkReferenceProps, EntityAttributes, + DateOffsetSpec, + VizPeriodGranularity, + DashboardItemType, } from './common'; export type { ReportConfig, @@ -72,6 +75,7 @@ export { ComponentConfig, LineChartChartConfig, ExportPresentationOptions, + DatePickerOffsetSpec, } from './dashboard-item'; export { MapOverlayConfig, @@ -106,7 +110,6 @@ export { SurveyResponseTemplateVariables, MarkdownTemplateVariables, } from './feedItem'; -export { VizPeriodGranularity, DashboardItemType } from './common'; export { isChartReport, isViewReport, isMatrixReport } from './report'; export { UserAccountPreferences } from './user'; export { ProjectConfig } from './project'; diff --git a/packages/ui-components/src/__tests__/components/DateRangePicker/DateRangePicker.test.jsx b/packages/ui-components/src/__tests__/components/DateRangePicker/DateRangePicker.test.jsx index 650dc5fd7e..0ec1e75c9f 100644 --- a/packages/ui-components/src/__tests__/components/DateRangePicker/DateRangePicker.test.jsx +++ b/packages/ui-components/src/__tests__/components/DateRangePicker/DateRangePicker.test.jsx @@ -97,11 +97,56 @@ describe('dateRangePicker', () => { } }); }); -}); + it('can display set start and end dates for year granularity when there is an offset', () => { + const initialEndDate = '2019-06-30'; + const initialStartDate = '2017-07-01'; + render( + , + ); + + const labelText = screen.getByLabelText('active-date'); + + expect(labelText).toHaveTextContent('Q3 2017 – Q2 2019'); + }); -const ControlledDateRangePicker = ({ granularity }) => { - const [startDate, setStartDate] = React.useState(START_DATE); - const [endDate, setEndDate] = React.useState(END_DATE); + it('can display set start and end dates for single year granularity when there is an offset and a date range delimiter', () => { + const initialEndDate = '2018-06-30'; + const initialStartDate = '2017-07-01'; + render( + , + ); + + const labelText = screen.getByLabelText('active-date'); + + expect(labelText).toHaveTextContent('Q3 2017/Q2 2018'); + }); +}); +// make this the same by default because this is always going to be a single date type +const ControlledDateRangePicker = ({ + granularity, + initialEndDate = END_DATE, + initialStartDate = END_DATE, + dateOffset, +}) => { + const [startDate, setStartDate] = React.useState(initialStartDate); + const [endDate, setEndDate] = React.useState(initialEndDate); const handleUpdate = (start, end) => { setStartDate(start); @@ -114,6 +159,7 @@ const ControlledDateRangePicker = ({ granularity }) => { endDate={endDate} granularity={granularity} onSetDates={handleUpdate} + dateOffset={dateOffset} /> ); }; @@ -130,10 +176,12 @@ describe('controlled dateRangePicker', () => { userEvent.click(prev); - const prevEndDate = moment(END_DATE) - .add(-1, value.momentShorthand) - .startOf(value.momentUnit) - .format(value.rangeFormat); + const prevEndDate = momentToDateDisplayString( + moment(END_DATE).add(-1, value.momentShorthand).endOf(value.momentUnit), + key, + value.rangeFormat, + value.modifier, + ); expect(labelText).toHaveTextContent(prevEndDate); @@ -149,4 +197,32 @@ describe('controlled dateRangePicker', () => { }); } }); + it('can click to increase and decrease dates for single year granularity when an offset is applied', () => { + const initialEndDate = '2018-06-30'; + const initialStartDate = '2017-07-01'; + render( + , + ); + + const labelText = screen.getByLabelText('active-date'); + const prev = screen.getByRole('button', { name: 'prev' }); + const next = screen.getByRole('button', { name: 'next' }); + + userEvent.click(prev); + + expect(labelText).toHaveTextContent('Jul 2016 – Jun 2017'); + + userEvent.click(next); + userEvent.click(next); + + expect(labelText).toHaveTextContent('Jul 2018 – Jun 2019'); + }); }); diff --git a/packages/ui-components/src/components/DateRangePicker/DatePicker.tsx b/packages/ui-components/src/components/DateRangePicker/DatePicker.tsx index b0ab831334..57e94cb2a4 100644 --- a/packages/ui-components/src/components/DateRangePicker/DatePicker.tsx +++ b/packages/ui-components/src/components/DateRangePicker/DatePicker.tsx @@ -13,7 +13,7 @@ export const DatePicker = ({ menuItems, }: { label: string; - selectedValue: number; + selectedValue: number | undefined; onChange: (event: ChangeEvent<{ value: any }>) => void; menuItems: ReactNode[]; }) => ( diff --git a/packages/ui-components/src/components/DateRangePicker/DatePickerDialog.tsx b/packages/ui-components/src/components/DateRangePicker/DatePickerDialog.tsx index 6ee3f4f1c1..8a5ba26db4 100644 --- a/packages/ui-components/src/components/DateRangePicker/DatePickerDialog.tsx +++ b/packages/ui-components/src/components/DateRangePicker/DatePickerDialog.tsx @@ -5,15 +5,17 @@ */ import React, { useEffect, useState } from 'react'; -import moment from 'moment'; +import moment, { Moment } from 'moment'; import styled from 'styled-components'; import { DialogProps, Typography } from '@material-ui/core'; +import { DatePickerOffsetSpec } from '@tupaia/types'; import { DEFAULT_MIN_DATE, GRANULARITIES, GRANULARITIES_WITH_ONE_DATE, + GRANULARITY_CONFIG, GRANULARITY_SHAPE, - roundStartEndDates, + roundStartDate, } from '@tupaia/utils'; import { Dialog, DialogHeader, DialogContent, DialogFooter } from '../Dialog'; import { DayPicker } from './DayPicker'; @@ -24,17 +26,8 @@ import { QuarterPicker } from './QuarterPicker'; import { Button, OutlinedButton } from '../Button'; import { BaseDatePickerProps, WeekPickerProps, YearPickerProps } from '../../types'; -const { - DAY, - WEEK, - SINGLE_WEEK, - MONTH, - SINGLE_MONTH, - QUARTER, - SINGLE_QUARTER, - YEAR, - SINGLE_YEAR, -} = GRANULARITIES; +const { DAY, WEEK, SINGLE_WEEK, MONTH, SINGLE_MONTH, QUARTER, SINGLE_QUARTER, YEAR, SINGLE_YEAR } = + GRANULARITIES; const Container = styled.fieldset` display: flex; @@ -89,7 +82,8 @@ type DateRowProps = (BaseDatePickerProps | YearPickerProps | WeekPickerProps) & title?: string; }; -const DateRow = ({ title, granularity, ...props }: DateRowProps) => { +const DateRow = ({ title, ...props }: DateRowProps) => { + const { granularity } = props; const getDatePickerComponent = () => { switch (granularity) { default: @@ -98,7 +92,7 @@ const DateRow = ({ title, granularity, ...props }: DateRowProps) => { <> - + ); case SINGLE_WEEK: @@ -106,7 +100,7 @@ const DateRow = ({ title, granularity, ...props }: DateRowProps) => { return ( <> - + ); case MONTH: @@ -114,7 +108,7 @@ const DateRow = ({ title, granularity, ...props }: DateRowProps) => { return ( <> - + ); case QUARTER: @@ -122,12 +116,12 @@ const DateRow = ({ title, granularity, ...props }: DateRowProps) => { return ( <> - + ); case YEAR: case SINGLE_YEAR: - return ; + return ; } }; return ( @@ -174,9 +168,11 @@ type DatePickerDialogProps = { endDate: string; minDate?: string; maxDate?: string; - onSetNewDates: (startDate: string, endDate: string) => void; + onSetNewDates: (startDate: Moment, endDate: Moment) => void; weekDisplayFormat?: string; muiDialogProps?: Omit; + dateRangeDelimiter?: string; + dateOffset?: DatePickerOffsetSpec; }; export const DatePickerDialog = ({ @@ -190,6 +186,8 @@ export const DatePickerDialog = ({ onSetNewDates, weekDisplayFormat, muiDialogProps = {}, + dateRangeDelimiter, + dateOffset, }: DatePickerDialogProps) => { const momentStartDate = moment(startDate); const momentEndDate = moment(endDate); @@ -214,19 +212,29 @@ export const DatePickerDialog = ({ return setErrorMessage('Start date must be before end date'); } - const { startDate: roundedStartDate, endDate: roundedEndDate } = roundStartEndDates( - granularity, - isSingleDate ? selectedEndDate.clone() : selectedStartDate, - selectedEndDate, - ); + const { momentUnit } = GRANULARITY_CONFIG[granularity as keyof typeof GRANULARITY_CONFIG]; + + const getStartDate = () => { + if (dateOffset && isSingleDate) { + return selectedEndDate.clone().subtract(1, momentUnit as moment.DurationInputArg2); + } + if (isSingleDate) { + return selectedEndDate.clone(); + } + return selectedStartDate; + }; + + // calculate the rounded start date + const startDate = getStartDate(); + const roundedStartDate = roundStartDate(granularity, startDate, dateOffset); // Only update if the dates have actually changed by at least one day if ( !momentStartDate.isSame(roundedStartDate, 'day') || - !momentEndDate.isSame(roundedEndDate, 'day') + !momentEndDate.isSame(selectedEndDate, 'day') ) { // Update the external control values! - onSetNewDates(roundedStartDate, roundedEndDate); + onSetNewDates(roundedStartDate, selectedEndDate); } onClose(); return setErrorMessage(''); @@ -242,6 +250,14 @@ export const DatePickerDialog = ({ } }, [momentStartDate?.format('DD/MM/YYYY'), momentEndDate?.format('DD/MM/YYYY')]); + useEffect(() => { + if (!isSingleDate) return; + + const { momentUnit } = granularity; + const newStartDate = selectedEndDate.clone().subtract(1, momentUnit); + setSelectedStartDate(newStartDate); + }, [selectedEndDate?.format('DD/MM/YYYY')]); + return ( )} {errorMessage ? {errorMessage} : null} diff --git a/packages/ui-components/src/components/DateRangePicker/DateRangePicker.tsx b/packages/ui-components/src/components/DateRangePicker/DateRangePicker.tsx index 0c5b164a73..c787d31692 100644 --- a/packages/ui-components/src/components/DateRangePicker/DateRangePicker.tsx +++ b/packages/ui-components/src/components/DateRangePicker/DateRangePicker.tsx @@ -16,6 +16,7 @@ import { IconButton as MuiIconButton, } from '@material-ui/core'; import { DateRange, KeyboardArrowLeft, KeyboardArrowRight } from '@material-ui/icons'; +import { DatePickerOffsetSpec } from '@tupaia/types'; import { GRANULARITIES, GRANULARITY_SHAPE } from '@tupaia/utils'; import { FlexStart } from '../Layout'; import { WeekDisplayFormatType } from '../../types'; @@ -83,6 +84,8 @@ interface DateRangePickerProps { isLoading?: boolean; weekDisplayFormat?: WeekDisplayFormatType; dialogProps?: Omit; + dateOffset?: DatePickerOffsetSpec; + dateRangeDelimiter?: string; } export const DateRangePicker = ({ @@ -95,6 +98,8 @@ export const DateRangePicker = ({ isLoading = false, weekDisplayFormat, dialogProps, + dateOffset, + dateRangeDelimiter, }: DateRangePickerProps) => { const [isOpen, setIsOpen] = useState(false); const { @@ -114,6 +119,8 @@ export const DateRangePicker = ({ granularity, onSetDates, weekDisplayFormat, + dateOffset, + dateRangeDelimiter, }); const handleOpen = () => { @@ -164,6 +171,8 @@ export const DateRangePicker = ({ onSetNewDates={handleDateChange} weekDisplayFormat={weekDisplayFormat} muiDialogProps={dialogProps} + dateOffset={dateOffset} + dateRangeDelimiter={dateRangeDelimiter} /> ); diff --git a/packages/ui-components/src/components/DateRangePicker/YearPicker.tsx b/packages/ui-components/src/components/DateRangePicker/YearPicker.tsx index 48774dd9ea..5c1ada07ee 100644 --- a/packages/ui-components/src/components/DateRangePicker/YearPicker.tsx +++ b/packages/ui-components/src/components/DateRangePicker/YearPicker.tsx @@ -4,10 +4,62 @@ * */ import React from 'react'; -import { Moment } from 'moment'; +import moment, { Moment } from 'moment'; import { MenuItem } from '../Inputs'; import { DatePicker } from './DatePicker'; import { YearPickerProps } from '../../types'; +import { + GRANULARITIES_WITH_ONE_DATE, + GRANULARITY_CONFIG, + roundEndDate, + roundStartDate, +} from '@tupaia/utils'; +import { getDatesAsString } from './useDateRangePicker'; + +const getOffsetStartDateForYear = ( + year: number, + granularity: YearPickerProps['granularity'], + dateOffset: YearPickerProps['dateOffset'], +) => { + const startDate = moment().set({ + year, + month: 0, + date: 1, + hour: 0, + minute: 0, + second: 0, + }); + + return roundStartDate(granularity, startDate, dateOffset); +}; + +const getOffsetEndDateForYear = ( + year: number, + offsetStartDate: Moment, + granularity: YearPickerProps['granularity'], + dateOffset: YearPickerProps['dateOffset'], +) => { + const isSetRangeGranularity = GRANULARITIES_WITH_ONE_DATE.includes(granularity); + + const endDate = moment().set({ + year, + month: 11, + date: 31, + hour: 23, + minute: 59, + second: 59, + }); + + if (isSetRangeGranularity) { + const { momentUnit } = GRANULARITY_CONFIG[granularity as keyof typeof GRANULARITY_CONFIG]; + return offsetStartDate + .clone() + .add(1, momentUnit as any) + .subtract(1, 'minute'); // set to the end of the day at the end of the range + } + + return roundEndDate(granularity, endDate, dateOffset); +}; export const YearPicker = ({ momentDateValue, @@ -15,28 +67,120 @@ export const YearPicker = ({ maxMomentDate, isIsoYear = false, onChange, + dateOffset, + granularity, + dateRangeDelimiter, + valueKey, }: YearPickerProps) => { + const isSetRangeGranularity = GRANULARITIES_WITH_ONE_DATE.includes(granularity); const momentToYear = (momentInstance: Moment, ...args: any[]) => isIsoYear ? momentInstance.isoWeekYear(...(args as [])) : momentInstance.year(...(args as [])); const minYear = momentToYear(minMomentDate); const maxYear = momentToYear(maxMomentDate); - const yearOptions = []; + const yearOptions: { + value: number; + displayLabel: string; + startDate: Moment; + endDate: Moment; + }[] = []; - for (let y = minYear; y <= maxYear; y++) { - yearOptions.push( - - {y} - , + const getDisplayLabel = (year: number) => { + // if there is no dateOffset, return the year as it is + if (!dateOffset) return year; + + const offsetStartDate = getOffsetStartDateForYear(year, granularity, dateOffset); + + const offsetEndDate = getOffsetEndDateForYear(year, offsetStartDate, granularity, dateOffset); + + if (isSetRangeGranularity) { + return getDatesAsString( + true, + dateOffset.unit, + offsetStartDate, + offsetEndDate, + undefined, + dateOffset, + dateRangeDelimiter, + ); + } + + if (valueKey === 'startDate') { + return getDatesAsString( + true, + dateOffset.unit, + offsetStartDate, + offsetStartDate, + undefined, + dateOffset, + dateRangeDelimiter, + ); + } + + return getDatesAsString( + true, + dateOffset.unit, + offsetEndDate, + offsetEndDate, + undefined, + dateOffset, + dateRangeDelimiter, ); + }; + + for (let y = minYear; y <= maxYear; y++) { + const displayLabel = getDisplayLabel(y); + const startDate = getOffsetStartDateForYear(y, granularity, dateOffset); + const endDate = getOffsetEndDateForYear(y, startDate, granularity, dateOffset); + // use the correct year based on the valueKey + const yearToUse = valueKey === 'startDate' ? startDate : endDate; + + if (startDate.isAfter(maxMomentDate)) { + continue; + } + yearOptions.push({ + value: yearToUse.year(), + displayLabel, + startDate, + endDate, + }); } + const menuItems = yearOptions.map(option => ( + + {option.displayLabel} + + )); + + const onChangeValue = (value: number) => { + return onChange(momentToYear(momentDateValue.clone(), value)); + }; + + const getSelectedOption = () => { + if (!dateOffset) { + return momentToYear(momentDateValue); + } + + const applicableOption = yearOptions.find(option => { + const { startDate, endDate } = option; + if (valueKey === 'startDate') { + return startDate.isSame(momentDateValue, 'year'); + } + + return momentDateValue.isBetween(startDate, endDate, 'year', '[]'); + }); + if (!applicableOption) return undefined; + + return applicableOption[valueKey].year(); + }; + const selectedOption = getSelectedOption(); + return ( onChange(momentToYear(momentDateValue.clone(), e.target.value))} - menuItems={yearOptions} + selectedValue={selectedOption} + onChange={e => onChangeValue(e.target.value)} + menuItems={menuItems} /> ); }; diff --git a/packages/ui-components/src/components/DateRangePicker/useDateRangePicker.tsx b/packages/ui-components/src/components/DateRangePicker/useDateRangePicker.tsx index 6b3951b272..08aefa6002 100644 --- a/packages/ui-components/src/components/DateRangePicker/useDateRangePicker.tsx +++ b/packages/ui-components/src/components/DateRangePicker/useDateRangePicker.tsx @@ -5,6 +5,7 @@ import { useEffect } from 'react'; import moment, { Moment } from 'moment'; +import { DatePickerOffsetSpec } from '@tupaia/types'; import { DEFAULT_MIN_DATE, getDefaultDates, @@ -22,53 +23,72 @@ import { GranularityType, ModifierType } from '../../types'; const DEFAULT_GRANULARITY = GRANULARITIES.DAY; -const getDatesAsString = ( +export const getDatesAsString = ( isSingleDate: boolean, granularity: GranularityType = DEFAULT_GRANULARITY, startDate: Moment, endDate: Moment, weekDisplayFormat?: string | number, + dateOffset?: DatePickerOffsetSpec, + dateRangeDelimiter = ' – ', ) => { const isWeek = granularity === GRANULARITIES.WEEK || granularity === GRANULARITIES.SINGLE_WEEK; - const { rangeFormat, modifier } = ( + + // when it's a single date, we use the preferred range delimiter, otherwise use the default delimiter because this indicates multiple offset dates selected + const delimiterToUse = isSingleDate && !!dateOffset ? dateRangeDelimiter : ' – '; + + const displayGranularity = dateOffset?.unit ?? granularity; + + const { rangeFormat, modifier, momentUnit } = ( isWeek && weekDisplayFormat ? WEEK_DISPLAY_CONFIG[weekDisplayFormat] - : GRANULARITY_CONFIG[granularity as keyof typeof GRANULARITY_CONFIG] + : GRANULARITY_CONFIG[displayGranularity as keyof typeof GRANULARITY_CONFIG] ) as { + // casting here because TS is inferring the types as different to the Moment types. This will probably be fixed once we use TS in the utils package rangeFormat: string; modifier?: ModifierType; + momentUnit: moment.unitOfTime.StartOf; }; + // if the start and end dates are the same day, we only need to display one date + const displayAsRange = !startDate.clone().isSame(endDate.clone(), momentUnit); + + const formattedEndDate = momentToDateDisplayString( + endDate, + displayGranularity, + rangeFormat, + modifier, + ); + + if (!displayAsRange) { + return formattedEndDate; + } + const formattedStartDate = momentToDateDisplayString( startDate, - granularity, + displayGranularity, rangeFormat, - modifier!, + modifier, ); - const formattedEndDate = momentToDateDisplayString(endDate, granularity, rangeFormat, modifier!); - return isSingleDate ? formattedEndDate : `${formattedStartDate} – ${formattedEndDate}`; // En dash + return `${formattedStartDate}${delimiterToUse}${formattedEndDate}`; }; -/** - * - * @param granularity - * @param startDate - * @param endDate - * @param defaultStartDate - * @param defaultEndDate - * @returns {{currentStartDate: (moment.Moment|*), currentEndDate: (moment.Moment|*)}} - */ const getCurrentDates = ( - granularity: GranularityType, - startDate: Moment | string, - endDate: Moment | string, + granularity: GranularityType | undefined, + startDate: Moment | string | undefined, + endDate: Moment | string | undefined, defaultStartDate: Moment, defaultEndDate: Moment, -) => ({ - currentStartDate: startDate ? roundStartDate(granularity, startDate) : defaultStartDate, - currentEndDate: endDate ? roundEndDate(granularity, endDate) : defaultEndDate, -}); +): { + currentStartDate: Moment; + currentEndDate: Moment; +} => { + return { + currentStartDate: startDate ? roundStartDate(granularity, startDate) : defaultStartDate, + currentEndDate: endDate ? roundEndDate(granularity, endDate) : defaultEndDate, + }; +}; /** * @@ -90,6 +110,8 @@ interface UseDateRangePickerProps { granularity?: GranularityType; onSetDates: (startDate: string, endDate: string) => void; weekDisplayFormat?: string | number; + dateOffset?: DatePickerOffsetSpec; + dateRangeDelimiter?: string; } export const useDateRangePicker = ({ startDate, @@ -99,6 +121,8 @@ export const useDateRangePicker = ({ granularity, onSetDates, weekDisplayFormat, + dateOffset, + dateRangeDelimiter, }: UseDateRangePickerProps) => { /** * Call the on change handler prop using iso formatted date @@ -108,24 +132,53 @@ export const useDateRangePicker = ({ }; const isSingleDate = GRANULARITIES_WITH_ONE_DATE.includes(granularity ?? ''); - const { - momentShorthand, - }: { - momentShorthand: string; - } = GRANULARITY_CONFIG[granularity as keyof typeof GRANULARITY_CONFIG]; + const { momentShorthand } = GRANULARITY_CONFIG[granularity as keyof typeof GRANULARITY_CONFIG]; - const minMomentDate = minDate ? moment(minDate) : moment(DEFAULT_MIN_DATE); - const maxMomentDate = maxDate ? moment(maxDate) : moment(); + const initialMinDate = minDate ? moment(minDate) : moment(DEFAULT_MIN_DATE); + + // round the start date, including the date offset if it is set + const minMomentDate = roundStartDate(granularity, initialMinDate, dateOffset); + + const getMaxDate = () => { + // Get the moment object for the max date, or if it's not set, use the current date + const initialMaxDate = maxDate ? moment(maxDate) : moment(); + + // if there is no offset, just round the end date and return it + if (!dateOffset) return roundEndDate(granularity, initialMaxDate); + + // calculate the difference between the min and max dates, and round up to the nearest whole number + const differenceBetweenDates = Math.ceil( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - diff types are not compatible with our period momentShorthand type (which is inferred as a string) + initialMaxDate.diff(minMomentDate, momentShorthand, true), + ); + + // add the difference between the min and max dates to the min date to get the new max date + const newMaxDate = minMomentDate + .clone() + .add(differenceBetweenDates, momentShorthand) + .subtract(1, 'days'); // subtract one day to make sure the max date is inclusive + + // round the end date, using the date offset if it is set + const roundedEndDate = roundEndDate(dateOffset?.unit ?? granularity, newMaxDate); + + return roundedEndDate; + }; + + const maxMomentDate = getMaxDate(); const { startDate: defaultStartDate, endDate: defaultEndDate } = getDefaultDates({ periodGranularity: granularity, + dateOffset, }) as { startDate: Moment; endDate: Moment; }; + const displayGranularity = dateOffset ? dateOffset.unit : granularity; + const { currentStartDate, currentEndDate } = getCurrentDates( - granularity!, + displayGranularity!, startDate!, endDate!, defaultStartDate, @@ -134,12 +187,15 @@ export const useDateRangePicker = ({ const nextDisabled = currentEndDate.isSameOrAfter(maxMomentDate); const prevDisabled = currentStartDate.isSameOrBefore(minMomentDate); + const labelText = getDatesAsString( isSingleDate, - granularity, + displayGranularity, currentStartDate, currentEndDate, weekDisplayFormat, + dateOffset, + dateRangeDelimiter, ); /** @@ -150,13 +206,19 @@ export const useDateRangePicker = ({ if (!isSingleDate) { console.warn('Can only change period for single unit date pickers (e.g. one month)'); } - const newStartDate = currentStartDate.clone().add(numberOfPeriodsToMove, momentShorthand); - const newEndDate = currentEndDate.clone().add(numberOfPeriodsToMove, momentShorthand); + + // If the dateOffset is set, we need to round the start and end dates to the nearest period, so that when we add the number of periods to move, we get the correct period, and can then round the start and end dates again. We shouldn't use the dates directly on the off cancel that a current date has been entered directly into the url, for example, and it doesn't match the range we want to work with. + const startDateWithoutOffset = roundStartDate(granularity, startDate); + const newStartDate = startDateWithoutOffset.clone().add(numberOfPeriodsToMove, momentShorthand); + const newEndDate = newStartDate.clone(); + const { startDate: roundedStartDate, endDate: roundedEndDate } = roundStartEndDates( granularity, newStartDate, newEndDate, + dateOffset, ); + handleDateChange(roundedStartDate, roundedEndDate); }; @@ -176,7 +238,7 @@ export const useDateRangePicker = ({ }, []); return { - isSingleDate, + isSingleDate: isSingleDate, currentStartDate: toStandardDateString(currentStartDate), currentEndDate: toStandardDateString(currentEndDate), handleReset, diff --git a/packages/ui-components/src/types/date-picker-types.ts b/packages/ui-components/src/types/date-picker-types.ts index 142e706f91..c498c1fda8 100644 --- a/packages/ui-components/src/types/date-picker-types.ts +++ b/packages/ui-components/src/types/date-picker-types.ts @@ -1,4 +1,5 @@ import { Moment } from 'moment'; +import { DatePickerOffsetSpec } from '@tupaia/types'; import { GRANULARITIES, WEEK_DISPLAY_FORMATS } from '@tupaia/utils'; import { ValueOf } from './helpers'; @@ -15,6 +16,10 @@ export type YearPickerProps = Pick< > & { isIsoYear?: boolean; onChange: (date: Moment | number) => void; + dateOffset?: DatePickerOffsetSpec; + granularity: GranularityType; + dateRangeDelimiter?: string; + valueKey: 'startDate' | 'endDate'; }; export type WeekPickerProps = BaseDatePickerProps & { @@ -23,6 +28,6 @@ export type WeekPickerProps = BaseDatePickerProps & { export type GranularityType = ValueOf; -export type ModifierType = 'startOfWeek' | 'endOfWeek' | undefined; +export type ModifierType = 'startOfWeek' | 'endOfWeek'; export type WeekDisplayFormatType = ValueOf; diff --git a/packages/utils/src/__tests__/period/periodGranularities.test.js b/packages/utils/src/__tests__/period/periodGranularities.test.js index 48f3355264..720fcc2738 100644 --- a/packages/utils/src/__tests__/period/periodGranularities.test.js +++ b/packages/utils/src/__tests__/period/periodGranularities.test.js @@ -174,6 +174,91 @@ describe('chartGranularities', () => { expect(startDate.format()).toEqual('2019-02-04T00:00:00+11:00'); expect(endDate.format()).toEqual('2019-02-04T23:59:59+11:00'); }); + + it('calculates current period if positive offset is provided and the closest period would start in the future', () => { + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_year_at_a_time', + dateOffset: { + unit: 'month', + offset: 6, + }, + }); + expect(startDate.format()).toEqual('2018-07-01T00:00:00+10:00'); + expect(endDate.format()).toEqual('2019-06-30T23:59:59+10:00'); + }); + + it('calculates the correct period if a positive offset is provided and closest period has already started', () => { + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_year_at_a_time', + dateOffset: { + unit: 'month', + offset: 1, // feb - jan + }, + }); + expect(startDate.format()).toEqual('2019-02-01T00:00:00+11:00'); + expect(endDate.format()).toEqual('2020-01-31T23:59:59+11:00'); + }); + + it('calculates current period if negative offset is provided ', () => { + // e.g. if we are in feb 2019, and we want to see march-feb + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_year_at_a_time', + dateOffset: { + unit: 'month', + offset: -10, // feb - jan the previous year + }, + }); + expect(startDate.format()).toEqual('2018-03-01T00:00:00+11:00'); + expect(endDate.format()).toEqual('2019-02-28T23:59:59+11:00'); + }); + + it('calculates offset default dates with months and weeks', () => { + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_month_at_a_time', + dateOffset: { + unit: 'week', + offset: 2, // start mid month + }, + }); + expect(startDate.format()).toEqual('2019-01-15T00:00:00+11:00'); + expect(endDate.format()).toEqual('2019-02-14T23:59:59+11:00'); + }); + + it('calculates offset default dates with months and days', () => { + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_month_at_a_time', + dateOffset: { + unit: 'day', + offset: 5, // start 5 days into the month + }, + }); + expect(startDate.format()).toEqual('2019-01-06T00:00:00+11:00'); + expect(endDate.format()).toEqual('2019-02-05T23:59:59+11:00'); + }); + + it('calculates offset default dates with weeks and days', () => { + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_week_at_a_time', + dateOffset: { + unit: 'day', + offset: 4, // start 4 days into the week + }, + }); + expect(startDate.format()).toEqual('2019-02-01T00:00:00+11:00'); + expect(endDate.format()).toEqual('2019-02-07T23:59:59+11:00'); + }); + + it('calculates offset default dates with years and quarters', () => { + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_year_at_a_time', + dateOffset: { + unit: 'quarter', + offset: 3, // q4-q1 + }, + }); + expect(startDate.format()).toEqual('2018-10-01T00:00:00+10:00'); + expect(endDate.format()).toEqual('2019-09-30T23:59:59+10:00'); + }); }); describe('defaultTimePeriod with a date range', () => { @@ -197,6 +282,22 @@ describe('chartGranularities', () => { expect(startDate.format()).toEqual('2019-02-04T00:00:00+11:00'); expect(endDate.format()).toEqual('2019-02-08T23:59:59+11:00'); }); + + it('works with offset dates', () => { + const { startDate, endDate } = getDefaultDates({ + periodGranularity: 'one_year_at_a_time', + defaultTimePeriod: { + start: { unit: 'year', offset: 2 }, + end: { unit: 'year', offset: 2 }, + }, + dateOffset: { + unit: 'quarter', + offset: 3, // q4-q1 + }, + }); + expect(startDate.format()).toEqual('2020-10-01T00:00:00+10:00'); + expect(endDate.format()).toEqual('2021-09-30T23:59:59+10:00'); + }); }); }); diff --git a/packages/utils/src/period/periodGranularities.js b/packages/utils/src/period/periodGranularities.js index a30bfc0648..818b63aeae 100644 --- a/packages/utils/src/period/periodGranularities.js +++ b/packages/utils/src/period/periodGranularities.js @@ -126,21 +126,29 @@ const validateDateString = date => { } }; -export const roundStartDate = (granularity, startDate) => { +export const roundStartDate = (granularity, startDate, dateOffset = null) => { const { momentUnit } = GRANULARITY_CONFIG[granularity]; const momentStartDate = moment.isMoment(startDate) ? startDate : moment(startDate); - return momentStartDate.clone().startOf(momentUnit); + const startOf = momentStartDate.clone().startOf(momentUnit); + if (dateOffset) { + return addMomentOffset(startOf, dateOffset); + } + return startOf; }; -export const roundEndDate = (granularity, endDate) => { +export const roundEndDate = (granularity, endDate, dateOffset = null) => { const { momentUnit } = GRANULARITY_CONFIG[granularity]; const momentEndDate = moment.isMoment(endDate) ? endDate : moment(endDate); - return momentEndDate.clone().endOf(momentUnit); + const endOf = momentEndDate.clone().endOf(momentUnit); + if (dateOffset) { + return addMomentOffset(endOf, dateOffset); + } + return endOf; }; -export const roundStartEndDates = (granularity, startDate, endDate) => ({ - startDate: roundStartDate(granularity, startDate), - endDate: roundEndDate(granularity, endDate), +export const roundStartEndDates = (granularity, startDate, endDate, dateOffset = null) => ({ + startDate: roundStartDate(granularity, startDate, dateOffset), + endDate: roundEndDate(granularity, endDate, dateOffset), }); /** @@ -153,6 +161,7 @@ export const roundStartEndDates = (granularity, startDate, endDate) => ({ export const momentToDateDisplayString = (date, granularity, format, modifier) => { // Use the explicit modifier passed in, otherwise fall back to the default modifier of the granularity const mod = modifier ?? GRANULARITY_CONFIG[granularity].modifier ?? null; + switch (mod) { case 'startOfWeek': return date.clone().startOf('W').format(format); @@ -163,6 +172,15 @@ export const momentToDateDisplayString = (date, granularity, format, modifier) = } }; +const validateSingleDateOffset = (offset, periodGranularity) => { + const validDateOffsetUnit = GRANULARITIES_WITH_ONE_DATE_VALID_OFFSET_UNIT[periodGranularity]; + if (offset.unit !== validDateOffsetUnit) { + throw new Error( + `defaultTimePeriod unit must match periodGranularity (periodGranularity: ${periodGranularity}, valid unit: ${validDateOffsetUnit}, given: ${offset.unit})`, + ); + } +}; + /** * Get default dates for start and end period of single date period granularities, * meaning both start and end date will have the same date. @@ -183,7 +201,11 @@ export const momentToDateDisplayString = (date, granularity, format, modifier) = * @param {*} periodGranularity * @param {*} defaultTimePeriod */ -const getDefaultDatesForSingleDateGranularities = (periodGranularity, defaultTimePeriod) => { +const getDefaultDatesForSingleDateGranularities = ( + periodGranularity, + defaultTimePeriod, + dateOffset, +) => { let startDate = moment(); let endDate = startDate; @@ -202,12 +224,7 @@ const getDefaultDatesForSingleDateGranularities = (periodGranularity, defaultTim // else, assume defaultTimePeriod is the period config. Eg: {defaultTimePeriod: {unit: 'month', offset: -1}} singleDateConfig = defaultTimePeriod; } - const validDateOffsetUnit = GRANULARITIES_WITH_ONE_DATE_VALID_OFFSET_UNIT[periodGranularity]; - if (singleDateConfig.unit !== validDateOffsetUnit) { - throw new Error( - `defaultTimePeriod unit must match periodGranularity (periodGranularity: ${periodGranularity}, valid unit: ${validDateOffsetUnit}, given: ${singleDateConfig.unit})`, - ); - } + validateSingleDateOffset(singleDateConfig, periodGranularity); // Grab all the details and get a single default date used for both start/end period. startDate = @@ -217,7 +234,35 @@ const getDefaultDatesForSingleDateGranularities = (periodGranularity, defaultTim endDate = startDate; } - return roundStartEndDates(periodGranularity, startDate, endDate); + const { startDate: defaultStartDate, endDate: defaultEndDate } = roundStartEndDates( + periodGranularity, + startDate, + endDate, + dateOffset, + ); + let defaultStartDateMoment = defaultStartDate; + let defaultEndDateMoment = defaultEndDate; + + if (dateOffset) { + // get the period we are currently in, for example if offset is 6 months, and we are currently in May, the period would be June - July previous year + // if the offset start date is after the initial end date, this means we have to make the start date 1 period before today + if (defaultStartDateMoment.isAfter(endDate)) { + const { momentUnit } = GRANULARITY_CONFIG[periodGranularity]; + const newStartingDate = moment().subtract(1, momentUnit); + defaultStartDateMoment = roundStartDate(periodGranularity, newStartingDate, dateOffset); + defaultEndDateMoment = roundEndDate(periodGranularity, newStartingDate, dateOffset); + } + + // if the offset end date is before the initial start date, this means we have to make the end date 1 period after today + if (defaultEndDateMoment.isBefore(startDate)) { + const { momentUnit } = GRANULARITY_CONFIG[periodGranularity]; + const newEndingDate = moment().add(1, momentUnit); + defaultStartDateMoment = roundStartDate(periodGranularity, newEndingDate, dateOffset); + defaultEndDateMoment = roundEndDate(periodGranularity, newEndingDate, dateOffset); + } + } + + return { startDate: defaultStartDateMoment, endDate: defaultEndDateMoment }; }; /** @@ -232,8 +277,9 @@ const getDefaultDatesForSingleDateGranularities = (periodGranularity, defaultTim * } * @param {*} periodGranularity * @param {*} defaultTimePeriod + * @param {*} dateOffset */ -const getDefaultDatesForRangeGranularities = (periodGranularity, defaultTimePeriod) => { +const getDefaultDatesForRangeGranularities = (periodGranularity, defaultTimePeriod, dateOffset) => { if (defaultTimePeriod) { let startDate = moment(); let endDate = startDate; @@ -257,14 +303,23 @@ const getDefaultDatesForRangeGranularities = (periodGranularity, defaultTimePeri throw new Error(`Start date must be earlier than the end date`); } - return roundStartEndDates(periodGranularity, startDate, endDate); + return roundStartEndDates(periodGranularity, startDate, endDate, dateOffset); + } + + let defaultStartDate = moment(DEFAULT_MIN_DATE); + let defaultEndDate = moment(); + + if (dateOffset) { + defaultStartDate = addMomentOffset(defaultStartDate, dateOffset); + // Round the new end date to the end of the period + defaultEndDate = roundEndDate(periodGranularity, defaultEndDate, dateOffset); } - return { startDate: moment(DEFAULT_MIN_DATE), endDate: moment() }; + return { startDate: defaultStartDate, endDate: defaultEndDate }; }; export function getDefaultDates(viewConfig) { - const { periodGranularity, defaultTimePeriod } = viewConfig; + const { periodGranularity, defaultTimePeriod, dateOffset } = viewConfig; // we need a valid granularity to proceed if (!periodGranularity) { @@ -273,9 +328,13 @@ export function getDefaultDates(viewConfig) { const isSingleDate = GRANULARITIES_WITH_ONE_DATE.includes(periodGranularity); if (isSingleDate) { - return getDefaultDatesForSingleDateGranularities(periodGranularity, defaultTimePeriod); + return getDefaultDatesForSingleDateGranularities( + periodGranularity, + defaultTimePeriod, + dateOffset, + ); } - return getDefaultDatesForRangeGranularities(periodGranularity, defaultTimePeriod); + return getDefaultDatesForRangeGranularities(periodGranularity, defaultTimePeriod, dateOffset); } export const getDefaultDrillDownDates = (drillDownViewConfig, previousStartDate) => { From 5293c2a19151b0f7c155853a0765a75637a4c715 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:28:48 +1200 Subject: [PATCH 15/27] feat(adminPanel): RN-1433: Allow archiving of survey responses (#5903) * Add archive button to admin panel * Working archive * Update filter * Add tooltip to button * Allow bes admins to delete * FIx sortable action column * PR fixes * Handle outdated responses with dhis * Check for outdated status with tasks * Fix tests * Update SurveyResponseOutdater.test.js --------- Co-authored-by: Andrew --- .../api/mutations/useEditSurveyResponse.js | 7 +- .../admin-panel/src/icons/ArchiveIcon.jsx | 29 +++ packages/admin-panel/src/icons/index.js | 1 + .../src/pages/resources/ResourcePage.jsx | 2 + packages/admin-panel/src/rootReducer.js | 4 +- .../src/routes/surveys/surveyResponses.jsx | 10 +- .../ArchiveSurveyResponseModal.jsx | 109 +++++++++++ .../src/surveyResponse/FileQuestionField.jsx | 181 ------------------ .../ResubmitSurveyResponseModal.jsx | 3 +- .../src/surveyResponse/SurveyScreens.jsx | 176 ----------------- .../admin-panel/src/surveyResponse/actions.js | 21 +- .../src/surveyResponse/constants.js | 19 +- .../admin-panel/src/surveyResponse/index.js | 1 + .../admin-panel/src/surveyResponse/reducer.js | 26 ++- .../DataFetchingTable/DataFetchingTable.jsx | 3 +- packages/admin-panel/src/table/actions.js | 36 ++++ .../ArchiveSurveyResponseButton.jsx | 43 +++++ .../table/columnTypes/ColumnActionButton.jsx | 6 +- .../src/table/columnTypes/columnFilters.jsx | 2 +- .../generateConfigForColumnType.jsx | 8 +- .../src/dhis/DhisChangeValidator.js | 17 +- .../data/aggregate/AggregateDataPusher.js | 2 + .../SurveyResponseOutdater.test.js | 14 ++ .../src/changeHandlers/TaskUpdateHandler.js | 7 +- .../SurveyResponseOutdater.js | 5 + 25 files changed, 335 insertions(+), 397 deletions(-) create mode 100644 packages/admin-panel/src/icons/ArchiveIcon.jsx create mode 100644 packages/admin-panel/src/surveyResponse/ArchiveSurveyResponseModal.jsx delete mode 100644 packages/admin-panel/src/surveyResponse/FileQuestionField.jsx delete mode 100644 packages/admin-panel/src/surveyResponse/SurveyScreens.jsx create mode 100644 packages/admin-panel/src/table/columnTypes/ArchiveSurveyResponseButton.jsx diff --git a/packages/admin-panel/src/api/mutations/useEditSurveyResponse.js b/packages/admin-panel/src/api/mutations/useEditSurveyResponse.js index 5de1e29fb2..c48fa3d852 100644 --- a/packages/admin-panel/src/api/mutations/useEditSurveyResponse.js +++ b/packages/admin-panel/src/api/mutations/useEditSurveyResponse.js @@ -6,7 +6,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useApiContext } from '../../utilities/ApiProvider'; -export const useEditSurveyResponse = (surveyResponseId, updatedSurveyResponse) => { +export const useEditSurveyResponse = (surveyResponseId, updatedSurveyResponse, onSuccess) => { const queryClient = useQueryClient(); const api = useApiContext(); return useMutation( @@ -19,7 +19,10 @@ export const useEditSurveyResponse = (surveyResponseId, updatedSurveyResponse) = onSuccess: async () => { // invalidate the survey response data await queryClient.invalidateQueries(['surveyResubmitData', surveyResponseId]); - return 'completed'; + if (onSuccess) { + onSuccess(); + } + return true; }, }, ); diff --git a/packages/admin-panel/src/icons/ArchiveIcon.jsx b/packages/admin-panel/src/icons/ArchiveIcon.jsx new file mode 100644 index 0000000000..767039381c --- /dev/null +++ b/packages/admin-panel/src/icons/ArchiveIcon.jsx @@ -0,0 +1,29 @@ +/* + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ +import React from 'react'; +import { SvgIcon } from '@material-ui/core'; + +export const ArchiveIcon = props => { + return ( + + + + ); +}; diff --git a/packages/admin-panel/src/icons/index.js b/packages/admin-panel/src/icons/index.js index 418d398bfb..f05c32dc0a 100644 --- a/packages/admin-panel/src/icons/index.js +++ b/packages/admin-panel/src/icons/index.js @@ -8,3 +8,4 @@ export { VizIcon } from './VizIcon'; export { ImportIcon } from './ImportIcon'; export { ExportIcon } from './ExportIcon'; export { CaretLeftIcon } from './CaretLeftIcon'; +export { ArchiveIcon } from './ArchiveIcon'; diff --git a/packages/admin-panel/src/pages/resources/ResourcePage.jsx b/packages/admin-panel/src/pages/resources/ResourcePage.jsx index 2deb31a774..9263c6c98a 100644 --- a/packages/admin-panel/src/pages/resources/ResourcePage.jsx +++ b/packages/admin-panel/src/pages/resources/ResourcePage.jsx @@ -15,6 +15,7 @@ import { QrCodeModal } from '../../qrCode'; import { ResubmitSurveyResponseModal } from '../../surveyResponse/ResubmitSurveyResponseModal'; import { Breadcrumbs } from '../../layout'; import { useItemDetails } from '../../api/queries/useResourceDetails'; +import { ArchiveSurveyResponseModal } from '../../surveyResponse'; const useEndpoint = (endpoint, details, params) => { if (!details && !params) return endpoint; @@ -125,6 +126,7 @@ export const ResourcePage = ({ + ); }; diff --git a/packages/admin-panel/src/rootReducer.js b/packages/admin-panel/src/rootReducer.js index e1fb76169e..2420b87efe 100644 --- a/packages/admin-panel/src/rootReducer.js +++ b/packages/admin-panel/src/rootReducer.js @@ -11,7 +11,7 @@ import { reducer as logs } from './logsTable'; import { reducer as dataChangeListener } from './dataChangeListener'; import { reducer as usedBy } from './usedBy'; import { reducer as qrCode } from './qrCode'; -import { reducer as resubmitSurveyResponse } from './surveyResponse'; +import { reducer as surveyResponse } from './surveyResponse'; const appReducer = combineReducers({ tables, @@ -21,7 +21,7 @@ const appReducer = combineReducers({ dataChangeListener, usedBy, qrCode, - resubmitSurveyResponse, + surveyResponse, }); export const rootReducer = (state, action) => { diff --git a/packages/admin-panel/src/routes/surveys/surveyResponses.jsx b/packages/admin-panel/src/routes/surveys/surveyResponses.jsx index a5870ef4fa..173f190438 100644 --- a/packages/admin-panel/src/routes/surveys/surveyResponses.jsx +++ b/packages/admin-panel/src/routes/surveys/surveyResponses.jsx @@ -29,7 +29,7 @@ const Pill = styled.span` `; const ResponseStatusPill = ({ value }) => { - const text = value ? 'Outdated' : 'Current'; + const text = value ? 'Archived' : 'Current'; const color = value ? GREY : GREEN; return {text}; }; @@ -130,6 +130,13 @@ export const SURVEY_RESPONSE_PAGE_COLUMNS = [ Header: 'Resubmit', type: 'resubmitSurveyResponse', }, + { + Header: 'Archive', + type: 'archive', + actionConfig: { + endpoint: 'surveyResponses', + }, + }, { Header: 'Delete', type: 'delete', @@ -198,6 +205,7 @@ export const surveyResponses = { defaultFilters: [{ id: 'outdated', value: false }], defaultSorting: [{ id: 'data_time', desc: true }], ExportModalComponent: SurveyResponsesExportModal, + needsBESAdminAccess: ['delete'], nestedViews: [ { title: 'Answers', diff --git a/packages/admin-panel/src/surveyResponse/ArchiveSurveyResponseModal.jsx b/packages/admin-panel/src/surveyResponse/ArchiveSurveyResponseModal.jsx new file mode 100644 index 0000000000..89f64df306 --- /dev/null +++ b/packages/admin-panel/src/surveyResponse/ArchiveSurveyResponseModal.jsx @@ -0,0 +1,109 @@ +/* + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { Modal, ModalCenteredContent, SpinningLoader } from '@tupaia/ui-components'; +import { closeArchiveSurveyResponseModal, onAfterMutate as onAfterMutateAction } from './actions'; +import { useEditSurveyResponse } from '../api/mutations/useEditSurveyResponse'; +import { Typography } from '@material-ui/core'; + +export const ArchiveSurveyResponseModalComponent = ({ + isOpen, + onDismiss, + surveyResponseId, + onAfterMutate, +}) => { + const onSuccessfulArchive = () => { + onAfterMutate(); + onDismiss(); + }; + const { + mutateAsync: editResponse, + isLoading, + isError, + error: editError, + reset, // reset the mutation state so we can dismiss the error + } = useEditSurveyResponse( + surveyResponseId, + { + outdated: true, + }, + onSuccessfulArchive, + ); + + const getButtons = () => { + if (isError) { + return [ + { + text: 'Close', + variant: 'contained', + onClick: reset, + }, + ]; + } + return [ + { + text: 'Cancel', + onClick: onDismiss, + variant: 'outlined', + disabled: isLoading, + }, + { + text: 'Submit', + onClick: editResponse, + disabled: isLoading, + }, + ]; + }; + + const buttons = getButtons(); + return ( + + + {isLoading ? ( + + ) : ( + + Are you sure you would like to archive this survey response? This cannot be undone. + + )} + + + ); +}; + +ArchiveSurveyResponseModalComponent.propTypes = { + isOpen: PropTypes.bool.isRequired, + onDismiss: PropTypes.func.isRequired, + surveyResponseId: PropTypes.string, + onAfterMutate: PropTypes.func.isRequired, +}; + +ArchiveSurveyResponseModalComponent.defaultProps = { + surveyResponseId: undefined, +}; + +const mapStateToProps = state => ({ + ...state.surveyResponse, + isOpen: state.surveyResponse.isArchiveModalOpen, +}); + +const mapDispatchToProps = dispatch => ({ + onAfterMutate: () => dispatch(onAfterMutateAction()), + onDismiss: () => dispatch(closeArchiveSurveyResponseModal()), +}); + +export const ArchiveSurveyResponseModal = connect( + mapStateToProps, + mapDispatchToProps, +)(ArchiveSurveyResponseModalComponent); diff --git a/packages/admin-panel/src/surveyResponse/FileQuestionField.jsx b/packages/admin-panel/src/surveyResponse/FileQuestionField.jsx deleted file mode 100644 index 3184c97a30..0000000000 --- a/packages/admin-panel/src/surveyResponse/FileQuestionField.jsx +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd - */ - -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import styled from 'styled-components'; -import generateId from 'uuid/v1'; -import { TextField, Modal } from '@tupaia/ui-components'; -import { getUniqueFileNameParts } from '@tupaia/utils'; -import EditIcon from '@material-ui/icons/Edit'; -import DeleteIcon from '@material-ui/icons/Delete'; -import ExportIcon from '@material-ui/icons/GetApp'; -import { FileUploadField } from '../widgets/InputField/FileUploadField'; -import { IconButton } from '../widgets'; -import { useApiContext } from '../utilities/ApiProvider'; - -const Container = styled.div` - padding-bottom: 1.2rem; -`; - -const TextFieldWithActions = styled.div` - display: flex; - gap: 15px; -`; - -const Actions = styled.div` - display: flex; - align-items: center; - gap: 3px; -`; - -const SmallIconButton = styled(IconButton)` - scale: 0.8; -`; - -const generateUniqueFileName = fileName => `${generateId()}_${fileName}`; - -const DEFAULT_MAX_FILE_SIZE_BYTES = 20 * 1024 * 1024; // 20 MB - -const AttachModal = ({ isOpen, onClose, maxSizeInBytes, onAttachFile, title }) => { - const [selectedFileSpec, setSelectedFileSpec] = useState({ fileName: null, file: null }); - - const handleClose = () => { - setSelectedFileSpec({ fileName: null, file: null }); - onClose(); - }; - - const handleSelectFile = ({ fileName, file }) => { - setSelectedFileSpec({ fileName, file }); - }; - - const handleAttachSelectedFile = () => { - onAttachFile(selectedFileSpec); - setSelectedFileSpec({ fileName: null, file: null }); - onClose(); - }; - - return ( - - - - ); -}; -AttachModal.propTypes = { - isOpen: PropTypes.bool.isRequired, - onClose: PropTypes.func.isRequired, - maxSizeInBytes: PropTypes.number.isRequired, - onAttachFile: PropTypes.func.isRequired, - title: PropTypes.string.isRequired, -}; - -/** - * Similar to FileUploadField but represents managing a file e.g. A user's certificate. - * - * E.g. when you display the field it will show the current file and allow you to remove it or replace it, - * rather than just allowing an arbitrary file upload like FileUploadField. - */ -export const FileQuestionField = ({ value: uniqueFileName, onChange, label, maxSizeInBytes }) => { - const [isDialogOpen, setIsDialogOpen] = useState(false); - const [isNewFile, setIsNewFile] = useState(false); - const { fileName = null } = uniqueFileName ? getUniqueFileNameParts(uniqueFileName) : {}; - - const handleSetFile = ({ fileName: newFileName, file }) => { - onChange({ - uniqueFileName: generateUniqueFileName(newFileName), - file, - }); - setIsNewFile(true); - }; - - const handleRemoveFile = () => { - onChange({ - uniqueFileName: null, - file: null, - }); - }; - - const api = useApiContext(); - const downloadFile = async () => { - await api.download('downloadFiles', { uniqueFileNames: uniqueFileName }, fileName); - }; - - return ( - - - - - - - - setIsDialogOpen(true)}> - - - - - - - - setIsDialogOpen(false)} - showFileSize - maxSizeInBytes={maxSizeInBytes} - onAttachFile={handleSetFile} - title={uniqueFileName ? 'Replace file' : 'Attach file'} - /> - - ); -}; - -FileQuestionField.propTypes = { - value: PropTypes.string, - onChange: PropTypes.func, - label: PropTypes.string, - maxSizeInBytes: PropTypes.number, -}; - -FileQuestionField.defaultProps = { - value: null, - onChange: () => {}, - label: '', - maxSizeInBytes: DEFAULT_MAX_FILE_SIZE_BYTES, -}; diff --git a/packages/admin-panel/src/surveyResponse/ResubmitSurveyResponseModal.jsx b/packages/admin-panel/src/surveyResponse/ResubmitSurveyResponseModal.jsx index 33158c5968..695d1e00fc 100644 --- a/packages/admin-panel/src/surveyResponse/ResubmitSurveyResponseModal.jsx +++ b/packages/admin-panel/src/surveyResponse/ResubmitSurveyResponseModal.jsx @@ -40,7 +40,8 @@ ResubmitSurveyResponseModalComponent.defaultProps = { }; const mapStateToProps = state => ({ - ...state.resubmitSurveyResponse, + ...state.surveyResponse, + isOpen: state.surveyResponse.isResubmitModalOpen, }); const mapDispatchToProps = dispatch => ({ diff --git a/packages/admin-panel/src/surveyResponse/SurveyScreens.jsx b/packages/admin-panel/src/surveyResponse/SurveyScreens.jsx deleted file mode 100644 index fa773187d8..0000000000 --- a/packages/admin-panel/src/surveyResponse/SurveyScreens.jsx +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2023 Beyond Essential Systems Pty Ltd - */ - -/* eslint-disable camelcase */ - -import React, { useState } from 'react'; -import { format } from 'date-fns'; -import styled from 'styled-components'; -import { Pagination } from '@material-ui/lab'; -import PropTypes from 'prop-types'; -import { Typography } from '@material-ui/core'; -import { TextField } from '@tupaia/ui-components'; -import { FileQuestionField } from './FileQuestionField'; - -const SectionContent = styled.div` - padding: 2rem 1rem 0.5rem 1rem; -`; - -const SectionHeader = styled(Typography)` - font-weight: 500; - font-size: 1.25rem; - line-height: 1.25rem; - padding-bottom: 0.5rem; - padding-top: 1.5rem; -`; - -const InstructionHeader = styled(Typography)` - margin: 0; -`; - -const InstructionText = styled(Typography)` - margin: 0; - padding: 5px 0px 25px 0px; -`; - -export const SurveyScreens = ({ - survey, - existingAnswers, - onChange, - onSetFormFile, - selectedEntity, - fields, -}) => { - const [updatedAnswers, setUpdatedAnswers] = useState({}); - const [currentScreenNumber, setCurrentScreenNumber] = useState(1); - - const pageCount = survey?.surveyQuestions?.length; - const screen = survey?.surveyQuestions?.find( - ({ screen_number }) => screen_number === currentScreenNumber, - ); - - const existingAndNewAnswers = { ...existingAnswers, ...updatedAnswers }; - - const handleAnswerChange = (questionCode, newValue) => { - const valueToSet = newValue === '' ? null : newValue; // Blanking an answer means deleting it, send null instead of empty string - const newAnswers = { ...updatedAnswers, [questionCode]: valueToSet }; - setUpdatedAnswers(newAnswers); - onChange('answers', newAnswers); - }; - - const handleFileAnswerChange = (questionCode, uniqueFileName, file) => { - if (file) { - onSetFormFile(questionCode, file); - handleAnswerChange(questionCode, uniqueFileName); - } else { - onSetFormFile(questionCode, null); - handleAnswerChange(questionCode, null); - } - }; - - const renderSurveyScreenComponent = component => { - if (component.question.type === 'Instruction') { - return ( -
- - Instruction - - {component.question.text} -
- ); - } - - if (component.question.type === 'PrimaryEntity') { - return ( - - ); - } - - if (component.question.type === 'File') { - return ( - - handleFileAnswerChange(component.question.code, uniqueFileName, file) - } - /> - ); - } - - if (component.question.type === 'SubmissionDate' || component.question.type === 'DateOfData') { - const formattedDate = - typeof fields.data_time === 'object' - ? format(fields.data_time, 'yyyy/MM/dd hh:mmaaa') - : format(new Date(fields.data_time), 'dd/MM/yyyy hh:mmaaa'); - - return ( - - ); - } - - return ( - handleAnswerChange(component.question.code, event.target.value.trim())} - key={`question-field-${component.question.code}`} - /> - ); - }; - - return ( -
- Answers - - {screen && - screen.survey_screen_components.map(component => renderSurveyScreenComponent(component))} - -
- setCurrentScreenNumber(screenNumber)} - hideNextButton={false} - hidePreviousButton={false} - variant="outlined" - shape="rounded" - size="large" - /> -
-
- ); -}; - -SurveyScreens.propTypes = { - survey: PropTypes.object.isRequired, - existingAnswers: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - onSetFormFile: PropTypes.func.isRequired, - selectedEntity: PropTypes.object.isRequired, - fields: PropTypes.object.isRequired, -}; diff --git a/packages/admin-panel/src/surveyResponse/actions.js b/packages/admin-panel/src/surveyResponse/actions.js index 64d11cb228..33724f2998 100644 --- a/packages/admin-panel/src/surveyResponse/actions.js +++ b/packages/admin-panel/src/surveyResponse/actions.js @@ -5,9 +5,11 @@ import { RESUBMIT_SURVEY_DISMISS, - RESUBMIT_SURVEY_END, + EDIT_SURVEY_RESPONSE_END, RESUBMIT_SURVEY_RESPONSE_OPEN, - RESUBMIT_SURVEY_START, + EDIT_SURVEY_RESPONSE_START, + ARCHIVE_SURVEY_RESPONSE_OPEN, + ARCHIVE_SURVEY_RESPONSE_DISMISS, } from './constants'; export const openResubmitSurveyResponseModal = recordId => async dispatch => { @@ -21,12 +23,23 @@ export const closeResubmitSurveyModal = () => ({ type: RESUBMIT_SURVEY_DISMISS, }); +export const openArchiveSurveyResponseModal = recordId => async dispatch => { + dispatch({ + type: ARCHIVE_SURVEY_RESPONSE_OPEN, + surveyResponseId: recordId, + }); +}; + +export const closeArchiveSurveyResponseModal = () => ({ + type: ARCHIVE_SURVEY_RESPONSE_DISMISS, +}); + // resubmission modal is not using redux for saving, this is for triggering a data refresh export const onAfterMutate = () => async dispatch => { dispatch({ - type: RESUBMIT_SURVEY_START, + type: EDIT_SURVEY_RESPONSE_START, }); dispatch({ - type: RESUBMIT_SURVEY_END, + type: EDIT_SURVEY_RESPONSE_END, }); }; diff --git a/packages/admin-panel/src/surveyResponse/constants.js b/packages/admin-panel/src/surveyResponse/constants.js index 90dc850e44..f5467f449f 100644 --- a/packages/admin-panel/src/surveyResponse/constants.js +++ b/packages/admin-panel/src/surveyResponse/constants.js @@ -1,18 +1,21 @@ /** - * Tupaia MediTrak - * Copyright (c) 2018-2023 Beyond Essential Systems Pty Ltd + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd */ export const RESUBMIT_SURVEY_RESPONSE_OPEN = 'RESUBMIT_SURVEY_RESPONSE_OPEN'; export const RESUBMIT_SURVEY_DISMISS = 'RESUBMIT_SURVEY_DISMISS'; -export const RESUBMIT_SURVEY_START = 'RESUMIT_SURVEY_START'; -export const RESUBMIT_SURVEY_END = 'RESUBMIT_SURVEY_END'; -export const RESUBMIT_SURVEY_ERROR = 'RESUBMIT_SURVEY_ERROR'; +export const EDIT_SURVEY_RESPONSE_START = 'RESUMIT_SURVEY_START'; +export const EDIT_SURVEY_RESPONSE_END = 'EDIT_SURVEY_RESPONSE_END'; +export const EDIT_SURVEY_RESPONSE_ERROR = 'EDIT_SURVEY_RESPONSE_ERROR'; + +export const ARCHIVE_SURVEY_RESPONSE_OPEN = 'ARCHIVE_SURVEY_RESPONSE_OPEN'; +export const ARCHIVE_SURVEY_RESPONSE_DISMISS = 'ARCHIVE_SURVEY_RESPONSE_DISMISS'; export const DATA_CHANGE_ACTIONS = { - start: RESUBMIT_SURVEY_START, - finish: RESUBMIT_SURVEY_END, - error: RESUBMIT_SURVEY_ERROR, + start: EDIT_SURVEY_RESPONSE_START, + finish: EDIT_SURVEY_RESPONSE_END, + error: EDIT_SURVEY_RESPONSE_ERROR, }; export const MODAL_STATUS = { diff --git a/packages/admin-panel/src/surveyResponse/index.js b/packages/admin-panel/src/surveyResponse/index.js index 5322d81ea7..4656af094f 100644 --- a/packages/admin-panel/src/surveyResponse/index.js +++ b/packages/admin-panel/src/surveyResponse/index.js @@ -6,3 +6,4 @@ // TODO: add other files to index export { reducer } from './reducer'; export * from './constants'; +export { ArchiveSurveyResponseModal } from './ArchiveSurveyResponseModal'; diff --git a/packages/admin-panel/src/surveyResponse/reducer.js b/packages/admin-panel/src/surveyResponse/reducer.js index e0f4ce9386..47639e24db 100644 --- a/packages/admin-panel/src/surveyResponse/reducer.js +++ b/packages/admin-panel/src/surveyResponse/reducer.js @@ -1,20 +1,36 @@ /** - * Tupaia MediTrak - * Copyright (c) 2018 Beyond Essential Systems Pty Ltd + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd */ import { createReducer } from '../utilities'; -import { RESUBMIT_SURVEY_RESPONSE_OPEN, RESUBMIT_SURVEY_DISMISS } from './constants'; +import { + RESUBMIT_SURVEY_RESPONSE_OPEN, + RESUBMIT_SURVEY_DISMISS, + ARCHIVE_SURVEY_RESPONSE_OPEN, + ARCHIVE_SURVEY_RESPONSE_DISMISS, +} from './constants'; const defaultState = { - isOpen: false, + isResubmitModalOpen: false, + isArchiveModalOpen: false, }; const stateChanges = { [RESUBMIT_SURVEY_DISMISS]: () => ({ ...defaultState, }), - [RESUBMIT_SURVEY_RESPONSE_OPEN]: payload => ({ ...payload, isOpen: true }), + [ARCHIVE_SURVEY_RESPONSE_DISMISS]: () => ({ + ...defaultState, + }), + [RESUBMIT_SURVEY_RESPONSE_OPEN]: payload => ({ ...payload, isResubmitModalOpen: true }), + [ARCHIVE_SURVEY_RESPONSE_OPEN]: payload => { + return { + ...defaultState, + ...payload, + isArchiveModalOpen: true, + }; + }, }; export const reducer = createReducer(defaultState, stateChanges); diff --git a/packages/admin-panel/src/table/DataFetchingTable/DataFetchingTable.jsx b/packages/admin-panel/src/table/DataFetchingTable/DataFetchingTable.jsx index 6e2f7d04d2..1068d3539c 100644 --- a/packages/admin-panel/src/table/DataFetchingTable/DataFetchingTable.jsx +++ b/packages/admin-panel/src/table/DataFetchingTable/DataFetchingTable.jsx @@ -145,6 +145,7 @@ const DataFetchingTableComponent = memo( Header: actionLabel || 'Action', maxWidth: buttonWidths, width: buttonWidths, + disableSortBy: true, // eslint-disable-next-line react/prop-types Cell: ({ row }) => { return ( @@ -241,7 +242,7 @@ const DataFetchingTableComponent = memo( onConfirm={onConfirmAction} onCancel={onCancelAction} title={deleteConfig?.title || `Delete ${singular}`} - heading={deleteConfig?.heading || `You are about to delete this ${singular}`} + heading={deleteConfig?.heading ?? `You are about to delete this ${singular}`} description={ deleteConfig?.description || `Are you sure you would like to delete this ${singular}? This cannot be undone.` diff --git a/packages/admin-panel/src/table/actions.js b/packages/admin-panel/src/table/actions.js index 9c55b10077..a9e4dae30c 100644 --- a/packages/admin-panel/src/table/actions.js +++ b/packages/admin-panel/src/table/actions.js @@ -163,6 +163,13 @@ export const requestDeleteRecord = (reduxId, endpoint, id, confirmMessage) => ({ actionCreator: () => deleteRecordFromTable(reduxId, endpoint, id), }); +export const requestArchiveSurveyResponse = (reduxId, endpoint, id, confirmMessage) => ({ + type: ACTION_REQUEST, + reduxId, + confirmMessage: confirmMessage || 'Are you sure you want to archive this record?', + actionCreator: () => archiveSurveyResponse(reduxId, endpoint, id), +}); + export const deleteRecordFromTable = (reduxId, endpoint, id) => async (dispatch, getState, { api }) => { @@ -193,3 +200,32 @@ export const deleteRecordFromTable = export const clearError = () => ({ type: CLEAR_ERROR, }); + +export const archiveSurveyResponse = + (reduxId, endpoint, id) => + async (dispatch, getState, { api }) => { + const fetchId = generateId(); + dispatch({ + type: DATA_CHANGE_REQUEST, + fetchId, + reduxId, + }); + try { + await api.put(`${endpoint}/${id}`, null, { + outdated: true, + }); + dispatch({ + type: DATA_CHANGE_SUCCESS, + fetchId, + reduxId, + }); + } catch (error) { + dispatch({ + type: DATA_CHANGE_ERROR, + reduxId, + fetchId, + errorMessage: error.message, + confirmActionMessage: '', + }); + } + }; diff --git a/packages/admin-panel/src/table/columnTypes/ArchiveSurveyResponseButton.jsx b/packages/admin-panel/src/table/columnTypes/ArchiveSurveyResponseButton.jsx new file mode 100644 index 0000000000..e2f9d14831 --- /dev/null +++ b/packages/admin-panel/src/table/columnTypes/ArchiveSurveyResponseButton.jsx @@ -0,0 +1,43 @@ +/** + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { openArchiveSurveyResponseModal } from '../../surveyResponse/actions'; +import { ColumnActionButton } from './ColumnActionButton'; +import { ArchiveIcon } from '../../icons'; + +export const ArchiveSurveyResponseButtonComponent = ({ openModal, row }) => { + if (row.original.outdated) return null; + return ( + + + + ); +}; + +ArchiveSurveyResponseButtonComponent.propTypes = { + openModal: PropTypes.func.isRequired, + row: PropTypes.shape({ + original: PropTypes.shape({ + outdated: PropTypes.bool.isRequired, + }).isRequired, + }).isRequired, +}; + +const mapDispatchToProps = (dispatch, ownProps) => { + return { + openModal: () => { + const recordId = ownProps.row.original.id; + dispatch(openArchiveSurveyResponseModal(recordId)); + }, + }; +}; + +export const ArchiveSurveyResponseButton = connect( + null, + mapDispatchToProps, +)(ArchiveSurveyResponseButtonComponent); diff --git a/packages/admin-panel/src/table/columnTypes/ColumnActionButton.jsx b/packages/admin-panel/src/table/columnTypes/ColumnActionButton.jsx index 004f7d5a01..0005922fb8 100644 --- a/packages/admin-panel/src/table/columnTypes/ColumnActionButton.jsx +++ b/packages/admin-panel/src/table/columnTypes/ColumnActionButton.jsx @@ -8,9 +8,9 @@ import { IconButton } from '@material-ui/core'; import styled from 'styled-components'; import { Tooltip } from '@tupaia/ui-components'; -const Button = styled(IconButton).attrs({ - color: 'primary', -})` +const Button = styled(IconButton).attrs(props => ({ + color: props.color || 'primary', +}))` padding: 0.3rem; `; diff --git a/packages/admin-panel/src/table/columnTypes/columnFilters.jsx b/packages/admin-panel/src/table/columnTypes/columnFilters.jsx index a5ea40fe9c..30f8aab4d9 100644 --- a/packages/admin-panel/src/table/columnTypes/columnFilters.jsx +++ b/packages/admin-panel/src/table/columnTypes/columnFilters.jsx @@ -82,7 +82,7 @@ export const OutdatedFilter = ({ filter, onChange, column }) => { id={column.id} options={[ { label: 'Show All', value: '' }, - { label: 'Outdated', value: true }, + { label: 'Archived', value: true }, { label: 'Current', value: false }, ]} onChange={e => onChange(e.target.value)} diff --git a/packages/admin-panel/src/table/columnTypes/generateConfigForColumnType.jsx b/packages/admin-panel/src/table/columnTypes/generateConfigForColumnType.jsx index 375cef39e6..4987ba57e8 100644 --- a/packages/admin-panel/src/table/columnTypes/generateConfigForColumnType.jsx +++ b/packages/admin-panel/src/table/columnTypes/generateConfigForColumnType.jsx @@ -16,9 +16,11 @@ import { TestDatabaseConnectionButton } from './TestDatabaseConnectionButton'; import { QrCodeButton } from './QrCodeButton'; import { ResubmitSurveyResponseButton } from './ResubmitSurveyResponseButton'; import { ExternalLinkButton } from './ExternalLinkButton'; +import { ArchiveSurveyResponseButton } from './ArchiveSurveyResponseButton'; -const generateCustomCell = (CustomCell, actionConfig, reduxId) => props => - ; +const generateCustomCell = (CustomCell, actionConfig, reduxId) => props => ( + +); const BUTTON_COLUMN_OPTIONS = { filterable: false, @@ -42,6 +44,7 @@ const CUSTOM_CELL_COMPONENTS = { qrCode: QrCodeButton, resubmitSurveyResponse: ResubmitSurveyResponseButton, externalLink: ExternalLinkButton, + archive: ArchiveSurveyResponseButton, }; const BUTTON_COLUMN_TYPES = [ @@ -55,6 +58,7 @@ const BUTTON_COLUMN_TYPES = [ 'bulkEdit', 'externalLink', 'sync', + 'archive', ]; export const generateConfigForColumnType = (type = 'tooltip', actionConfig, reduxId) => { diff --git a/packages/central-server/src/dhis/DhisChangeValidator.js b/packages/central-server/src/dhis/DhisChangeValidator.js index 10c657dd68..6af5e0a2b3 100644 --- a/packages/central-server/src/dhis/DhisChangeValidator.js +++ b/packages/central-server/src/dhis/DhisChangeValidator.js @@ -220,15 +220,10 @@ export class DhisChangeValidator extends ChangeValidator { return entities.filter(e => e.allowsPushingToDhis()).map(e => e.id); }; - // get associated answers for the survey responses that are being reinstated + // get associated answers for the survey responses that are being reinstated or updated getAnswersToUpdate = async allChanges => { const surveyResponseChanges = await allChanges.filter( - c => - c.record_type === 'survey_response' && - c.old_record && - c.old_record.outdated === true && - c.new_record && - c.new_record.outdated === false, + c => c.record_type === 'survey_response' && c.new_record && c.new_record.outdated === false, ); const surveyResponseIdsToUpdate = surveyResponseChanges.map(c => c.record_id); @@ -252,9 +247,12 @@ export class DhisChangeValidator extends ChangeValidator { const updateChanges = this.getUpdateChanges(changes); const validEntityIds = await this.getValidEntityUpdates(updateChanges); const validAnswerIds = await this.getValidAnswerUpdates(updateChanges); - const validSurveyResponseIds = await this.getValidSurveyResponseUpdates(updateChanges); + const validSurveyResponseIds = await this.getValidSurveyResponseUpdates(updateChanges, { + outdated: false, + }); const answersToUpdate = await this.getAnswersToUpdate(changes); - return [ + + const changesToBeMade = [ ...this.filterChangesWithMatchingIds(changes, [ ...validEntityIds, ...validAnswerIds, @@ -263,5 +261,6 @@ export class DhisChangeValidator extends ChangeValidator { ]), ...answersToUpdate, ]; + return changesToBeMade; }; } diff --git a/packages/central-server/src/dhis/pushers/data/aggregate/AggregateDataPusher.js b/packages/central-server/src/dhis/pushers/data/aggregate/AggregateDataPusher.js index 984d51029a..918ad919c7 100644 --- a/packages/central-server/src/dhis/pushers/data/aggregate/AggregateDataPusher.js +++ b/packages/central-server/src/dhis/pushers/data/aggregate/AggregateDataPusher.js @@ -308,6 +308,7 @@ export class AggregateDataPusher extends DataPusher { comparator: '!=', comparisonValue: surveyResponse.id, }, + outdated: false, survey_id: surveyResponse.survey_id, entity_id: surveyResponse.entity_id, data_time: { @@ -386,6 +387,7 @@ export class AggregateDataPusher extends DataPusher { comparisonType: 'whereBetween', args: [periodBounds], }, + outdated: false, }; switch (this.recordType) { case this.models.surveyResponse.databaseRecord: { diff --git a/packages/database/src/__tests__/changeHandlers/SurveyResponseOutdater.test.js b/packages/database/src/__tests__/changeHandlers/SurveyResponseOutdater.test.js index 2d5b7f9747..3e9ecf6d89 100644 --- a/packages/database/src/__tests__/changeHandlers/SurveyResponseOutdater.test.js +++ b/packages/database/src/__tests__/changeHandlers/SurveyResponseOutdater.test.js @@ -356,6 +356,20 @@ describe('SurveyResponseOutdater', () => { }); }); + it("Changing a response to be outdated doesn't change the status", async () => { + const [idA] = await createResponses([ + { survey_id: monthlySurveyId, entity_id: tonga.id, date: '2021-06-01' }, + ]); + await assertOutdatedStatuses({ + [idA]: false, + }); + + await models.surveyResponse.update({ id: idA }, { outdated: true }); + await assertOutdatedStatuses({ + [idA]: true, + }); + }); + it('moving an outdated response to a non periodic survey makes it "not outdated"', async () => { const [idA, , idC] = await createResponses([ { survey_id: monthlySurveyId, entity_id: tonga.id, date: '2021-06-01' }, diff --git a/packages/database/src/changeHandlers/TaskUpdateHandler.js b/packages/database/src/changeHandlers/TaskUpdateHandler.js index 99bcf87805..6479f48926 100644 --- a/packages/database/src/changeHandlers/TaskUpdateHandler.js +++ b/packages/database/src/changeHandlers/TaskUpdateHandler.js @@ -24,7 +24,12 @@ export class TaskUpdateHandler extends ChangeHandler { const { type, new_record: newRecord, old_record: oldRecord } = changeDetails; // if the change is not a create, we don't need to do anything. This is because once a task is marked as complete, it will never be undone - if (type !== 'update' || !oldRecord || oldRecord.entity_id === newRecord.entity_id) { + if ( + type !== 'update' || + !oldRecord || + oldRecord.entity_id === newRecord.entity_id || + newRecord.outdated === true + ) { return []; } return [newRecord]; diff --git a/packages/database/src/changeHandlers/surveyResponseOutdater/SurveyResponseOutdater.js b/packages/database/src/changeHandlers/surveyResponseOutdater/SurveyResponseOutdater.js index e8e625cb89..b4058fc84d 100644 --- a/packages/database/src/changeHandlers/surveyResponseOutdater/SurveyResponseOutdater.js +++ b/packages/database/src/changeHandlers/surveyResponseOutdater/SurveyResponseOutdater.js @@ -57,6 +57,11 @@ export class SurveyResponseOutdater extends ChangeHandler { return [newRecord]; } + //If the new record is being changed to be outdated, no need to process it, as it already has the correct status + if (newRecord.outdated && !oldRecord.outdated) { + return []; + } + const records = []; const fieldsOfInterest = ['data_time', 'end_time', 'survey_id', 'entity_id', 'id']; if (!haveSameFields([newRecord, oldRecord], fieldsOfInterest)) { From 1026e43751fc854682b20afb1ad6fbdafe1291ae Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Fri, 27 Sep 2024 15:26:46 +1200 Subject: [PATCH 16/27] fix(datatrakWeb): RN-1483: Fix issue with code gen replacing saved values on resubmit (#5926) * Fix issue with code gen replacing values * Update useSurveyResponseWithForm.ts --- .../Survey/SurveyContext/SurveyContext.tsx | 21 ++++++++++-------- .../features/Survey/SurveyContext/reducer.ts | 3 +++ .../features/Survey/SurveyContext/utils.ts | 22 +++++++++++-------- .../Survey/utils/useSurveyResponseWithForm.ts | 14 +++++++----- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/datatrak-web/src/features/Survey/SurveyContext/SurveyContext.tsx b/packages/datatrak-web/src/features/Survey/SurveyContext/SurveyContext.tsx index 35f94da023..7cc17f5ede 100644 --- a/packages/datatrak-web/src/features/Survey/SurveyContext/SurveyContext.tsx +++ b/packages/datatrak-web/src/features/Survey/SurveyContext/SurveyContext.tsx @@ -36,6 +36,9 @@ const defaultContext = { cancelModalOpen: false, countryCode: '', primaryEntityQuestion: null, + isResubmitScreen: false, + isResubmitReviewScreen: false, + isResubmit: false, } as SurveyFormContextType; const SurveyFormContext = createContext(defaultContext); @@ -52,7 +55,11 @@ export const SurveyContext = ({ children, surveyCode, countryCode }) => { const screenNumber = params.screenNumber ? parseInt(params.screenNumber!, 10) : null; const { data: survey } = useSurvey(surveyCode); const isResponseScreen = !!urlSearchParams.get('responseId'); - const isReviewScreen = !!useMatch(ROUTES.SURVEY_REVIEW); + const isResubmitReviewScreen = !!useMatch(ROUTES.SURVEY_RESUBMIT_REVIEW); + const isReviewScreen = !!useMatch(ROUTES.SURVEY_REVIEW) || isResubmitReviewScreen; + const isResubmitScreen = !!useMatch(ROUTES.SURVEY_RESUBMIT_SCREEN); + const isResubmit = + !!useMatch(ROUTES.SURVEY_RESUBMIT) || isResubmitScreen || isResubmitReviewScreen; let { formData } = state; @@ -101,7 +108,7 @@ export const SurveyContext = ({ children, surveyCode, countryCode }) => { const activeScreen = visibleScreens?.[screenNumber! - 1]?.surveyScreenComponents || []; const initialiseFormData = () => { - if (!surveyCode || isResponseScreen) return; + if (!surveyCode || isResponseScreen || isResubmit) return; // if we are on the response screen, we don't want to initialise the form data, because we want to show the user's saved answers const initialFormData = generateCodeForCodeGeneratorQuestions( flattenedScreenComponents, @@ -146,6 +153,9 @@ export const SurveyContext = ({ children, surveyCode, countryCode }) => { countryCode, surveyCode, primaryEntityQuestion, + isResubmitScreen, + isResubmitReviewScreen, + isResubmit, }} > @@ -164,10 +174,6 @@ export const useSurveyForm = () => { const numberOfScreens = visibleScreens?.length || 0; const isLast = screenNumber === numberOfScreens; const isSuccessScreen = !!useMatch(ROUTES.SURVEY_SUCCESS); - const isResubmitScreen = !!useMatch(ROUTES.SURVEY_RESUBMIT_SCREEN); - const isResubmitReviewScreen = !!useMatch(ROUTES.SURVEY_RESUBMIT_REVIEW); - const isResubmit = - !!useMatch(ROUTES.SURVEY_RESUBMIT) || isResubmitScreen || isResubmitReviewScreen; const toggleSideMenu = () => { dispatch({ type: ACTION_TYPES.TOGGLE_SIDE_MENU }); @@ -211,8 +217,5 @@ export const useSurveyForm = () => { getAnswerByQuestionId, openCancelConfirmation, closeCancelConfirmation, - isResubmitScreen, - isResubmitReviewScreen, - isResubmit, }; }; diff --git a/packages/datatrak-web/src/features/Survey/SurveyContext/reducer.ts b/packages/datatrak-web/src/features/Survey/SurveyContext/reducer.ts index fe2be9d8a6..54fafcc7f8 100644 --- a/packages/datatrak-web/src/features/Survey/SurveyContext/reducer.ts +++ b/packages/datatrak-web/src/features/Survey/SurveyContext/reducer.ts @@ -28,6 +28,9 @@ export type SurveyFormContextType = { cancelModalOpen: boolean; countryCode: string; primaryEntityQuestion?: SurveyScreenComponent | null; + isResubmitScreen: boolean; + isResubmitReviewScreen: boolean; + isResubmit: boolean; }; export const surveyReducer = ( diff --git a/packages/datatrak-web/src/features/Survey/SurveyContext/utils.ts b/packages/datatrak-web/src/features/Survey/SurveyContext/utils.ts index c23c7206d4..468b778af7 100644 --- a/packages/datatrak-web/src/features/Survey/SurveyContext/utils.ts +++ b/packages/datatrak-web/src/features/Survey/SurveyContext/utils.ts @@ -248,6 +248,17 @@ const updateDependentQuestions = ( return formDataCopy; }; +const generateCodeAnswer = (question: SurveyScreenComponent, formData: Record) => { + const { config, questionId } = question; + const { codeGenerator } = config as { + codeGenerator: CodeGeneratorQuestionConfig; + }; + if (hasCodeGeneratorConfig(question) && !formData[questionId]) { + return codeGenerator.type === 'shortid' ? generateShortId(codeGenerator) : generateMongoId(); + } + return formData[questionId]; +}; + export const generateCodeForCodeGeneratorQuestions = ( screenComponents: SurveyScreenComponent[], formData: Record, @@ -255,15 +266,8 @@ export const generateCodeForCodeGeneratorQuestions = ( const formDataCopy = { ...formData }; screenComponents?.forEach(question => { if (!question.config) return; - const { config, questionId } = question; - const { codeGenerator } = config as { - codeGenerator: CodeGeneratorQuestionConfig; - }; - if (hasCodeGeneratorConfig(question) && !formDataCopy[questionId]) { - const code = - codeGenerator.type === 'shortid' ? generateShortId(codeGenerator) : generateMongoId(); - formDataCopy[questionId] = code; - } + const { questionId } = question; + formDataCopy[questionId] = generateCodeAnswer(question, formDataCopy); }); return formDataCopy; }; diff --git a/packages/datatrak-web/src/features/Survey/utils/useSurveyResponseWithForm.ts b/packages/datatrak-web/src/features/Survey/utils/useSurveyResponseWithForm.ts index 1971836ea1..422a1cc655 100644 --- a/packages/datatrak-web/src/features/Survey/utils/useSurveyResponseWithForm.ts +++ b/packages/datatrak-web/src/features/Survey/utils/useSurveyResponseWithForm.ts @@ -9,6 +9,7 @@ import { stripTimezoneFromDate } from '@tupaia/utils'; import { useSurvey } from '../../../api'; import { useSurveyForm } from '../SurveyContext'; import { getAllSurveyComponents } from '../utils'; +import { generateCodeForCodeGeneratorQuestions } from '../SurveyContext/utils'; /** * Utility hook to process survey response data and populate the form with it @@ -16,7 +17,7 @@ import { getAllSurveyComponents } from '../utils'; export const useSurveyResponseWithForm = ( surveyResponse?: DatatrakWebSingleSurveyResponseRequest.ResBody, ) => { - const { setFormData, surveyScreens, surveyCode, formData } = useSurveyForm(); + const { setFormData, surveyScreens, surveyCode, formData, isResponseScreen } = useSurveyForm(); const { isLoading, isFetched, isSuccess } = useSurvey(surveyCode); const surveyLoading = isLoading || !isFetched; @@ -71,11 +72,12 @@ export const useSurveyResponseWithForm = ( formattedAnswers[dateOfDataQuestion.questionId] = surveyResponse.dataTime; } - // combine this so that formData always takes precedence - const newData = { - ...formattedAnswers, - ...formData, - }; + const combinedData = { ...formattedAnswers, ...formData }; + + // combine this so that formData always takes precedence, and apply a code to any code generator questions without answers when resubmitting. This is because otherwise, if there is no code generator answer already saved, the code generator will not be triggered and the answer will remain empty. + const newData = isResponseScreen + ? combinedData + : generateCodeForCodeGeneratorQuestions(flattenedScreenComponents, combinedData); setFormData(newData); // Reset the form context with the new answers, to trigger re-render of the form From eac9381295792132813361a45425681162551290 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 08:01:07 +1300 Subject: [PATCH 17/27] tweak(datatrakWeb): RN-1429: Hide Waka on mobile Datatrak Web (#5914) --- packages/datatrak-web/index.html | 73 +++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/packages/datatrak-web/index.html b/packages/datatrak-web/index.html index edb640c977..c3e6ad3784 100644 --- a/packages/datatrak-web/index.html +++ b/packages/datatrak-web/index.html @@ -1,9 +1,15 @@ - + - - + + Tupaia DataTrak @@ -21,26 +27,44 @@ /> - + <% if (process.env.REACT_APP_DEPLOYMENT_NAME === 'master' || process.env.REACT_APP_DEPLOYMENT_NAME === 'main' || process.env.REACT_APP_DEPLOYMENT_NAME === 'production') { %> - - - + + - gtag('config', 'G-P5KF6SLGKR'); - - + + - + if (!isMobile) { + const script = document.createElement('script'); + script.id = 'ze-snippet'; + script.src = + 'https://static.zdassets.com/ekr/snippet.js?key=4719227f-a493-431d-a920-41ebcafbcccb'; + document.head.appendChild(script); + } + + <% } %> + @@ -63,14 +87,14 @@ + rel="stylesheet" + href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" + integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" + crossorigin="" + /> @@ -79,6 +103,5 @@
- From b7bd7629b3f9c8f42b5591e0ea37570479793720 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 08:02:18 +1300 Subject: [PATCH 18/27] tweak(config): Add support for hot reloading on internal deps changes (#5920) * Add ts watch scripts * Add js watcher * Ability to watch while running stack * Add comments --- README.md | 3 +++ package.json | 2 ++ packages/api-client/package.json | 1 + packages/central-server/package.json | 2 +- packages/database/package.json | 1 + packages/datatrak-web-server/package.json | 2 +- packages/tsutils/package.json | 1 + packages/tupaia-web-server/package.json | 2 +- packages/types/package.json | 1 + packages/utils/package.json | 1 + packages/utils/tsconfig.json | 11 ++++++++--- scripts/bash/backendStartDev.sh | 10 ++++++---- 12 files changed, 27 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3b62204a08..33021bf40f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ The [Tupaia Contributing Guidelines](/.github/CONTRIBUTING.md) and [BES Contribu It is set up using [Yarn workspaces](https://yarnpkg.com/features/workspaces), meaning any command you would normally run inside a package can be run from the root directory using `yarn workspace @tupaia/package-name command`. For example, `yarn workspace @tupaia/central-server start-dev`. +If you want to watch internal dependencies while running a server, run `yarn workspace @tupaia/package-name start-dev -i`. The `-i` command will listen to changes in the internal dependencies' `dist` folders and restart on changes. +You can also run `build-watch` on these internal dependencies to watch changes and rebuild the package on change. This, combined with `-i` on the server start script will mean anytime you change something in your chosen package, the servers will restart. For example, you could run `yarn workspace @tupaia/central-server start-dev` and also `yarn workspace @tupaia/utils build-watch` which would mean the `central-server` would restart anytime you make a change in `utils`. By default, `central-server`, `datatrak-web-server`, and `tupaia-web-server` have `-i` enabled, for convenience. + Use the `start-stack` command to start all servers needed to run a stack. Available for `admin-panel`, `datatrak`, `lesmis`, `psss` and `tupaia-web`. For example, `yarn start-stack tupaia-web`. > [!TIP] diff --git a/package.json b/package.json index ce63d80a59..ec4dd91c0e 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,9 @@ "test-all": "node ./scripts/node/testAll --silent", "validate": "./scripts/bash/validate.sh", "package:build:ts": "cd $INIT_CWD && tsc -p tsconfig-build.json", + "package:build:ts-watch": "cd $INIT_CWD && tsc -p tsconfig-build.json --watch", "package:build:js": "cd $INIT_CWD && babel src --out-dir dist --source-maps --config-file \"../../babel.config.json\" --copy-files --no-copy-ignored --ignore \"**/__tests__\",\"**/__mocks__\"", + "package:build:js-watch": "cd $INIT_CWD && babel src --out-dir dist --source-maps --config-file \"../../babel.config.json\" --copy-files --no-copy-ignored --ignore \"**/__tests__\",\"**/__mocks__\" --watch", "package:build:types": "cd $INIT_CWD && tsc", "package:build:vite": "cd $INIT_CWD && vite build --config \"../../vite.config.js\"", "package:build:lib": "cd $INIT_CWD && babel src --out-dir lib --source-maps --config-file \"../../babel.config.json\" --copy-files --no-copy-ignored --ignore \"**/__tests__\",\"**/__mocks__\"", diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 063fc3aa85..7ee72b9da7 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -8,6 +8,7 @@ "scripts": { "build": "rm -rf dist && npm run --prefix ../../ package:build:ts", "build-dev": "npm run build", + "build-watch": "rm -rf dist && npm run --prefix ../../ package:build:ts-watch", "lint": "yarn package:lint", "lint:fix": "yarn lint --fix", "test": "yarn package:test", diff --git a/packages/central-server/package.json b/packages/central-server/package.json index 143fd26c11..52d652afa8 100644 --- a/packages/central-server/package.json +++ b/packages/central-server/package.json @@ -20,7 +20,7 @@ "lint:fix": "yarn lint --fix", "scheduled-task": "babel-node ./scripts/scheduledTask.js --config-file '../../babel.config.json'", "start": "node dist", - "start-dev": "yarn package:start:backend-start-dev 9999", + "start-dev": "yarn package:start:backend-start-dev 9999 -i", "start-verbose": "LOG_LEVEL=debug yarn start-dev", "setup-test": "yarn workspace @tupaia/database setup-test-database", "test": "yarn workspace @tupaia/database check-test-database-exists && NODE_ENV=test mocha", diff --git a/packages/database/package.json b/packages/database/package.json index c1e8c5d7b6..d95b783165 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -16,6 +16,7 @@ "build:src": "npm run --prefix ../../ package:build:js", "build:types": "npm run --prefix ../../ package:build:types", "build-dev": "npm run build", + "build-watch": "rm -rf dist && npm run build:types && npm run --prefix ../../ package:build:js-watch", "dump-database": "./scripts/dumpDatabase.sh", "lint": "yarn package:lint", "lint:fix": "yarn lint --fix", diff --git a/packages/datatrak-web-server/package.json b/packages/datatrak-web-server/package.json index fa9504e2f9..04cc359f1a 100644 --- a/packages/datatrak-web-server/package.json +++ b/packages/datatrak-web-server/package.json @@ -20,7 +20,7 @@ "lint": "yarn package:lint:ts", "lint:fix": "yarn lint --fix", "start": "node dist", - "start-dev": "LOG_LEVEL=debug yarn package:start:backend-start-dev 9998 -ts", + "start-dev": "LOG_LEVEL=debug yarn package:start:backend-start-dev 9998 -ts -i", "start-verbose": "LOG_LEVEL=debug yarn start-dev", "test": "yarn package:test" }, diff --git a/packages/tsutils/package.json b/packages/tsutils/package.json index ae4ea19271..192c6c13d5 100644 --- a/packages/tsutils/package.json +++ b/packages/tsutils/package.json @@ -14,6 +14,7 @@ "scripts": { "build": "rm -rf dist && npm run --prefix ../../ package:build:ts", "build-dev": "npm run build", + "build-watch": "rm -rf dist && npm run --prefix ../../ package:build:ts-watch", "lint": "yarn package:lint", "lint:fix": "yarn lint --fix", "test": "yarn package:test --passWithNoTests", diff --git a/packages/tupaia-web-server/package.json b/packages/tupaia-web-server/package.json index d923bb4c8b..4182f76e5b 100644 --- a/packages/tupaia-web-server/package.json +++ b/packages/tupaia-web-server/package.json @@ -20,7 +20,7 @@ "lint": "yarn package:lint:ts", "lint:fix": "yarn lint --fix", "start": "node dist", - "start-dev": "LOG_LEVEL=debug yarn package:start:backend-start-dev 9998 -ts", + "start-dev": "LOG_LEVEL=debug yarn package:start:backend-start-dev 9998 -ts -i", "start-verbose": "LOG_LEVEL=debug yarn start-dev", "setup-test": "yarn workspace @tupaia/database setup-test-database", "test": "yarn package:test:withdb" diff --git a/packages/types/package.json b/packages/types/package.json index 45f32ab980..d74a3d826d 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -17,6 +17,7 @@ "scripts": { "build": "rm -rf dist && npm run --prefix ../../ package:build:ts", "build-dev": "npm run build", + "build-watch": "rm -rf dist && npm run --prefix ../../ package:build:ts-watch", "lint": "yarn package:lint", "lint:fix": "yarn lint --fix", "test": "echo \"No tests specified\" && exit 0", diff --git a/packages/utils/package.json b/packages/utils/package.json index c0a3e1d282..1622f9bab7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -16,6 +16,7 @@ "build:src": "npm run --prefix ../../ package:build:js", "build:types": "npm run --prefix ../../ package:build:types", "build-dev": "npm run build", + "build-watch": "rm -rf dist && npm run build:types && npm run --prefix ../../ package:build:js-watch", "lint": "yarn package:lint", "lint:fix": "yarn lint --fix", "test": "yarn package:test", diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json index ada1054457..38d70058b6 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -1,8 +1,13 @@ { "extends": "../../tsconfig-js.json", "compilerOptions": { - "outDir": "dist" + "outDir": "dist", }, - "include": ["src/**/*.js"], - "exclude": ["src/__tests__", "src/migrations"] + "include": [ + "src/**/*.js" + ], + "exclude": [ + "src/__tests__", + "src/migrations" + ] } diff --git a/scripts/bash/backendStartDev.sh b/scripts/bash/backendStartDev.sh index 2ef6e7945a..214e413b07 100755 --- a/scripts/bash/backendStartDev.sh +++ b/scripts/bash/backendStartDev.sh @@ -41,21 +41,23 @@ done # Start server command for TS if [[ ${type_script} == true ]]; then - start_server="nodemon --watch src -e ts,json --exec node --inspect=${inspect_port} -r ts-node/register src/index.ts" + start_server="nodemon --watch src -e ts,json,js --exec node --inspect=${inspect_port} -r ts-node/register src/index.ts" fi echo "Starting server" +# If internal dependencies are included, add them to the watch list. This will watch for changes to the dist folder of each internal dependency. If the internal dependency then gets rebuilt, the server will restart. if [[ ${include_internal} == true ]]; then echo "Internal dependencies are under watch for hot reload" - for PACKAGE in $(${DIR}/getInternalDependencies.sh .); do + for PACKAGE in $(${DIR}/getInternalDependencies.sh); do watch_flags="${watch_flags} --watch ../${PACKAGE}/dist" done # add the watch flags to the server start process, as well as a 1 second delay to debounce the # many restarts that otherwise happen during the initial build of internal dependencies start_server="${start_server} --delay 1 ${watch_flags}" - ${CONCURRENTLY_BIN} "${DIR}/buildInternalDependencies.sh --watch --packagePath ." "eval ${start_server}" + else echo "Starting server without internal dependency build and watch. To include internal dependencies, add the -i flag - it's much faster than it used to be!" - eval ${start_server} + fi +eval ${start_server} From 21d1e439fcb0b95d4fb08962c80376dc23972123 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 08:04:03 +1300 Subject: [PATCH 19/27] tweak(datatrakWeb): RN-1426: Shift activity feed upwards when less than 2 recent surveys (#5923) --- .../src/views/LandingPage/LandingPage.tsx | 35 +++++++++++++------ .../LandingPage/RecentSurveysSection.tsx | 10 ++++-- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/packages/datatrak-web/src/views/LandingPage/LandingPage.tsx b/packages/datatrak-web/src/views/LandingPage/LandingPage.tsx index f86026d1bf..524d3c6816 100644 --- a/packages/datatrak-web/src/views/LandingPage/LandingPage.tsx +++ b/packages/datatrak-web/src/views/LandingPage/LandingPage.tsx @@ -13,6 +13,7 @@ import { ActivityFeedSection } from './ActivityFeedSection'; import { RecentSurveysSection } from './RecentSurveysSection'; import { TasksSection } from './TasksSection'; import { DESKTOP_MEDIA_QUERY, HEADER_HEIGHT } from '../../constants'; +import { useCurrentUserRecentSurveys } from '../../api'; const PageContainer = styled(BasePageContainer)` display: flex; @@ -34,7 +35,9 @@ const PageBody = styled.div` } `; -const Grid = styled.div` +const Grid = styled.div<{ + $hasMoreThanOneSurvey: boolean; +}>` flex: 1; display: flex; flex-direction: column; @@ -74,12 +77,24 @@ const Grid = styled.div` } ${({ theme }) => theme.breakpoints.up('lg')} { - grid-template-rows: 10.5rem auto auto; + grid-template-rows: ${({ $hasMoreThanOneSurvey }) => + $hasMoreThanOneSurvey ? '10.5rem auto auto' : '10.5rem 7rem auto'}; grid-template-columns: 23% 1fr 1fr 30%; - grid-template-areas: - 'surveySelect surveySelect surveySelect tasks' - 'recentSurveys recentSurveys recentSurveys tasks' - 'recentResponses activityFeed activityFeed leaderboard'; + grid-template-areas: ${({ $hasMoreThanOneSurvey }) => { + //If there is < 2 surveys, the recentSurveys section will be smaller and the activity feed will shift upwards on larger screens + if ($hasMoreThanOneSurvey) { + return ` + 'surveySelect surveySelect surveySelect tasks' + 'recentSurveys recentSurveys recentSurveys tasks' + 'recentResponses activityFeed activityFeed leaderboard' + `; + } + return `'surveySelect surveySelect surveySelect tasks' + 'recentSurveys activityFeed activityFeed tasks' + 'recentResponses activityFeed activityFeed leaderboard' + `; + }}; + > div { min-height: auto; } @@ -91,15 +106,15 @@ const Grid = styled.div` `; export const LandingPage = () => { - // Todo: Remove this feature flag once the feature is complete - const showTasks = process.env.REACT_APP_TUPAIA_TASKS !== 'false'; + const { data: recentSurveys = [] } = useCurrentUserRecentSurveys(); + const hasMoreThanOneSurvey = recentSurveys.length > 1; return ( - + - {showTasks && } + diff --git a/packages/datatrak-web/src/views/LandingPage/RecentSurveysSection.tsx b/packages/datatrak-web/src/views/LandingPage/RecentSurveysSection.tsx index 5ea1771f6d..14a656eb56 100644 --- a/packages/datatrak-web/src/views/LandingPage/RecentSurveysSection.tsx +++ b/packages/datatrak-web/src/views/LandingPage/RecentSurveysSection.tsx @@ -16,10 +16,13 @@ const RecentSurveys = styled.section` flex-direction: column; `; -const ScrollBody = styled.div` +const ScrollBody = styled.div<{ + $hasMoreThanOneSurvey: boolean; +}>` border-radius: 10px; display: grid; - grid-template-columns: repeat(auto-fill, minmax(calc(33.3% - 1rem), 1fr)); + grid-template-columns: ${({ $hasMoreThanOneSurvey }) => + $hasMoreThanOneSurvey ? ' repeat(auto-fill, minmax(calc(33.3% - 1rem), 1fr))' : '1fr'}; grid-column-gap: 1rem; grid-row-gap: 0.6rem; @@ -41,11 +44,12 @@ const ScrollBody = styled.div` export const RecentSurveysSection = () => { const { data: recentSurveys = [], isSuccess, isLoading } = useCurrentUserRecentSurveys(); + const hasMoreThanOneSurvey = recentSurveys.length > 1; return ( Top surveys - + {isLoading && } {isSuccess && ( <> From db4bac24b69fc87c537679baec4b856bddfc8b5a Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 08:04:47 +1300 Subject: [PATCH 20/27] tweak(tupaiaWeb): RN-1445: Update request access flow (#5901) * Request project access modal in ui components * Move datatrak web to use new ui component * WIP * Fix build issue * WIP * Remove old files from tupaia web * Styling fixes * Tidy ups * PR fixes * Update RequestProjectAccess.tsx --------- Co-authored-by: Andrew --- .../src/api/queries/useCountryAccessList.ts | 2 +- .../src/features/RequestProjectAccess.tsx | 32 +++ .../RequestProjectAccess.tsx | 70 ------ .../src/views/RequestProjectAccessPage.tsx | 18 +- .../src/views/RequestProjectAccessModal.tsx | 161 ++++++++++++++ .../RequestProjectAccessModal/ModalHeader.tsx | 88 -------- .../ProjectAccessForm.tsx | 129 ----------- .../ProjectDetails.tsx | 40 ---- .../RequestProjectAccessModal/ProjectHero.tsx | 69 ------ .../RequestProjectAccessModal.tsx | 204 ------------------ .../RequestedCountries.tsx | 90 -------- .../views/RequestProjectAccessModal/index.ts | 6 - .../src/components/Inputs/InputLabel.tsx | 1 + .../ProjectAccessForm.tsx | 98 +++++++-- .../RequestProjectAccess.tsx | 117 ++++++++++ .../features/RequestProjectAccess/index.ts | 2 +- packages/ui-components/src/features/index.ts | 1 + 17 files changed, 406 insertions(+), 722 deletions(-) create mode 100644 packages/datatrak-web/src/features/RequestProjectAccess.tsx delete mode 100644 packages/datatrak-web/src/features/RequestProjectAccess/RequestProjectAccess.tsx create mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal.tsx delete mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal/ModalHeader.tsx delete mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectAccessForm.tsx delete mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectDetails.tsx delete mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectHero.tsx delete mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal/RequestProjectAccessModal.tsx delete mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal/RequestedCountries.tsx delete mode 100644 packages/tupaia-web/src/views/RequestProjectAccessModal/index.ts rename packages/{datatrak-web => ui-components}/src/features/RequestProjectAccess/ProjectAccessForm.tsx (62%) create mode 100644 packages/ui-components/src/features/RequestProjectAccess/RequestProjectAccess.tsx rename packages/{datatrak-web => ui-components}/src/features/RequestProjectAccess/index.ts (55%) diff --git a/packages/datatrak-web/src/api/queries/useCountryAccessList.ts b/packages/datatrak-web/src/api/queries/useCountryAccessList.ts index 38e4193aa6..6ce073651d 100644 --- a/packages/datatrak-web/src/api/queries/useCountryAccessList.ts +++ b/packages/datatrak-web/src/api/queries/useCountryAccessList.ts @@ -7,7 +7,7 @@ import { useQuery } from '@tanstack/react-query'; import { Project, ProjectCountryAccessListRequest } from '@tupaia/types'; import { get } from '../api'; -export const useCountryAccessList = (projectCode: Project['code']) => { +export const useCountryAccessList = (projectCode?: Project['code']) => { return useQuery( ['me/countries', projectCode], (): Promise => diff --git a/packages/datatrak-web/src/features/RequestProjectAccess.tsx b/packages/datatrak-web/src/features/RequestProjectAccess.tsx new file mode 100644 index 0000000000..4e98d364c7 --- /dev/null +++ b/packages/datatrak-web/src/features/RequestProjectAccess.tsx @@ -0,0 +1,32 @@ +/* + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ + +import React from 'react'; +import { RequestProjectAccess as UIRequestProjectAccess } from '@tupaia/ui-components'; +import { useCountryAccessList, useProject, useRequestProjectAccess } from '../api'; + +interface RequestProjectAccessProps { + variant?: 'page' | 'modal'; + projectCode?: string; + onClose?: () => void; +} + +export const RequestProjectAccess = ({ projectCode, onClose }: RequestProjectAccessProps) => { + const { data: project, isLoading: isLoadingProject, isFetched } = useProject(projectCode); + const { mutate: requestProjectAccess, isLoading, isSuccess } = useRequestProjectAccess(); + const { data: countries } = useCountryAccessList(projectCode); + + return ( + + ); +}; diff --git a/packages/datatrak-web/src/features/RequestProjectAccess/RequestProjectAccess.tsx b/packages/datatrak-web/src/features/RequestProjectAccess/RequestProjectAccess.tsx deleted file mode 100644 index eb3601e3a4..0000000000 --- a/packages/datatrak-web/src/features/RequestProjectAccess/RequestProjectAccess.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd - */ - -import React from 'react'; -import styled from 'styled-components'; -import { Typography } from '@material-ui/core'; -import { SpinningLoader } from '@tupaia/ui-components'; -import { useProject } from '../../api'; -import { ProjectAccessForm } from './ProjectAccessForm'; - -const Wrapper = styled.div` - display: flex; - flex-direction: column; -`; - -const BodyText = styled(Typography).attrs({ - color: 'textSecondary', -})` - font-size: 0.875rem; - margin: 1rem 0 2rem; -`; - -const Container = styled.div` - padding-top: 1.75rem; -`; - -const Logo = styled.img` - max-width: 7.5rem; - width: 100%; - height: auto; -`; - -const ProjectDetails = styled.div` - padding: 1rem 0 1.6rem; -`; - -interface RequestProjectAccessProps { - variant?: 'page' | 'modal'; - projectCode?: string; - onClose?: () => void; -} - -export const RequestProjectAccess = ({ projectCode, onClose }: RequestProjectAccessProps) => { - const { data: project, isLoading: isLoadingProject, isFetched } = useProject(projectCode); - - const showLoading = isLoadingProject || !isFetched; - - return ( - - Request project access - Complete the form below to request access to this project - - {showLoading ? ( - - ) : ( - <> - {project?.logoUrl && } - - {project?.name} - {project?.description && {project.description}} - - - - )} - - - ); -}; diff --git a/packages/datatrak-web/src/views/RequestProjectAccessPage.tsx b/packages/datatrak-web/src/views/RequestProjectAccessPage.tsx index 10a04fe2ab..18d0393f99 100644 --- a/packages/datatrak-web/src/views/RequestProjectAccessPage.tsx +++ b/packages/datatrak-web/src/views/RequestProjectAccessPage.tsx @@ -5,9 +5,10 @@ import React from 'react'; import styled from 'styled-components'; import { Paper } from '@material-ui/core'; -import { RequestProjectAccess } from '../features'; import { useNavigate, useSearchParams } from 'react-router-dom'; +import { RequestProjectAccess } from '@tupaia/ui-components'; import { ROUTES } from '../constants'; +import { useCountryAccessList, useProject, useRequestProjectAccess } from '../api'; const Wrapper = styled(Paper).attrs({ variant: 'outlined', @@ -21,13 +22,26 @@ export const RequestProjectAccessPage = () => { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const projectCode = searchParams.get('project') || ''; + + const { data: project, isLoading: isLoadingProject, isFetched } = useProject(projectCode); + const { mutate: requestProjectAccess, isLoading, isSuccess } = useRequestProjectAccess(); + const { data: countries } = useCountryAccessList(projectCode); + const onReturnToProjects = () => { navigate(ROUTES.PROJECT_SELECT); }; return ( - + ); }; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal.tsx b/packages/tupaia-web/src/views/RequestProjectAccessModal.tsx new file mode 100644 index 0000000000..70cd8b9f6d --- /dev/null +++ b/packages/tupaia-web/src/views/RequestProjectAccessModal.tsx @@ -0,0 +1,161 @@ +/* + * Tupaia + * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd + */ +import React, { useEffect } from 'react'; +import { + Location, + generatePath, + useLocation, + useNavigate, + useParams, + useSearchParams, +} from 'react-router-dom'; +import styled from 'styled-components'; +import { RequestProjectAccess } from '@tupaia/ui-components'; +import { DEFAULT_URL, MODAL_ROUTES, ROUTE_STRUCTURE, URL_SEARCH_PARAMS } from '../constants'; +import { Modal } from '../components'; +import { gaEvent, removeUrlSearchParams } from '../utils'; +import { + useProjectCountryAccessList, + useLandingPage, + useProject, + useUser, + useEntity, +} from '../api/queries'; +import { useRequestCountryAccess } from '../api/mutations'; + +const ModalBody = styled.div` + display: flex; + flex-direction: column; + padding: 1.2rem; + width: 48rem; + max-width: 100%; + + .MuiAlert-root + .MuiAlert-root { + margin-block-start: 1rem; + } +`; + +export const RequestProjectAccessModal = () => { + const [urlSearchParams] = useSearchParams(); + const params = useParams(); + + const { + mutate: requestCountryAccess, + isLoading: isSubmitting, + isError: hasRequestCountryAccessError, + error: requestCountryAccessError, + isSuccess, + } = useRequestCountryAccess(); + const { hash, ...location } = useLocation(); + const navigate = useNavigate(); + const { isLandingPage } = useLandingPage(); + const { isLoggedIn, isLoading: isLoadingUser, isFetching } = useUser(); + + // Get the project code from the URL search params, or from the URL params if not otherwise set + const altProjectCode = urlSearchParams.get(URL_SEARCH_PARAMS.PROJECT); + const requestingProjectCode = altProjectCode || params?.projectCode; + + const { data: requestingProject, isLoading, isFetched } = useProject(requestingProjectCode!); + // the project loaded behind the modal, based on the url project code + const { data: backgroundProject } = useProject(params?.projectCode); + + useEffect(() => { + // if user is not already logged in, redirect to login page first, and then redirect back to this page + const checkLogin = () => { + if (isLoadingUser || isLoggedIn || isFetching) return; + navigate( + { + ...location, + hash: MODAL_ROUTES.LOGIN, + }, + { + state: { + referrer: location, + }, + }, + ); + }; + checkLogin(); + }, [isLoggedIn, isLoadingUser, isFetching, requestingProject]); + + const { data: countries = [], isFetching: isLoadingCountryAccessList } = + useProjectCountryAccessList(requestingProjectCode!); + + // if the project code is the same as the selected project and the user has access, then we are not returning to the projects page, we just want to close the modal + const isReturningToProjects = !( + (!altProjectCode || altProjectCode === params?.projectCode) && + requestingProject?.hasAccess + ); + + // only request the entity if the project code is the same as the selected project, or if the alt project code is not set, so that we don't get any false errors. This query is just to check if the user has been directed here from the useEntity hook because of a 403 error + const showCheckForEntityError = !altProjectCode || params.projectCode === altProjectCode; + const { error: entityError, isError } = useEntity( + params.projectCode, + params.entityCode, + showCheckForEntityError, + ); + + const error = requestCountryAccessError || entityError; + + // show the error if the user is getting a 403 error when trying to access an entity, as this means they have been redirected here from the useEntity hook + const showError = (isError && entityError.code === 403) || hasRequestCountryAccessError; + + const getBaseCloseLocation = () => { + if (isLandingPage) return location; + + if (isReturningToProjects) { + return { + ...location, + // if the user has access to the project in the background, then return to the project with the project modal open, otherwise return to the default url with the project modal open + pathname: backgroundProject?.hasAccess ? location.pathname : DEFAULT_URL, + hash: MODAL_ROUTES.PROJECTS, + }; + } + + // if the user has accessed the request access modal and does have access to that project in some way, then return to the project. This would happen if the user went directly to the project with the request access modal details in the url + return { + ...location, + pathname: generatePath(ROUTE_STRUCTURE, { + projectCode: requestingProject?.code, + entityCode: requestingProject?.homeEntityCode, + dashboardName: requestingProject?.dashboardGroupName as string | undefined, + }), + }; + }; + + const getCloseLocation = () => { + const baseCloseLocation = getBaseCloseLocation(); + // return the base close location with the project search param removed + return { + ...baseCloseLocation, + search: removeUrlSearchParams([URL_SEARCH_PARAMS.PROJECT]), + } as Location; + }; + + const closeLocation = getCloseLocation(); + + const onCloseModal = () => { + gaEvent('User', 'Close Dialog'); + navigate(closeLocation); + }; + + return ( + + + + + + ); +}; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal/ModalHeader.tsx b/packages/tupaia-web/src/views/RequestProjectAccessModal/ModalHeader.tsx deleted file mode 100644 index d6774e96d8..0000000000 --- a/packages/tupaia-web/src/views/RequestProjectAccessModal/ModalHeader.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd - */ -import React from 'react'; -import styled from 'styled-components'; -import { Location } from 'react-router'; -import ExploreIcon from '@material-ui/icons/ExploreOutlined'; -import { MODAL_ROUTES, TUPAIA_LIGHT_LOGO_SRC, MOBILE_BREAKPOINT } from '../../constants'; -import { RouterButton } from '../../components'; - -const Header = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1rem; - - @media screen and (max-width: ${MOBILE_BREAKPOINT}) { - flex-wrap: wrap; - } -`; - -const HeaderContainer = styled.div` - display: flex; - flex-direction: column; - - @media screen and (min-width: ${MOBILE_BREAKPOINT}) { - & + & { - margin-left: 2rem; - width: 50%; - } - } -`; - -const TagLine = styled.p` - text-align: left; - font-size: 0.75rem; -`; - -const Logo = styled.img` - max-width: 6.5rem; -`; - -const ProjectsButton = styled(RouterButton).attrs({ - variant: 'outlined', - color: 'default', -})` - margin-bottom: 1rem; - width: 14rem; - height: 3.1rem; - border-radius: 3px; - font-size: 0.8rem; - - svg { - margin-right: 0.625rem; - } -`; - -export const ModalHeader = ({ - isLandingPage, - baseCloseLocation, -}: { - isLandingPage: boolean; - baseCloseLocation: Location; -}) => { - const onCloseLocation = { - ...baseCloseLocation, - hash: MODAL_ROUTES.PROJECTS, - }; - return ( -
- - - - Data aggregation, analysis, and visualisation for the most remote settings in the world - - - - {!isLandingPage && ( - - - View other projects - - )} - -
- ); -}; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectAccessForm.tsx b/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectAccessForm.tsx deleted file mode 100644 index f144bd3724..0000000000 --- a/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectAccessForm.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd - */ -import React from 'react'; -import { SubmitHandler, useForm } from 'react-hook-form'; -import { Typography } from '@material-ui/core'; -import styled from 'styled-components'; -import { Alert } from '@tupaia/ui-components'; -import { CountryAccessListItem, SingleProject } from '../../types'; -import { - AuthModalButton, - CheckboxList, - Form as BaseForm, - LoadingScreen, - TextField, -} from '../../components'; -import { useRequestCountryAccess } from '../../api/mutations'; -import { useQueryClient } from '@tanstack/react-query'; - -const Note = styled.p` - text-align: left; - color: ${({ theme }) => theme.palette.text.secondary}; - font-size: small; - margin-bottom: 2rem; -`; - -const Form = styled(BaseForm)` - legend { - text-align: left; - } -`; - -const Error = styled(Typography).attrs({ - color: 'error', -})` - margin-bottom: 1rem; -`; - -const AlertText = styled(Typography)` - text-align: left; - font-size: inherit; -`; - -interface ProjectCountryFormProps { - availableCountries: CountryAccessListItem[]; - projectName?: SingleProject['name']; - isLandingPage?: boolean; - onCloseModal?: () => void; - closeButtonText?: string; -} - -export const ProjectAccessForm = ({ - availableCountries, - projectName, - isLandingPage, - closeButtonText, - onCloseModal, -}: ProjectCountryFormProps) => { - const formContext = useForm({ - mode: 'onChange', - }); - - const { isValid } = formContext.formState; - - const { - mutate: requestCountryAccess, - isLoading, - isError, - error, - isSuccess, - } = useRequestCountryAccess(); - - const queryClient = useQueryClient(); - - if (isSuccess) - return ( -
- - - Thank you for your access request to {projectName}. We will review your application and - respond by email shortly. - - - - Note: This can take some time to process, as requests require formal permission to be - granted. - - {!isLandingPage && ( - { - queryClient.invalidateQueries({ queryKey: ['me/countries'] }); - onCloseModal?.(); - }} - > - {closeButtonText} - - )} -
- ); - - return ( -
}> - {isError && {error.message}} - - {availableCountries.length > 0 && ( - ({ - value: id, - label: name, - }))} - name="entityIds" - required - /> - )} - - - Request Access - - - ); -}; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectDetails.tsx b/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectDetails.tsx deleted file mode 100644 index 57cf380ea9..0000000000 --- a/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectDetails.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd - */ -import React from 'react'; -import styled from 'styled-components'; -import { SingleProject } from '../../types'; -import { Typography, Divider } from '@material-ui/core'; - -const Wrapper = styled.div` - margin: 2.25rem 0; - text-align: left; -`; - -const ProjectTitle = styled.h3` - font-size: 1.3rem; - margin: 0 0 0.3rem 0; -`; - -const Countries = styled(Typography)` - margin: 0.6rem 0 1.4rem; - font-size: 0.875rem; - opacity: 0.7; - text-transform: uppercase; -`; - -interface ProjectDetailsProps { - project?: SingleProject; -} - -export const ProjectDetails = ({ project }: ProjectDetailsProps) => { - return ( - - {project?.name} - {project?.description} - {project?.names && {project.names.join(', ')}} - - - ); -}; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectHero.tsx b/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectHero.tsx deleted file mode 100644 index 6847598805..0000000000 --- a/packages/tupaia-web/src/views/RequestProjectAccessModal/ProjectHero.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd - */ -import React from 'react'; -import styled from 'styled-components'; -import { SingleProject } from '../../types'; - -const FullWidth = styled.div` - width: calc(100% + 4rem); - margin-left: -2rem; -`; - -const HeadingWrapper = styled.div` - padding: 1rem 2rem; - background-color: rgba(0, 0, 0, 0.2); -`; - -const Heading = styled.h2` - font-size: 1rem; - font-weight: ${({ theme }) => theme.typography.fontWeightMedium}; - text-align: left; - margin: 0; -`; - -const HeroImage = styled.div<{ - src: string; -}>` - width: 100%; - height: 15rem; - background-image: ${({ src }) => `url(${src})`}; - position: relative; - background-size: cover; -`; - -const LogoImage = styled.div<{ - src: string; -}>` - position: absolute; - width: 8.2rem; - height: 4.7rem; - background-color: ${({ theme }) => theme.palette.common.white}; - background-image: ${({ src }) => (src ? `url(${src})` : 'none')}; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - bottom: -1.9rem; - right: 2.5rem; - box-shadow: 0 0 6px rgba(0, 0, 0, 0.25); - border-radius: 3px; - overflow: hidden; -`; - -interface ProjectHeroProps { - project?: SingleProject; -} - -export const ProjectHero = ({ project }: ProjectHeroProps) => { - return ( - - - Requesting Project Access - - - {project?.logoUrl && } - - - ); -}; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal/RequestProjectAccessModal.tsx b/packages/tupaia-web/src/views/RequestProjectAccessModal/RequestProjectAccessModal.tsx deleted file mode 100644 index a97b2bf3fb..0000000000 --- a/packages/tupaia-web/src/views/RequestProjectAccessModal/RequestProjectAccessModal.tsx +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd - */ -import React, { useEffect, useState } from 'react'; -import { - Location, - generatePath, - useLocation, - useNavigate, - useParams, - useSearchParams, -} from 'react-router-dom'; -import styled from 'styled-components'; -import { Alert, SpinningLoader } from '@tupaia/ui-components'; -import { CountryAccessListItem } from '../../types'; -import { DEFAULT_URL, MODAL_ROUTES, ROUTE_STRUCTURE, URL_SEARCH_PARAMS } from '../../constants'; -import { LoadingScreen, Modal } from '../../components'; -import { gaEvent, removeUrlSearchParams } from '../../utils'; -import { - useProjectCountryAccessList, - useLandingPage, - useProject, - useUser, - useEntity, -} from '../../api/queries'; -import { ModalHeader } from './ModalHeader'; -import { ProjectHero } from './ProjectHero'; -import { ProjectDetails } from './ProjectDetails'; -import { ProjectAccessForm } from './ProjectAccessForm'; -import { RequestedCountries } from './RequestedCountries'; - -const ModalBody = styled.div` - display: flex; - flex-direction: column; - padding: 0.2rem 0 0; - width: 30rem; - max-width: 100%; - - .MuiAlert-root + .MuiAlert-root { - margin-block-start: 1rem; - } -`; - -export const RequestProjectAccessModal = () => { - const [urlSearchParams] = useSearchParams(); - const params = useParams(); - const [requestAdditionalCountries, setRequestAdditionalCountries] = useState(false); - const { hash, ...location } = useLocation(); - const navigate = useNavigate(); - const { isLandingPage } = useLandingPage(); - const { isLoggedIn, isLoading: isLoadingUser, isFetching } = useUser(); - - // Get the project code from the URL search params, or from the URL params if not otherwise set - const altProjectCode = urlSearchParams.get(URL_SEARCH_PARAMS.PROJECT); - const requestingProjectCode = altProjectCode || params?.projectCode; - - const { data: requestingProject, isLoading } = useProject(requestingProjectCode!); - // the project loaded behind the modal, based on the url project code - const { data: backgroundProject } = useProject(params?.projectCode); - - useEffect(() => { - // if user is not already logged in, redirect to login page first, and then redirect back to this page - const checkLogin = () => { - if (isLoadingUser || isLoggedIn || isFetching) return; - navigate( - { - ...location, - hash: MODAL_ROUTES.LOGIN, - }, - { - state: { - referrer: location, - }, - }, - ); - }; - checkLogin(); - }, [isLoggedIn, isLoadingUser, isFetching, requestingProject]); - - const { data: countries = [], isFetching: isLoadingCountryAccessList } = - useProjectCountryAccessList(requestingProjectCode!); - - const countriesWithAccess = countries?.filter((c: CountryAccessListItem) => c.hasAccess); - - // the countries that have already got a request - const requestedCountries = countries?.filter((c: CountryAccessListItem) => c.hasPendingAccess); - - // the countries that are available to request - const availableCountries = countries?.filter( - (c: CountryAccessListItem) => !c.hasAccess && !c.hasPendingAccess, - ); - - // Show the form if there are available countries, or if there are requested countries and the user has opted to request additional countries - const showForm = requestedCountries?.length - ? requestAdditionalCountries && availableCountries?.length > 0 - : availableCountries?.length > 0; - - // Show the requested countries if there are any, and the user has not opted to request additional countries - const showRequestedCountries = requestedCountries?.length > 0 && !requestAdditionalCountries; - - // if the project code is the same as the selected project and the user has access, then we are not returning to the projects page, we just want to close the modal - const isReturningToProjects = !( - (!altProjectCode || altProjectCode === params?.projectCode) && - requestingProject?.hasAccess - ); - - // only request the entity if the project code is the same as the selected project, or if the alt project code is not set, so that we don't get any false errors. This query is just to check if the user has been directed here from the useEntity hook because of a 403 error - const showCheckForEntityError = !altProjectCode || params.projectCode === altProjectCode; - const { error, isError } = useEntity( - params.projectCode, - params.entityCode, - showCheckForEntityError, - ); - - // show the error if the user is getting a 403 error when trying to access an entity, as this means they have been redirected here from the useEntity hook - const showError = isError && error.code === 403; - - // show the no countries message if the country access list has loaded and there are no countries available - const showNoCountriesMessage = !isLoadingCountryAccessList && !availableCountries?.length; - - const getBaseCloseLocation = () => { - if (isLandingPage) return location; - // if the user has accessed the request access modal and does have access to that project in some way, then return to the project. This would happen if the user went directly to the project with the request access modal details in the url - if ( - (!altProjectCode || altProjectCode === params?.projectCode) && - requestingProject?.hasAccess - ) { - return { - ...location, - pathname: generatePath(ROUTE_STRUCTURE, { - projectCode: requestingProject?.code, - entityCode: requestingProject?.homeEntityCode, - dashboardName: requestingProject?.dashboardGroupName as string | undefined, - }), - }; - } - return { - ...location, - // if the user has access to the project in the background, then return to the project with the project modal open, otherwise return to the default url with the project modal open - pathname: backgroundProject?.hasAccess ? location.pathname : DEFAULT_URL, - hash: MODAL_ROUTES.PROJECTS, - }; - }; - - const getCloseLocation = () => { - const baseCloseLocation = getBaseCloseLocation(); - // return the base close location with the project search param removed - return { - ...baseCloseLocation, - search: removeUrlSearchParams([URL_SEARCH_PARAMS.PROJECT]), - } as Location; - }; - - const closeLocation = getCloseLocation(); - - const onCloseModal = () => { - gaEvent('User', 'Close Dialog'); - navigate(closeLocation); - }; - return ( - - - - - - - {isLoadingCountryAccessList ? ( - - ) : ( - <> - {showError && {error.message}} - {showNoCountriesMessage && ( - - There are no countries available to request access to for this project. This means - you already have access to all countries in this project. If you need to change your - permissions, please contact your system administrator. - - )} - {showRequestedCountries && ( - 0} - onShowForm={() => setRequestAdditionalCountries(true)} - isLandingPage={isLandingPage} - baseCloseLocation={closeLocation} - /> - )} - {showForm && ( - - )} - - )} - - - ); -}; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal/RequestedCountries.tsx b/packages/tupaia-web/src/views/RequestProjectAccessModal/RequestedCountries.tsx deleted file mode 100644 index aad388a4a8..0000000000 --- a/packages/tupaia-web/src/views/RequestProjectAccessModal/RequestedCountries.tsx +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd - */ -import React from 'react'; -import { Location } from 'react-router'; -import { Link, Typography, List } from '@material-ui/core'; -import styled from 'styled-components'; -import { AuthModalButton, RouterButton } from '../../components'; -import { MODAL_ROUTES } from '../../constants'; -import { CountryAccessListItem } from '../../types'; - -const Text = styled(Typography)` - margin-bottom: 1rem; -`; - -const SubHeading = styled(Typography).attrs({ - variant: 'h3', -})` - font-size: 1rem; -`; - -const AccessRequestList = styled(List)` - list-style-type: none; - font-weight: ${({ theme }) => theme.typography.fontWeightBold}; - font-size: 1rem; -`; - -interface RequestedCountriesProps { - requestedCountries: CountryAccessListItem[]; - countriesWithAccess: CountryAccessListItem[]; - onShowForm: () => void; - hasAdditionalCountries: boolean; - isLandingPage?: boolean; - baseCloseLocation: Location; -} -export const RequestedCountries = ({ - requestedCountries, - countriesWithAccess, - onShowForm, - hasAdditionalCountries, - isLandingPage, - baseCloseLocation, -}: RequestedCountriesProps) => { - const onCloseLocation = { - ...baseCloseLocation, - hash: MODAL_ROUTES.PROJECTS, - }; - return ( -
- - You have already requested access to this project. - - Countries requested for this project: - - {requestedCountries.map(({ name }) => ( -
  • {name}
  • - ))} -
    - {countriesWithAccess.length > 0 && ( - <> - Countries with approved access for this project: - - {countriesWithAccess.map(({ name }) => ( -
  • {name}
  • - ))} -
    - - )} - - - This can take some time to process, as requests require formal permission to be granted. - - - If you have any questions, please email:  - admin@tupaia.org - - {hasAdditionalCountries && ( - - Request additional countries - - )} - {!isLandingPage && ( - - Back to projects - - )} -
    - ); -}; diff --git a/packages/tupaia-web/src/views/RequestProjectAccessModal/index.ts b/packages/tupaia-web/src/views/RequestProjectAccessModal/index.ts deleted file mode 100644 index 2efd543e8c..0000000000 --- a/packages/tupaia-web/src/views/RequestProjectAccessModal/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd - */ - -export { RequestProjectAccessModal } from './RequestProjectAccessModal'; diff --git a/packages/ui-components/src/components/Inputs/InputLabel.tsx b/packages/ui-components/src/components/Inputs/InputLabel.tsx index 1c5db3f5e8..b7b797597b 100644 --- a/packages/ui-components/src/components/Inputs/InputLabel.tsx +++ b/packages/ui-components/src/components/Inputs/InputLabel.tsx @@ -38,6 +38,7 @@ const TooltipWrapper = styled.span` const Tooltip = styled(BaseTooltip)` & .MuiTooltip-tooltip { background-color: ${props => props.theme.palette.text.primary}; + color: ${props => props.theme.palette.background.paper}; border-radius: 3px; font-weight: ${props => props.theme.typography.fontWeightRegular}; font-size: 0.69rem; diff --git a/packages/datatrak-web/src/features/RequestProjectAccess/ProjectAccessForm.tsx b/packages/ui-components/src/features/RequestProjectAccess/ProjectAccessForm.tsx similarity index 62% rename from packages/datatrak-web/src/features/RequestProjectAccess/ProjectAccessForm.tsx rename to packages/ui-components/src/features/RequestProjectAccess/ProjectAccessForm.tsx index 9c144458f7..788b48d4b1 100644 --- a/packages/datatrak-web/src/features/RequestProjectAccess/ProjectAccessForm.tsx +++ b/packages/ui-components/src/features/RequestProjectAccess/ProjectAccessForm.tsx @@ -13,15 +13,15 @@ import { Typography, } from '@material-ui/core'; import { CheckCircle } from '@material-ui/icons'; +import { ProjectCountryAccessListRequest, WebServerProjectRequest } from '@tupaia/types'; import { Checkbox as BaseCheckbox, - Form, - FormInput, SpinningLoader, TextField, -} from '@tupaia/ui-components'; -import { useCountryAccessList, useRequestProjectAccess } from '../../api'; -import { Button } from '../../components'; + Button, + Alert, +} from '../../components'; +import { Form, FormInput } from '../Form'; const FormControl = styled(BaseFormControl).attrs({ component: 'fieldset', @@ -63,6 +63,9 @@ const TextArea = styled(TextField).attrs({ font-size: 0.875rem; padding: 0.875rem; } + .MuiInputBase-root { + background-color: ${({ theme }) => theme.palette.background.paper}; + } // we have to override this here as there are selectors inside ui-components with higher specificity than we can achieve via the theme overrides .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline { box-shadow: none; @@ -95,19 +98,38 @@ const LoaderWrapper = styled.div` /** Fixes janky spacing changes when 'Request access' button is enabled or disabled */ const StyledDialogActions = styled(DialogActions)` gap: 1rem; - + padding: 1.5rem 0 0 0; & > :not(:first-child) { margin-inline-start: 0; } `; +const FormButton = styled(Button)` + text-transform: none; + font-size: 0.875rem; +`; + +type Country = ProjectCountryAccessListRequest.ResBody[number]; + interface ProjectAccessFormProps { - project: any; + project?: WebServerProjectRequest.ResBody; onClose?: () => void; + countries: Country[]; + onSubmit: (data: { entityIds: string[]; message: string; projectCode: string }) => void; + isSubmitting: boolean; + isSuccess: boolean; + closeButtonText?: string; } -export const ProjectAccessForm = ({ project, onClose }: ProjectAccessFormProps) => { - const { data: countries } = useCountryAccessList(project.code); +export const ProjectAccessForm = ({ + project, + onClose, + countries, + onSubmit, + isSubmitting, + isSuccess, + closeButtonText = 'Back to projects', +}: ProjectAccessFormProps) => { const formContext = useForm({ mode: 'onChange', }); @@ -115,16 +137,38 @@ export const ProjectAccessForm = ({ project, onClose }: ProjectAccessFormProps) formState: { isValid }, register, } = formContext; - const { mutate: requestProjectAccess, isLoading, isSuccess } = useRequestProjectAccess(); const projectCode = project?.code; const submitForm = (formData: any) => { - requestProjectAccess({ + onSubmit({ ...formData, projectCode, }); }; + // the countries that are available to request + const availableCountries = countries?.filter((c: Country) => !c.hasAccess && !c.hasPendingAccess); + + // show the no countries message if the country access list has loaded and there are no countries available + const showNoCountriesMessage = !availableCountries?.length && !isSuccess; + + if (showNoCountriesMessage) { + return ( + <> + + There are no countries available to request access to for this project. This means you + already have access to all countries in this project. If you need to change your + permissions, please contact your system administrator. + + + + Back + + + + ); + } + // On success, show a success message to the user and direct them back to the projects list if (isSuccess) return ( @@ -141,36 +185,46 @@ export const ProjectAccessForm = ({ project, onClose }: ProjectAccessFormProps) - + {closeButtonText} ); // While the request is being processed, show a loading spinner - if (isLoading) + if (isSubmitting) return ( ); + const getTooltip = (country: Country) => { + if (country.hasPendingAccess) { + return 'Approval in progress'; + } + if (country.hasAccess) { + return 'You already have access to this country'; + } + return undefined; + }; + return (
    } formContext={formContext}> - {countries?.map(({ id, name, hasPendingAccess }) => { + {countries?.map(country => { + const { id, name, hasPendingAccess, hasAccess } = country; + const tooltip = getTooltip(country); return ( value.length > 0 })} - disabled={hasPendingAccess} + disabled={hasPendingAccess || hasAccess} key={id} label={name} name="entityIds" value={id} - tooltip={ - hasPendingAccess ? 'You have already requested access to this country' : undefined - } + tooltip={tooltip} /> ); })} @@ -178,16 +232,16 @@ export const ProjectAccessForm = ({ project, onClose }: ProjectAccessFormProps) - - + ); diff --git a/packages/ui-components/src/features/RequestProjectAccess/RequestProjectAccess.tsx b/packages/ui-components/src/features/RequestProjectAccess/RequestProjectAccess.tsx new file mode 100644 index 0000000000..e48311ecc5 --- /dev/null +++ b/packages/ui-components/src/features/RequestProjectAccess/RequestProjectAccess.tsx @@ -0,0 +1,117 @@ +/* + * Tupaia + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd + */ + +import React from 'react'; +import styled from 'styled-components'; +import { Typography } from '@material-ui/core'; +import { ProjectCountryAccessListRequest, WebServerProjectRequest } from '@tupaia/types'; +import { ProjectAccessForm } from './ProjectAccessForm'; +import { Alert, SpinningLoader } from '../../components'; + +const Wrapper = styled.div` + display: flex; + flex-direction: column; + text-align: left; +`; + +const BodyText = styled(Typography).attrs({ + color: 'textSecondary', +})` + font-size: 0.875rem; + margin: 1rem 0 2rem; +`; + +const Container = styled.div` + padding-top: 1.75rem; +`; + +const Logo = styled.img` + max-width: 8rem; + width: 100%; + height: auto; + border-radius: 3px; + background-color: ${({ theme }) => theme.palette.common.white}; + padding: 0.8rem; +`; + +const ProjectDetails = styled.div` + padding: 1rem 0 1.6rem; +`; + +const Title = styled(Typography).attrs({ + variant: 'h1', +})` + font-size: 1.125rem; + font-weight: ${({ theme }) => theme.typography.fontWeightMedium}; +`; + +const ProjectName = styled(Typography).attrs({ + variant: 'h2', +})` + font-size: 1rem; + font-weight: ${({ theme }) => theme.typography.fontWeightMedium}; +`; + +const ProjectDescription = styled(Typography)` + font-size: 0.875rem; + margin-block-start: 0.25rem; +`; + +interface RequestProjectAccessProps { + onClose?: () => void; + project?: WebServerProjectRequest.ResBody; + isLoading?: boolean; + countries: ProjectCountryAccessListRequest.ResBody[number][]; + onSubmit: (data: { entityIds: string[]; message: string; projectCode: string }) => void; + isSubmitting: boolean; + isSuccess: boolean; + closeButtonText?: string; + errorMessage?: string; +} + +export const RequestProjectAccess = ({ + onClose, + project, + isLoading, + countries, + onSubmit, + isSuccess, + isSubmitting, + closeButtonText, + errorMessage, +}: RequestProjectAccessProps) => { + return ( + + Request project access + Complete the form below to request access to this project + + {isLoading ? ( + + ) : ( + <> + {project?.logoUrl && } + + {project?.name} + {project?.description && ( + {project.description} + )} + + {errorMessage && {errorMessage}} + + + + )} + + + ); +}; diff --git a/packages/datatrak-web/src/features/RequestProjectAccess/index.ts b/packages/ui-components/src/features/RequestProjectAccess/index.ts similarity index 55% rename from packages/datatrak-web/src/features/RequestProjectAccess/index.ts rename to packages/ui-components/src/features/RequestProjectAccess/index.ts index a84ef8d286..6a75452192 100644 --- a/packages/datatrak-web/src/features/RequestProjectAccess/index.ts +++ b/packages/ui-components/src/features/RequestProjectAccess/index.ts @@ -1,5 +1,5 @@ /* * Tupaia - * Copyright (c) 2017 - 2023 Beyond Essential Systems Pty Ltd + * Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd */ export { RequestProjectAccess } from './RequestProjectAccess'; diff --git a/packages/ui-components/src/features/index.ts b/packages/ui-components/src/features/index.ts index cc8c1f7629..d14d6c80a7 100644 --- a/packages/ui-components/src/features/index.ts +++ b/packages/ui-components/src/features/index.ts @@ -5,3 +5,4 @@ export * from './Auth'; export * from './Form'; export { RouterLink } from './RouterLink'; +export * from './RequestProjectAccess'; From ccac2f9b64fc1409fb83872f1fc71ca655030d2f Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:01:25 +1300 Subject: [PATCH 21/27] fix(tests): Fix broken timezone tests after DST changes (#5927) Update timezone.test.js --- packages/utils/src/__tests__/timezone.test.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/utils/src/__tests__/timezone.test.js b/packages/utils/src/__tests__/timezone.test.js index e6dc9528d2..7ba71829e8 100644 --- a/packages/utils/src/__tests__/timezone.test.js +++ b/packages/utils/src/__tests__/timezone.test.js @@ -7,16 +7,17 @@ import { getOffsetForTimezone } from '../timezone'; describe('getOffsetForTimezone', () => { it('Should return the correct offset for the timezone', async () => { - expect(getOffsetForTimezone('Pacific/Auckland')).toBe('+12:00'); - expect(getOffsetForTimezone('Pacific/Chatham')).toBe('+12:45'); - expect(getOffsetForTimezone('Pacific/Fiji')).toBe('+12:00'); - expect(getOffsetForTimezone('Asia/Kolkata')).toBe('+05:30'); - expect(getOffsetForTimezone('Asia/Kathmandu')).toBe('+05:45'); - expect(getOffsetForTimezone('Asia/Tehran')).toBe('+03:30'); - expect(getOffsetForTimezone('Europe/London')).toBe('+01:00'); - expect(getOffsetForTimezone('America/New_York')).toBe('-04:00'); - expect(getOffsetForTimezone('America/Los_Angeles')).toBe('-07:00'); - expect(getOffsetForTimezone('Pacific/Honolulu')).toBe('-10:00'); + const date = new Date('2024-08-01'); + expect(getOffsetForTimezone('Pacific/Auckland', date)).toBe('+12:00'); + expect(getOffsetForTimezone('Pacific/Chatham', date)).toBe('+12:45'); + expect(getOffsetForTimezone('Pacific/Fiji', date)).toBe('+12:00'); + expect(getOffsetForTimezone('Asia/Kolkata', date)).toBe('+05:30'); + expect(getOffsetForTimezone('Asia/Kathmandu', date)).toBe('+05:45'); + expect(getOffsetForTimezone('Asia/Tehran', date)).toBe('+03:30'); + expect(getOffsetForTimezone('Europe/London', date)).toBe('+01:00'); + expect(getOffsetForTimezone('America/New_York', date)).toBe('-04:00'); + expect(getOffsetForTimezone('America/Los_Angeles', date)).toBe('-07:00'); + expect(getOffsetForTimezone('Pacific/Honolulu', date)).toBe('-10:00'); expect(getOffsetForTimezone('Australia/Lord_Howe', new Date('2021-03-08'))).toBe('+11:00'); expect(getOffsetForTimezone('Australia/Lord_Howe', new Date('2021-07-08'))).toBe('+10:30'); }); From 33a2dfe369f4a5a055557e9e8ad7acaefadf0c71 Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:20:40 +1300 Subject: [PATCH 22/27] fix(datatrakWeb): RN-1484: Fix autocomplete question not sticking (#5929) --- .../src/features/Questions/AutocompleteQuestion.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/datatrak-web/src/features/Questions/AutocompleteQuestion.tsx b/packages/datatrak-web/src/features/Questions/AutocompleteQuestion.tsx index 054bd4279d..dd6f561113 100644 --- a/packages/datatrak-web/src/features/Questions/AutocompleteQuestion.tsx +++ b/packages/datatrak-web/src/features/Questions/AutocompleteQuestion.tsx @@ -67,7 +67,7 @@ export const AutocompleteQuestion = ({ config = {}, controllerProps: { value: selectedValue = null, onChange, ref, invalid }, }: SurveyQuestionInputProps) => { - const [searchValue, setSearchValue] = useState(''); + const [searchValue, setSearchValue] = useState(selectedValue?.value || selectedValue || ''); const { autocomplete = {} } = config!; const { attributes, createNew } = autocomplete; const { data, isLoading, isError, error, isFetched } = useAutocompleteOptions( @@ -130,7 +130,8 @@ export const AutocompleteQuestion = ({ value={selectedValue?.value || selectedValue || null} required={required} onChange={(_e, newSelectedOption) => handleSelectOption(newSelectedOption)} - onInputChange={throttle((_, newValue) => { + onInputChange={throttle((e, newValue) => { + if (newValue === searchValue || !e || !e.target) return; setSearchValue(newValue); }, 200)} inputValue={searchValue} From 8c564995c1136b3f87d6b417c25f9e00e211495d Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:28:44 +1300 Subject: [PATCH 23/27] fix(datatrakWeb): RN-1454: Don't show all entities when no value in review screen (#5930) --- .../src/components/SelectList/SelectList.tsx | 4 +++- .../src/features/EntitySelector/EntitySelector.tsx | 3 +++ .../src/features/EntitySelector/ResultsList.tsx | 9 ++++++++- .../src/features/Questions/EntityQuestion.tsx | 6 +++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/datatrak-web/src/components/SelectList/SelectList.tsx b/packages/datatrak-web/src/components/SelectList/SelectList.tsx index 83c310e359..9ee4153e96 100644 --- a/packages/datatrak-web/src/components/SelectList/SelectList.tsx +++ b/packages/datatrak-web/src/components/SelectList/SelectList.tsx @@ -63,6 +63,7 @@ interface SelectListProps { labelProps?: FormLabelProps & { component?: React.ElementType; }; + noResultsMessage?: string; } export const SelectList = ({ @@ -72,6 +73,7 @@ export const SelectList = ({ ListItem, variant = 'inline', labelProps = {}, + noResultsMessage = 'No items to display', }: SelectListProps) => { return ( @@ -82,7 +84,7 @@ export const SelectList = ({ )} {items.length === 0 ? ( - No items to display + {noResultsMessage} ) : ( )} diff --git a/packages/datatrak-web/src/features/EntitySelector/EntitySelector.tsx b/packages/datatrak-web/src/features/EntitySelector/EntitySelector.tsx index 2584ec2e4e..1fd84010ce 100644 --- a/packages/datatrak-web/src/features/EntitySelector/EntitySelector.tsx +++ b/packages/datatrak-web/src/features/EntitySelector/EntitySelector.tsx @@ -68,6 +68,7 @@ interface EntitySelectorProps { component?: React.ElementType; variant?: TypographyProps['variant']; }; + noResultsMessage?: string; } export const EntitySelector = ({ @@ -88,6 +89,7 @@ export const EntitySelector = ({ showSearchInput, legend, legendProps, + noResultsMessage, }: EntitySelectorProps) => { const { errors } = useFormContext(); const [isDirty, setIsDirty] = useState(false); @@ -164,6 +166,7 @@ export const EntitySelector = ({ onSelect={onSelect} searchResults={disableSearch ? [] : displayResults} showRecentEntities={showRecentEntities} + noResultsMessage={noResultsMessage} /> )}
    diff --git a/packages/datatrak-web/src/features/EntitySelector/ResultsList.tsx b/packages/datatrak-web/src/features/EntitySelector/ResultsList.tsx index 952af1a30a..bde1e21c8c 100644 --- a/packages/datatrak-web/src/features/EntitySelector/ResultsList.tsx +++ b/packages/datatrak-web/src/features/EntitySelector/ResultsList.tsx @@ -49,6 +49,7 @@ interface ResultsListProps { searchResults?: SearchResults; onSelect: (value: ListItemType) => void; showRecentEntities?: boolean; + noResultsMessage?: string; } export const ResultsList = ({ @@ -56,6 +57,7 @@ export const ResultsList = ({ searchResults, onSelect, showRecentEntities, + noResultsMessage, }: ResultsListProps) => { const getEntitiesList = (returnRecentEntities?: boolean) => { const entities = searchResults?.filter(({ isRecent }) => @@ -85,7 +87,12 @@ export const ResultsList = ({ )} {showRecentEntities && All entities} - + ); diff --git a/packages/datatrak-web/src/features/Questions/EntityQuestion.tsx b/packages/datatrak-web/src/features/Questions/EntityQuestion.tsx index 8e599008ed..a16166a7c7 100644 --- a/packages/datatrak-web/src/features/Questions/EntityQuestion.tsx +++ b/packages/datatrak-web/src/features/Questions/EntityQuestion.tsx @@ -36,17 +36,21 @@ export const EntityQuestion = ({ invalid, }} showLegend={isReviewScreen || isResponseScreen} + disableSearch={(isReviewScreen || isResponseScreen) && !value} projectCode={surveyProjectCode} config={config} data={formData} countryCode={countryCode} - showRecentEntities + showRecentEntities={!isReviewScreen && !isResponseScreen} showSearchInput={!isReviewScreen && !isResponseScreen} legend={label} legendProps={{ component: Typography, variant: 'h4', }} + noResultsMessage={ + isReviewScreen || isResponseScreen ? 'No entity selected' : 'No entities to display' + } /> ); }; From d02206f67604d6633ecc0670f5cbcb04a4ed70aa Mon Sep 17 00:00:00 2001 From: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:25:16 +1300 Subject: [PATCH 24/27] tweak(adminPanel): RN-1456: Allow export of archived survey responses via the admin panel (#5904) * Allow export of outdated responses * Update timezone.test.js * Change mode language * Update exportResponsesToFile.js * Reset values on close modal --------- Co-authored-by: Andrew --- .../src/importExport/ExportModal.jsx | 6 ++++ .../SurveyResponsesExportModal.jsx | 28 +++++++++++++++++-- .../exportResponsesToFile.js | 7 ++++- .../exportSurveyResponses.js | 2 ++ .../getSurveyResponsesExportModal.jsx | 2 +- 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/packages/admin-panel/src/importExport/ExportModal.jsx b/packages/admin-panel/src/importExport/ExportModal.jsx index 0c0e51902f..eb80a08dc4 100644 --- a/packages/admin-panel/src/importExport/ExportModal.jsx +++ b/packages/admin-panel/src/importExport/ExportModal.jsx @@ -27,6 +27,7 @@ export const ExportModal = React.memo( exportButtonText, cancelButtonText, isExportingMessage, + onCloseModal, }) => { const api = useApiContext(); const [status, setStatus] = useState(STATUS.IDLE); @@ -44,6 +45,9 @@ export const ExportModal = React.memo( setStatus(STATUS.IDLE); setError(null); setIsOpen(false); + if (onCloseModal) { + onCloseModal(); + } }; const handleSubmit = async event => { @@ -152,6 +156,7 @@ ExportModal.propTypes = { exportButtonText: PropTypes.string, cancelButtonText: PropTypes.string, isExportingMessage: PropTypes.string, + onCloseModal: PropTypes.func, }; ExportModal.defaultProps = { @@ -162,4 +167,5 @@ ExportModal.defaultProps = { isExportingMessage: 'Export is taking a while, and will continue in the background. You will be emailed the exported file when the process completes.', values: {}, + onCloseModal: null, }; diff --git a/packages/admin-panel/src/importExport/SurveyResponsesExportModal.jsx b/packages/admin-panel/src/importExport/SurveyResponsesExportModal.jsx index ed044696b6..7a3a50b93d 100644 --- a/packages/admin-panel/src/importExport/SurveyResponsesExportModal.jsx +++ b/packages/admin-panel/src/importExport/SurveyResponsesExportModal.jsx @@ -10,6 +10,7 @@ import { stripTimezoneFromDate } from '@tupaia/utils'; import { ReduxAutocomplete } from '../autocomplete'; import { ExportModal } from './ExportModal'; import { EntityOptionLabel } from '../widgets'; +import { Checkbox, FormControlLabel } from '@material-ui/core'; const MODES = { COUNTRY: { value: 'country', formInput: 'countryCode' }, @@ -40,8 +41,20 @@ export const SurveyResponsesExportModal = () => { })); }; + const clearValues = () => { + setValues({}); + onChangeMode(MODES.COUNTRY.value); + setCountryCode(undefined); + setEntityIds(undefined); + }; + return ( - + { /> onChangeMode(event.currentTarget.value)} options={[ { @@ -126,6 +139,17 @@ export const SurveyResponsesExportModal = () => { } }} /> + handleValueChange('includeArchived', event.target.checked)} + name="include-archived" + color="primary" + /> + } + label="Include archived survey responses" + /> ); }; diff --git a/packages/central-server/src/apiV2/export/exportSurveyResponses/exportResponsesToFile.js b/packages/central-server/src/apiV2/export/exportSurveyResponses/exportResponsesToFile.js index 1bad77f428..283924806e 100644 --- a/packages/central-server/src/apiV2/export/exportSurveyResponses/exportResponsesToFile.js +++ b/packages/central-server/src/apiV2/export/exportSurveyResponses/exportResponsesToFile.js @@ -63,6 +63,7 @@ export async function exportResponsesToFile( surveyResponse, surveys, timeZone, + includeArchived = false, }, ) { if (surveys.length === 0) { @@ -165,8 +166,12 @@ export async function exportResponsesToFile( const findResponsesForSurvey = async survey => { const surveyResponseFindConditions = { survey_id: survey.id, - outdated: false, // only get the latest version of each survey response. Outdated responses are usually resubmissions }; + + if (includeArchived !== true && includeArchived !== 'true') { + surveyResponseFindConditions.outdated = false; // only get the latest version of each survey response unless includeArchived === true. Outdated responses are usually resubmissions + } + const dataTimeCondition = getDataTimeCondition(); if (dataTimeCondition) { surveyResponseFindConditions.data_time = dataTimeCondition; diff --git a/packages/central-server/src/apiV2/export/exportSurveyResponses/exportSurveyResponses.js b/packages/central-server/src/apiV2/export/exportSurveyResponses/exportSurveyResponses.js index 89c5ed8beb..4e784b0ac9 100644 --- a/packages/central-server/src/apiV2/export/exportSurveyResponses/exportSurveyResponses.js +++ b/packages/central-server/src/apiV2/export/exportSurveyResponses/exportSurveyResponses.js @@ -22,6 +22,7 @@ export async function exportSurveyResponses(req, res) { entityIds, entityCode, countryCode, + includeArchived = false, latest = false, startDate, endDate, @@ -58,6 +59,7 @@ export async function exportSurveyResponses(req, res) { surveyResponse, surveys, timeZone, + includeArchived, }); respondWithDownload(res, filePath); } diff --git a/packages/lesmis/src/views/AdminPanel/components/getSurveyResponsesExportModal.jsx b/packages/lesmis/src/views/AdminPanel/components/getSurveyResponsesExportModal.jsx index 450864ec62..d6d43d84ae 100644 --- a/packages/lesmis/src/views/AdminPanel/components/getSurveyResponsesExportModal.jsx +++ b/packages/lesmis/src/views/AdminPanel/components/getSurveyResponsesExportModal.jsx @@ -45,7 +45,7 @@ export const getSurveyResponsesExportModal = translate => { /> setMode(event.currentTarget.value)} options={[ { From d046bf80cbb59d353a33dce7130bde6a3cbd7c71 Mon Sep 17 00:00:00 2001 From: Salman <114740396+hrazasalman@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:46:12 +1000 Subject: [PATCH 25/27] fix(adminPanel): RN-1397: Filtering by sort order result inconsistency (#5837) Update custom filters --- .../DataFetchingTable/useColumnFilters.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/admin-panel/src/table/DataFetchingTable/useColumnFilters.js b/packages/admin-panel/src/table/DataFetchingTable/useColumnFilters.js index d4326f75a0..6aacd96eca 100644 --- a/packages/admin-panel/src/table/DataFetchingTable/useColumnFilters.js +++ b/packages/admin-panel/src/table/DataFetchingTable/useColumnFilters.js @@ -15,21 +15,20 @@ export const useColumnFilters = (defaultFilters = []) => { const filters = urlFilters ? JSON.parse(urlFilters) : defaultFilters; const onChangeFilters = newFilters => { - // if the filters are the same, don't update the URL - if (JSON.stringify(newFilters) === JSON.stringify(filters)) return; + // Remove filters with empty values + const updatedFilters = newFilters.filter(filter => filter.value !== ''); - if (newFilters.length === 0) { - // if there are filters in the URL, delete the filters key - urlSearchParams.delete('filters'); + // Check if the cleaned filters are the same as current filters + if (JSON.stringify(updatedFilters) === JSON.stringify(filters)) return; - setUrlSearchParams(urlSearchParams, { - state: location.state, - }); - return; + if (updatedFilters.length === 0) { + // If there are no filters left, delete the filters key + urlSearchParams.delete('filters'); + } else { + // Update the filters key in the URL + urlSearchParams.set('filters', JSON.stringify(updatedFilters)); } - // update the filters key in the URL - urlSearchParams.set('filters', JSON.stringify(newFilters)); setUrlSearchParams(urlSearchParams, { state: location.state, }); From 64356c13cce24287bdd9d92789dc712da163fc9f Mon Sep 17 00:00:00 2001 From: Salman <114740396+hrazasalman@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:47:23 +1000 Subject: [PATCH 26/27] tweak(adminPanel): RN-1427: Remove .CSV from supported file types (#5862) * Update EditSurveyPage.jsx * all file uploader updated * updated * updates --------- Co-authored-by: alexd-bes <129009580+alexd-bes@users.noreply.github.com> --- packages/admin-panel/src/importExport/ImportModal.jsx | 1 + packages/admin-panel/src/pages/StrivePage.jsx | 4 ++++ .../src/pages/resources/editSurvey/EditSurveyPage.jsx | 1 - packages/admin-panel/src/routes/entities/entities.js | 4 ++++ packages/admin-panel/src/routes/surveys/dataElements.js | 4 ++++ packages/admin-panel/src/routes/surveys/dataMapping.js | 4 ++++ packages/admin-panel/src/routes/surveys/optionSets.js | 4 ++++ packages/admin-panel/src/routes/surveys/surveyResponses.jsx | 4 ++++ packages/admin-panel/src/routes/surveys/surveys.js | 4 ++++ packages/admin-panel/src/routes/users/permissions.js | 4 ++++ packages/admin-panel/src/routes/users/users.jsx | 4 ++++ .../admin-panel/src/routes/visualisations/dashboardItems.jsx | 3 +++ packages/admin-panel/src/routes/visualisations/dataTables.js | 3 +++ .../admin-panel/src/routes/visualisations/mapOverlays.jsx | 3 +++ .../src/widgets/InputField/registerInputFields.jsx | 1 + 15 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/admin-panel/src/importExport/ImportModal.jsx b/packages/admin-panel/src/importExport/ImportModal.jsx index ef4515b59d..3708ec16ee 100644 --- a/packages/admin-panel/src/importExport/ImportModal.jsx +++ b/packages/admin-panel/src/importExport/ImportModal.jsx @@ -190,6 +190,7 @@ export const ImportModalComponent = React.memo( onChange={newFiles => setFiles(newFiles ?? [])} name="file-upload" multiple={actionConfig.multiple} + accept={actionConfig.accept} /> )} diff --git a/packages/admin-panel/src/pages/StrivePage.jsx b/packages/admin-panel/src/pages/StrivePage.jsx index 6893d1cf84..a72a4a6e8b 100644 --- a/packages/admin-panel/src/pages/StrivePage.jsx +++ b/packages/admin-panel/src/pages/StrivePage.jsx @@ -12,6 +12,10 @@ const importConfig = { title: 'Import lab results or vector data', actionConfig: { importEndpoint: 'striveLabResults', + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, }; diff --git a/packages/admin-panel/src/pages/resources/editSurvey/EditSurveyPage.jsx b/packages/admin-panel/src/pages/resources/editSurvey/EditSurveyPage.jsx index 28ce086b10..a54c08d47d 100644 --- a/packages/admin-panel/src/pages/resources/editSurvey/EditSurveyPage.jsx +++ b/packages/admin-panel/src/pages/resources/editSurvey/EditSurveyPage.jsx @@ -203,7 +203,6 @@ const EditSurveyPageComponent = withConnectedEditor( accept={{ 'application/vnd.ms-excel': ['.xls'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], - 'text/csv': ['.csv'], }} fileName={initialFileName} label="Survey questions" diff --git a/packages/admin-panel/src/routes/entities/entities.js b/packages/admin-panel/src/routes/entities/entities.js index 5c66a1f06f..63c3cc61ac 100644 --- a/packages/admin-panel/src/routes/entities/entities.js +++ b/packages/admin-panel/src/routes/entities/entities.js @@ -78,6 +78,10 @@ const IMPORT_CONFIG = { 'Please note that if this is the first time a country is being imported, you will need to restart central-server post-import for it to sync to DHIS2.', // hope to fix one day in https://github.com/beyondessential/central-server/issues/481 actionConfig: { importEndpoint: ENTITIES_ENDPOINT, + accept: { + 'application/geo+json': ['.geojson'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, queryParameters: [ { diff --git a/packages/admin-panel/src/routes/surveys/dataElements.js b/packages/admin-panel/src/routes/surveys/dataElements.js index e474f667bf..aa25ad44b4 100644 --- a/packages/admin-panel/src/routes/surveys/dataElements.js +++ b/packages/admin-panel/src/routes/surveys/dataElements.js @@ -11,6 +11,10 @@ const IMPORT_CONFIG = { title: `Import ${RESOURCE_NAME.singular}`, actionConfig: { importEndpoint: 'dataElements', + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, }; diff --git a/packages/admin-panel/src/routes/surveys/dataMapping.js b/packages/admin-panel/src/routes/surveys/dataMapping.js index 41ba5dd1c3..427900f8f1 100644 --- a/packages/admin-panel/src/routes/surveys/dataMapping.js +++ b/packages/admin-panel/src/routes/surveys/dataMapping.js @@ -62,6 +62,10 @@ const IMPORT_CONFIG = { title: `Import ${RESOURCE_NAME.singular}`, actionConfig: { importEndpoint: 'dataElementDataServices', + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, }; diff --git a/packages/admin-panel/src/routes/surveys/optionSets.js b/packages/admin-panel/src/routes/surveys/optionSets.js index a058490d12..eb0d73d704 100644 --- a/packages/admin-panel/src/routes/surveys/optionSets.js +++ b/packages/admin-panel/src/routes/surveys/optionSets.js @@ -80,6 +80,10 @@ const IMPORT_CONFIG = { title: `Import ${getPluralForm(RESOURCE_NAME)}`, actionConfig: { importEndpoint: 'optionSets', + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, queryParameters: [ { diff --git a/packages/admin-panel/src/routes/surveys/surveyResponses.jsx b/packages/admin-panel/src/routes/surveys/surveyResponses.jsx index 173f190438..dfa85fefc2 100644 --- a/packages/admin-panel/src/routes/surveys/surveyResponses.jsx +++ b/packages/admin-panel/src/routes/surveys/surveyResponses.jsx @@ -182,6 +182,10 @@ const IMPORT_CONFIG = { timeZone: getBrowserTimeZone(), respondWithEmailTimeout: 10 * 1000, // if an import doesn't finish in 10 seconds, email results }, + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, queryParameters: [ { diff --git a/packages/admin-panel/src/routes/surveys/surveys.js b/packages/admin-panel/src/routes/surveys/surveys.js index 159e9b2856..b955e1a293 100644 --- a/packages/admin-panel/src/routes/surveys/surveys.js +++ b/packages/admin-panel/src/routes/surveys/surveys.js @@ -169,6 +169,10 @@ const SURVEY_FIELDS = { name: 'surveyQuestions', labelTooltip: 'Import a questions spreadsheet to update the questions and screens of this survey.', + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, }, }; diff --git a/packages/admin-panel/src/routes/users/permissions.js b/packages/admin-panel/src/routes/users/permissions.js index 159d62339e..580dd46444 100644 --- a/packages/admin-panel/src/routes/users/permissions.js +++ b/packages/admin-panel/src/routes/users/permissions.js @@ -114,6 +114,10 @@ const IMPORT_CONFIG = { title: `Import user ${getPluralForm(RESOURCE_NAME)}`, actionConfig: { importEndpoint: 'userPermissions', + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, }; diff --git a/packages/admin-panel/src/routes/users/users.jsx b/packages/admin-panel/src/routes/users/users.jsx index 71d80d137e..562864c4af 100644 --- a/packages/admin-panel/src/routes/users/users.jsx +++ b/packages/admin-panel/src/routes/users/users.jsx @@ -178,6 +178,10 @@ const IMPORT_CONFIG = { title: `Import ${getPluralForm(RESOURCE_NAME)}`, actionConfig: { importEndpoint: 'users', + accept: { + 'application/vnd.ms-excel': ['.xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + }, }, }; diff --git a/packages/admin-panel/src/routes/visualisations/dashboardItems.jsx b/packages/admin-panel/src/routes/visualisations/dashboardItems.jsx index 1687caf5b1..250f072dc3 100644 --- a/packages/admin-panel/src/routes/visualisations/dashboardItems.jsx +++ b/packages/admin-panel/src/routes/visualisations/dashboardItems.jsx @@ -94,6 +94,9 @@ const IMPORT_CONFIG = { actionConfig: { importEndpoint: 'dashboardVisualisations', multiple: true, + accept: { + 'application/json': ['.json'], + }, }, getFinishedMessage: response => ( <> diff --git a/packages/admin-panel/src/routes/visualisations/dataTables.js b/packages/admin-panel/src/routes/visualisations/dataTables.js index 3f2f8bae6f..6b0374dde6 100644 --- a/packages/admin-panel/src/routes/visualisations/dataTables.js +++ b/packages/admin-panel/src/routes/visualisations/dataTables.js @@ -113,6 +113,9 @@ const IMPORT_CONFIG = { actionConfig: { importEndpoint: 'dataTables', multiple: true, + accept: { + 'application/json': ['.json'], + }, }, }; const EDITOR_CONFIG = { displayUsedBy: true }; diff --git a/packages/admin-panel/src/routes/visualisations/mapOverlays.jsx b/packages/admin-panel/src/routes/visualisations/mapOverlays.jsx index 157cc49575..68de6496fe 100644 --- a/packages/admin-panel/src/routes/visualisations/mapOverlays.jsx +++ b/packages/admin-panel/src/routes/visualisations/mapOverlays.jsx @@ -170,6 +170,9 @@ const IMPORT_CONFIG = { actionConfig: { importEndpoint: 'mapOverlayVisualisations', multiple: true, + accept: { + 'application/json': ['.json'], + }, }, getFinishedMessage: response => ( <> diff --git a/packages/admin-panel/src/widgets/InputField/registerInputFields.jsx b/packages/admin-panel/src/widgets/InputField/registerInputFields.jsx index a35b037847..448342126d 100644 --- a/packages/admin-panel/src/widgets/InputField/registerInputFields.jsx +++ b/packages/admin-panel/src/widgets/InputField/registerInputFields.jsx @@ -381,6 +381,7 @@ export const registerInputFields = () => { props.onSetFormFile(props.inputKey, { fileName, file })} /> From 91fb98da508f1056bddb5327ea954c6c6657e2bd Mon Sep 17 00:00:00 2001 From: Salman <114740396+hrazasalman@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:05:22 +1000 Subject: [PATCH 27/27] fix(adminPanel): RN-1396: Entity import wipes attributes if attributes are not specified in import file (#5829) * attribute updates * slight update * Update Entity.js * exlude blank rows * merge: dev -> rn-1396 (#5896) * deps(security): RN-1096: Update version of `decode-uri-component` (#5850) Update decide-uri-component * deps(security): RN-1096: Update version of `jsonwebtoken` (#5851) * Update json-web-token * Update jsonwebtoken in auth package * deps(security): RN-1096: Update XLSX version (#5849) * Update xlsx * xlsx fixes * Handle xlsx blank rows and parsing * tweak(types): RN-1418: Update EntityType type (#5871) * Update config for entity type * Types update * Fix uses of EntityType * tweak(adminPanel): RN-1393: Minor Admin panel updates (#5867) * Scroll on profile pages * Entity hierarchy export wording * Handle single button action widths * Bold active tabs * Move survey questions to the top of add survey modal * Fix input colours * Fix sync logs tooltip * PR fix * deps(root): RN-1417: Update storybook version (#5878) * Basic setup * Add warmup script * Update main.ts * deps(uiChartComponents): RN-1417: Update storybook version PART 2 (#5879) charts storybook * deps(uiMapComponents): RN-1417: Update storybook version PART 3 (#5880) * map components * Fix tests * deps(uiComponents): RN-1417: Update storybook version PART 4 (#5881) * ui components storybook * Fix tests * deps(tupaiaWeb): RN-1417: Update storybook version PART 5 (#5882) * tupaia web storybook * Fix tests * Fix build * tweak(centralServer): RN-1351: Handle bad DHIS2 sync requests (#5887) Throw an error and register bad requests on dhis sync queue * tweak(datatrakWeb): RN-1438: Upgrade React Query to V4 (#5868) * Bumping react-query * Update render.tsx * fixing Reports.test.tsx * navigation bug fix * removed logging * tweak(adminPanel): RN-1439: Upgrade React Query to V4 (#5875) * bumping to v4 * Update yarn.lock * tweak(psss): RN-1442: Upgrade React Query to V4 (#5874) * upgrade * Update yarn.lock * tweak(lesmis): RN-1441: Upgrade React Query to V4 (#5873) * upgrade * Update yarn.lock * tweak(tupaiaWeb): RN-1440: Upgrade React Query to V4 (#5870) * Bumping react-query * Bumping react-query to v4 * Update render.tsx * GitAction fix * fixing Reports.test.tsx * navigation bug fix * review update * removed logging * Update yarn.lock * Update yarn.lock * Update VerifyEmailPage.tsx * Update useReportPreview.js * fix(adminPanel): Miscellaneous Bug fixes (Tiny) (#5891) * bugfix * update * updates * tweak(tupaiaWeb): RN-1437: Download files visual restyle (#5889) * Common download files component * PR fix --------- Co-authored-by: Salman <114740396+hrazasalman@users.noreply.github.com> * Update extractEntitiesByCountryName.js --------- Co-authored-by: alexd-bes <129009580+alexd-bes@users.noreply.github.com> Co-authored-by: Tom Caiger --- .../importEntities/extractEntitiesByCountryName.js | 3 ++- .../import/importEntities/updateCountryEntities.js | 7 +++++-- packages/database/src/modelClasses/Entity.js | 12 ++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js b/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js index 7fd089ec8e..ee52b535fe 100644 --- a/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js +++ b/packages/central-server/src/apiV2/import/importEntities/extractEntitiesByCountryName.js @@ -55,7 +55,8 @@ const xlsxParser = filePath => { (entitiesByCountry, [countryName, sheet]) => ({ ...entitiesByCountry, [countryName]: xlsx.utils - .sheet_to_json(sheet, { raw: false }) + .sheet_to_json(sheet, { defval: null, raw: false }) + .filter(row => Object.values(row).some(value => value !== null)) .map(row => processXlsxRow(row, { countryName })), }), {}, diff --git a/packages/central-server/src/apiV2/import/importEntities/updateCountryEntities.js b/packages/central-server/src/apiV2/import/importEntities/updateCountryEntities.js index dfc710395f..8074550976 100644 --- a/packages/central-server/src/apiV2/import/importEntities/updateCountryEntities.js +++ b/packages/central-server/src/apiV2/import/importEntities/updateCountryEntities.js @@ -123,7 +123,7 @@ export async function updateCountryEntities( screen_bounds: screenBounds, category_code: categoryCode, facility_type: facilityType, - attributes = {}, + attributes, } = entityObject; if (codes.includes(code)) { throw new ImportValidationError( @@ -175,9 +175,12 @@ export async function updateCountryEntities( country_code: country.code, image_url: imageUrl, metadata: entityMetadata, - attributes, }, ); + + if (attributes !== undefined) { + await transactingModels.entity.updateEntityAttributes(code, attributes); + } if (longitude && latitude) { await transactingModels.entity.updatePointCoordinates(code, { longitude, latitude }); } diff --git a/packages/database/src/modelClasses/Entity.js b/packages/database/src/modelClasses/Entity.js index 747cc7a125..ad95e6037e 100644 --- a/packages/database/src/modelClasses/Entity.js +++ b/packages/database/src/modelClasses/Entity.js @@ -367,6 +367,18 @@ export class EntityModel extends MaterializedViewLogDatabaseModel { ); } + async updateEntityAttributes(code, attributes) { + attributes = attributes ?? {}; + return this.database.executeSql( + ` + UPDATE "entity" + SET "attributes" = ? + WHERE "code" = ?; + `, + [attributes, code], + ); + } + async updateRegionCoordinates(code, geojson) { const shouldSetBounds = (