Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: create embedded superset dashboard #3185

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ cypress.env.json
cypress/screenshots
cypress/videos
cypress/downloads
.aider*
74 changes: 67 additions & 7 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,50 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2024-12-19T11:30:27.893Z\n"
"PO-Revision-Date: 2024-12-19T11:30:27.893Z\n"
"POT-Creation-Date: 2025-01-16T15:24:12.682Z\n"
"PO-Revision-Date: 2025-01-16T15:24:12.682Z\n"

msgid "Untitled dashboard"
msgstr "Untitled dashboard"

msgid "Dashboards"
msgstr "Dashboards"
msgid "New dashboard: choose type"
msgstr "New dashboard: choose type"

msgid "Internal: Data from {{systemName}}"
msgstr "Internal: Data from {{systemName}}"

msgid "Show data and visualizations from this DHIS2 instance."
msgstr "Show data and visualizations from this DHIS2 instance."

msgid "External: Data from another source"
msgstr "External: Data from another source"

msgid "Embed a dashboard from a third-party source, like Superset."
msgstr "Embed a dashboard from a third-party source, like Superset."

msgid "Create dashboard"
msgstr "Create dashboard"

msgid "Configure source"
msgstr "Configure source"

msgid "Cancel"
msgstr "Cancel"

msgid "New dashboard: configure external source (superset)"
msgstr "New dashboard: configure external source (superset)"

msgid "Could not create dashboard"
msgstr "Could not create dashboard"

msgid "An unknown error occurred"
msgstr "An unknown error occurred"

msgid "Back"
msgstr "Back"

msgid "Save dashboard"
msgstr "Save dashboard"

msgid "The dashboard couldn't be made available offline. Try again."
msgstr "The dashboard couldn't be made available offline. Try again."
Expand Down Expand Up @@ -81,9 +117,6 @@ msgstr "No, cancel"
msgid "Yes, clear filters and sync"
msgstr "Yes, clear filters and sync"

msgid "Cancel"
msgstr "Cancel"

msgid "Confirm"
msgstr "Confirm"

Expand Down Expand Up @@ -120,6 +153,9 @@ msgstr "Search for a dashboard"
msgid "No dashboards found"
msgstr "No dashboards found"

msgid "Dashboards"
msgstr "Dashboards"

msgid "{{appKey}} app not found"
msgstr "{{appKey}} app not found"

Expand Down Expand Up @@ -255,6 +291,30 @@ msgstr "Resources"
msgid "Reports"
msgstr "Reports"

msgid "Title"
msgstr "Title"

msgid "Code"
msgstr "Code"

msgid "Description"
msgstr "Description"

msgid "Superset Embed ID"
msgstr "Superset Embed ID"

msgid "Invalid UUID"
msgstr "Invalid UUID"

msgid "Options"
msgstr "Options"

msgid "Show chart controls on dashboard items"
msgstr "Show chart controls on dashboard items"

msgid "Show filters"
msgstr "Show filters"

msgid "Visualizations"
msgstr "Visualizations"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { useConfig } from '@dhis2/app-runtime'
import i18n from '@dhis2/d2-i18n'
import {
Button,
Modal,
ModalActions,
ModalContent,
ModalTitle,
} from '@dhis2/ui'
import PropTypes from 'prop-types'
import React, { useCallback, useState } from 'react'
import { DashboardTypeRadio } from './DashboardTypeRadio.js'
import { IconDashboardExternal } from './IconDashboardExternal.js'
import { IconDashboardInternal } from './IconDashboardInternal.js'
import styles from './styles/ChooseDashboardTypeModal.module.css'

const TYPE_INTERNAL = 'INTERNAL'
const TYPE_SUPERSET = 'SUPERSET'

const autoFocus = (element) => {
element?.focus()
}

export const ChooseDashboardTypeModal = ({
onCancel,
onSelectSuperset,
onSelectInternal,
}) => {
const {
systemInfo: { systemName },
} = useConfig()
const [selectedType, setSelectedType] = useState(TYPE_INTERNAL)
const handleDashboardTypeChange = useCallback((event) => {
setSelectedType(event.target.value)
}, [])
const isInternal = selectedType === TYPE_INTERNAL

return (
<Modal>
<form onSubmit={isInternal ? onSelectInternal : onSelectSuperset}>
<ModalTitle>
{i18n.t('New dashboard: choose type', {
nsSeparator: '###',
})}
</ModalTitle>
<ModalContent>
<fieldset
ref={autoFocus}
className={styles.dashboardTypeRadioGroup}
tabIndex={0}
HendrikThePendric marked this conversation as resolved.
Show resolved Hide resolved
>
<DashboardTypeRadio
type={TYPE_INTERNAL}
selectedType={selectedType}
onChange={handleDashboardTypeChange}
icon={<IconDashboardInternal />}
title={i18n.t(
'Internal: Data from {{systemName}}',
{
systemName,
nsSeparator: '###',
}
)}
subtitle={i18n.t(
'Show data and visualizations from this DHIS2 instance.'
)}
/>
<DashboardTypeRadio
type={TYPE_SUPERSET}
selectedType={selectedType}
onChange={handleDashboardTypeChange}
icon={<IconDashboardExternal />}
title={i18n.t(
'External: Data from another source',
{
nsSeparator: '###',
}
)}
subtitle={i18n.t(
'Embed a dashboard from a third-party source, like Superset.'
)}
/>
</fieldset>
</ModalContent>
<ModalActions>
<div className={styles.buttonStrip}>
<Button primary type="submit">
{isInternal
? i18n.t('Create dashboard')
: i18n.t('Configure source')}
</Button>
<Button secondary onClick={onCancel}>
{i18n.t('Cancel')}
</Button>
</div>
</ModalActions>
</form>
</Modal>
)
}

ChooseDashboardTypeModal.propTypes = {
onCancel: PropTypes.func,
onSelectInternal: PropTypes.func,
onSelectSuperset: PropTypes.func,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Button, IconAdd16 } from '@dhis2/ui'
import React, { useCallback, useState } from 'react'
import { useHistory } from 'react-router-dom'
import { useHasSupersetSupport } from '../../SystemSettingsProvider.js'
import { ChooseDashboardTypeModal } from './ChooseDashboardTypeModal.js'
import { CreateSupersetEmbeddedDashboard } from './CreateSupersetEmbeddedDashboard.js'
import styles from './styles/CreateDashboardButton.module.css'

export const CreateDashboardButton = () => {
const history = useHistory()
const hasSupersetSupport = useHasSupersetSupport()
const [isChooseDashboardTypeModalOpen, setIsChooseDashboardTypeModalOpen] =
useState(false)
const [isCreateSupersetDashboardOpen, setIsCreateSupersetDashboardOpen] =
useState(false)
const navigateToNewInternalDashboardView = useCallback(() => {
history.push('/new')
}, [history])
const handleCreateButtonClick = useCallback(() => {
if (hasSupersetSupport) {
setIsChooseDashboardTypeModalOpen(true)
} else {
navigateToNewInternalDashboardView()
}
}, [hasSupersetSupport, navigateToNewInternalDashboardView])

return (
<>
<Button
onClick={handleCreateButtonClick}
secondary
small
icon={<IconAdd16 />}
className={styles.createDashboardButton}
dataTest="new-button"
/>
{isChooseDashboardTypeModalOpen && (
<ChooseDashboardTypeModal
onCancel={() => {
setIsChooseDashboardTypeModalOpen(false)
}}
onSelectSuperset={() => {
setIsChooseDashboardTypeModalOpen(false)
setIsCreateSupersetDashboardOpen(true)
}}
onSelectInternal={() => {
setIsChooseDashboardTypeModalOpen(false)
navigateToNewInternalDashboardView()
}}
/>
)}
{isCreateSupersetDashboardOpen && (
<CreateSupersetEmbeddedDashboard
backToChooseDashboardModal={() => {
setIsCreateSupersetDashboardOpen(false)
setIsChooseDashboardTypeModalOpen(true)
}}
closeModal={() => {
setIsCreateSupersetDashboardOpen(false)
}}
/>
)}
</>
)
}
Loading
Loading