diff --git a/i18n/en.pot b/i18n/en.pot index 4731601..082359c 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ 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: 2022-07-20T16:52:08.431Z\n" -"PO-Revision-Date: 2022-07-20T16:52:08.431Z\n" +"POT-Creation-Date: 2022-07-29T14:31:45.194Z\n" +"PO-Revision-Date: 2022-07-29T14:31:45.194Z\n" msgid "Search within results" msgstr "Search within results" @@ -77,6 +77,25 @@ msgstr "SQL Views" msgid "Search for a SQL view" msgstr "Search for a SQL view" +msgid "Attribute has been created. App will reload shortly." +msgstr "Attribute has been created. App will reload shortly." + +msgid "Attribute could not be created." +msgstr "Attribute could not be created." + +msgid "" +"Do you want to create an attribute that allows saving default variable " +"values?" +msgstr "" +"Do you want to create an attribute that allows saving default variable " +"values?" + +msgid "Cancel" +msgstr "Cancel" + +msgid "Create" +msgstr "Create" + msgid "Download CSV" msgstr "Download CSV" diff --git a/src/components/Data/ViewData.js b/src/components/Data/ViewData.js index 67b3cb1..80ec210 100644 --- a/src/components/Data/ViewData.js +++ b/src/components/Data/ViewData.js @@ -13,8 +13,8 @@ import { } from '../../services/extractVariables' import { useQuery } from '../../services/useQuery' import { useDataStoreConfig } from '../ConfigProvider' -import { useUserInfo } from '../UserInfoProvider' import Layout from '../Layout' +import { useUserInfo } from '../UserInfoProvider' import DataWrapper from './DataWrapper' import ErrorMessage from './ErrorMessage' import LinksMenu from './LinksMenu' @@ -82,7 +82,7 @@ const BackButton = () => ( const ViewData = ({ match }) => { const { baseUrl } = useConfig() const { config, configWaiting } = useDataStoreConfig() - const { userInfo, userWaiting } = useUserInfo() + const { userInfo } = useUserInfo() const query = useQuery() const engine = useDataEngine() const id = match.params.id @@ -212,17 +212,17 @@ const ViewData = ({ match }) => { const filteredAttributeValues = data.sqlView.attributeValues.filter( av => av.attribute.id !== config?.defaultsAttributeId ) - let newVariables = { + const newVariables = { attribute: { id: config?.defaultsAttributeId }, value: JSON.stringify(variables), } - let newSQLView = { ...data.sqlView } + const newSQLView = { ...data.sqlView } newSQLView.attributeValues = [ ...filteredAttributeValues, newVariables, ] - let response = await engine.mutate(sqlUpdate, { + const response = await engine.mutate(sqlUpdate, { variables: { id: data.sqlView.id, data: newSQLView }, }) if ( diff --git a/src/components/Main.js b/src/components/Main.js index 158bc85..9af5e41 100644 --- a/src/components/Main.js +++ b/src/components/Main.js @@ -1,10 +1,10 @@ import React from 'react' import { HashRouter as Router, Switch, Route } from 'react-router-dom' import ConfigProvider from './ConfigProvider' -import UserInfoProvider from './UserInfoProvider' import ViewData from './Data/ViewData' import Layout from './Layout' import SelectQuery from './Selection/SelectQuery' +import UserInfoProvider from './UserInfoProvider' import '../locales' const Main = () => { diff --git a/src/components/Selection/SelectQuery.js b/src/components/Selection/SelectQuery.js index 62b8d30..a36e408 100644 --- a/src/components/Selection/SelectQuery.js +++ b/src/components/Selection/SelectQuery.js @@ -1,11 +1,14 @@ import { DataQuery } from '@dhis2/app-runtime' import i18n from '@dhis2/d2-i18n' -import { Button, CircularLoader, IconMore24 } from '@dhis2/ui' +import { Button, CircularLoader, IconMore24, IconSettings24 } from '@dhis2/ui' import PropTypes from 'prop-types' import React, { createRef, useState } from 'react' import { Link } from 'react-router-dom' +import { useDataStoreConfig } from '../ConfigProvider' import LinksMenu from '../Data/LinksMenu' import CustomTable from '../Table/CustomTable' +import { useUserInfo } from '../UserInfoProvider' +import SettingsModal from './SettingsModal' const sqlViewsQuery = { sql: { @@ -61,12 +64,37 @@ const SelectQuery = () => { { name: 'uid', hidden: true }, ] + const { userInfo } = useUserInfo() + const { config } = useDataStoreConfig() + const [settingsModalOpen, setSettingsModalOpen] = useState(false) + return ( {({ loading, error, data }) => ( <>
-

{i18n.t('SQL Views')}

+ {settingsModalOpen && ( + + )} + +
+

{i18n.t('SQL Views')}

+ {userInfo?.superuser && + !config?.defaultsAttributeId && ( +
+
+ )} +
{loading && } {error && {`Error: ${error.message}`}} {data && ( @@ -119,6 +147,13 @@ const SelectQuery = () => { margin: var(--spacers-dp24) 0 var(--spacers-dp12); line-height: 20px; } + .headerContainer { + display: flex; + align-items: center; + } + .rightButton { + margin-left: auto; + } `} )} diff --git a/src/components/Selection/SettingsModal.js b/src/components/Selection/SettingsModal.js new file mode 100644 index 0000000..0eb9b39 --- /dev/null +++ b/src/components/Selection/SettingsModal.js @@ -0,0 +1,106 @@ +import { useAlert, useDataEngine } from '@dhis2/app-runtime' +import i18n from '@dhis2/d2-i18n' +import { + Button, + ButtonStrip, + Modal, + ModalActions, + ModalContent, +} from '@dhis2/ui' +import PropTypes from 'prop-types' +import React from 'react' + +const DEFAULT_ATTIBUTE_NAME = 'default-sql-values' + +const attributeCreate = { + resource: 'attributes', + type: 'create', + data: ({ data }) => data, +} + +const dataStoreCreate = { + resource: 'dataStore/sqlViewer/config', + type: 'create', + data: ({ data }) => data, +} + +const SettingsModal = ({ setSettingsModalOpen }) => { + const engine = useDataEngine() + const { show: showAlert } = useAlert( + ({ msg }) => msg, + ({ options }) => ({ ...options, duration: 3000 }) + ) + + const createAttribute = async () => { + try { + // post to create attribute + const defaultsAttribute = { + name: DEFAULT_ATTIBUTE_NAME, + valueType: 'LONG_TEXT', + sqlViewAttribute: true, + } + const attributeResponse = await engine.mutate(attributeCreate, { + variables: { data: defaultsAttribute }, + }) + + // if successful, post to create datastore (note: assumes datastore does not exist) + const datastoreContent = { + defaultsAttributeId: attributeResponse?.response?.uid, + } + await engine.mutate(dataStoreCreate, { + variables: { data: datastoreContent }, + }) + + showAlert({ + msg: i18n.t('Attribute has been created. App will reload shortly.'), + options: { success: true }, + }) + + // here the context should be created, but reloading page is a simpler approach + setTimeout(() => { + location.reload() + }, 3000) + } catch (e) { + showAlert({ + msg: i18n.t('Attribute could not be created.'), + options: { warning: true }, + }) + } + setSettingsModalOpen(false) + } + + return ( + { + setSettingsModalOpen(false) + }} + position="middle" + > + + {i18n.t( + 'Do you want to create an attribute that allows saving default variable values?' + )} + + + + + + + + + ) +} + +SettingsModal.propTypes = { + setSettingsModalOpen: PropTypes.func, +} + +export default SettingsModal