diff --git a/package.json b/package.json index af6e459..6b7c554 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "@auth0/auth0-react": "1.10.2", "@emotion/react": "11.7.1", "@emotion/styled": "11.6.0", - "@kingsrook/qqq-frontend-core": "1.0.105", + "@kingsrook/qqq-frontend-core": "1.0.110", "@mui/icons-material": "5.4.1", "@mui/material": "5.11.1", "@mui/styles": "5.11.1", diff --git a/src/qqq/components/buttons/DefaultButtons.tsx b/src/qqq/components/buttons/DefaultButtons.tsx index 23a65cc..c277617 100644 --- a/src/qqq/components/buttons/DefaultButtons.tsx +++ b/src/qqq/components/buttons/DefaultButtons.tsx @@ -30,14 +30,17 @@ import MDButton from "qqq/components/legacy/MDButton"; export const standardWidth = "150px"; +const standardML = {xs: 1, md: 3}; + interface QCreateNewButtonProps { tablePath: string; } + export function QCreateNewButton({tablePath}: QCreateNewButtonProps): JSX.Element { return ( - + add}> Create New @@ -54,6 +57,7 @@ interface QSaveButtonProps onClickHandler?: any, disabled: boolean } + QSaveButton.defaultProps = { label: "Save", iconName: "save" @@ -62,7 +66,7 @@ QSaveButton.defaultProps = { export function QSaveButton({label, iconName, onClickHandler, disabled}: QSaveButtonProps): JSX.Element { return ( - + {iconName}} disabled={disabled}> {label} @@ -72,17 +76,18 @@ export function QSaveButton({label, iconName, onClickHandler, disabled}: QSaveBu interface QDeleteButtonProps { - onClickHandler: any - disabled?: boolean + onClickHandler: any; + disabled?: boolean; } QDeleteButton.defaultProps = { disabled: false }; + export function QDeleteButton({onClickHandler, disabled}: QDeleteButtonProps): JSX.Element { return ( - + delete} disabled={disabled}> Delete @@ -93,7 +98,7 @@ export function QDeleteButton({onClickHandler, disabled}: QDeleteButtonProps): J export function QEditButton(): JSX.Element { return ( - + edit}> Edit @@ -132,7 +137,7 @@ interface QCancelButtonProps onClickHandler: any; disabled: boolean; label?: string; - iconName?: string + iconName?: string; } export function QCancelButton({ @@ -140,7 +145,7 @@ export function QCancelButton({ }: QCancelButtonProps): JSX.Element { return ( - + {iconName}} onClick={onClickHandler} disabled={disabled}> {label} @@ -155,15 +160,15 @@ QCancelButton.defaultProps = { interface QSubmitButtonProps { - label?: string - iconName?: string - disabled: boolean + label?: string; + iconName?: string; + disabled: boolean; } export function QSubmitButton({label, iconName, disabled}: QSubmitButtonProps): JSX.Element { return ( - + {iconName}} disabled={disabled}> {label} diff --git a/src/qqq/components/forms/DynamicForm.tsx b/src/qqq/components/forms/DynamicForm.tsx index 0823648..8c59440 100644 --- a/src/qqq/components/forms/DynamicForm.tsx +++ b/src/qqq/components/forms/DynamicForm.tsx @@ -172,14 +172,10 @@ function QDynamicForm({formData, formLabel, bulkEditMode, bulkEditSwitchChangeHa {labelElement} $; } if (displayFormat && displayFormat.endsWith("%%")) { - // @ts-ignore inputProps.endAdornment = %; } + if (placeholder) + { + inputProps.placeholder = placeholder + } + + if(backgroundColor) + { + inputProps.sx = { + "&.MuiInputBase-root": { + backgroundColor: backgroundColor + } + }; + } + // @ts-ignore const handleOnWheel = (e) => { diff --git a/src/qqq/components/forms/DynamicFormUtils.ts b/src/qqq/components/forms/DynamicFormUtils.ts index 067fdde..e94e4b6 100644 --- a/src/qqq/components/forms/DynamicFormUtils.ts +++ b/src/qqq/components/forms/DynamicFormUtils.ts @@ -22,6 +22,7 @@ import {AdornmentType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/AdornmentType"; import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData"; import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType"; +import {FieldPossibleValueProps} from "qqq/models/fields/FieldPossibleValueProps"; import * as Yup from "yup"; @@ -129,18 +130,11 @@ class DynamicFormUtils if (effectivelyIsRequired) { - if (field.possibleValueSourceName) - { - //////////////////////////////////////////////////////////////////////////////////////////// - // the "nullable(true)" here doesn't mean that you're allowed to set the field to null... // - // rather, it's more like "null is how empty will be treated" or some-such... // - //////////////////////////////////////////////////////////////////////////////////////////// - return (Yup.string().required(`${field.label} is required.`).nullable(true)); - } - else - { - return (Yup.string().required(`${field.label} is required.`)); - } + //////////////////////////////////////////////////////////////////////////////////////////// + // the "nullable(true)" here doesn't mean that you're allowed to set the field to null... // + // rather, it's more like "null is how empty will be treated" or some-such... // + //////////////////////////////////////////////////////////////////////////////////////////// + return (Yup.string().required(`${field.label ?? "This field"} is required.`).nullable(true)); } return (null); } @@ -155,47 +149,49 @@ class DynamicFormUtils { const field = qFields[i]; + if(!dynamicFormFields[field.name]) + { + continue; + } + ///////////////////////////////////////// // add props for possible value fields // ///////////////////////////////////////// - if (field.possibleValueSourceName && dynamicFormFields[field.name]) + if (field.possibleValueSourceName || field.inlinePossibleValueSource) { - let initialDisplayValue = null; + let props: FieldPossibleValueProps = + { + isPossibleValue: true, + fieldName: field.name, + initialDisplayValue: null + } + if (displayValues) { - initialDisplayValue = displayValues.get(field.name); + props.initialDisplayValue = displayValues.get(field.name); } - if (tableName) + if(field.inlinePossibleValueSource) { - dynamicFormFields[field.name].possibleValueProps = - { - isPossibleValue: true, - tableName: tableName, - fieldName: field.name, - initialDisplayValue: initialDisplayValue, - }; + ////////////////////////////////////////////////////////////////////// + // handle an inline PVS - which is a list of possible value objects // + ////////////////////////////////////////////////////////////////////// + props.possibleValues = field.inlinePossibleValueSource; + } + else if (tableName) + { + props.tableName = tableName; } else if (processName) { - dynamicFormFields[field.name].possibleValueProps = - { - isPossibleValue: true, - processName: processName, - fieldName: field.name, - initialDisplayValue: initialDisplayValue, - }; + props.processName = processName; } else { - dynamicFormFields[field.name].possibleValueProps = - { - isPossibleValue: true, - initialDisplayValue: initialDisplayValue, - fieldName: field.name, - possibleValueSourceName: field.possibleValueSourceName - }; + props.possibleValueSourceName = field.possibleValueSourceName; } + + dynamicFormFields[field.name].possibleValueProps = props; } } } diff --git a/src/qqq/components/forms/DynamicSelect.tsx b/src/qqq/components/forms/DynamicSelect.tsx index ca1e596..70658fe 100644 --- a/src/qqq/components/forms/DynamicSelect.tsx +++ b/src/qqq/components/forms/DynamicSelect.tsx @@ -30,20 +30,17 @@ import TextField from "@mui/material/TextField"; import {ErrorMessage, useFormikContext} from "formik"; import colors from "qqq/assets/theme/base/colors"; import MDTypography from "qqq/components/legacy/MDTypography"; +import {FieldPossibleValueProps} from "qqq/models/fields/FieldPossibleValueProps"; import Client from "qqq/utils/qqq/Client"; import React, {useEffect, useState} from "react"; interface Props { - tableName?: string; - processName?: string; - fieldName?: string; - possibleValueSourceName?: string; + fieldPossibleValueProps: FieldPossibleValueProps; overrideId?: string; fieldLabel: string; inForm: boolean; initialValue?: any; - initialDisplayValue?: string; initialValues?: QPossibleValue[]; onChange?: any; isEditable?: boolean; @@ -57,13 +54,8 @@ interface Props } DynamicSelect.defaultProps = { - tableName: null, - processName: null, - fieldName: null, - possibleValueSourceName: null, inForm: true, initialValue: null, - initialDisplayValue: null, initialValues: undefined, onChange: null, isEditable: true, @@ -103,8 +95,10 @@ export const getAutocompleteOutlinedStyle = (isDisabled: boolean) => const qController = Client.getInstance(); -function DynamicSelect({tableName, processName, fieldName, possibleValueSourceName, overrideId, fieldLabel, inForm, initialValue, initialDisplayValue, initialValues, onChange, isEditable, isMultiple, bulkEditMode, bulkEditSwitchChangeHandler, otherValues, variant, initiallyOpen, useCase}: Props) +function DynamicSelect({fieldPossibleValueProps, overrideId, fieldLabel, inForm, initialValue, initialValues, onChange, isEditable, isMultiple, bulkEditMode, bulkEditSwitchChangeHandler, otherValues, variant, initiallyOpen, useCase}: Props) { + const {fieldName, initialDisplayValue, possibleValueSourceName, possibleValues, processName, tableName} = fieldPossibleValueProps; + const [open, setOpen] = useState(initiallyOpen); const [options, setOptions] = useState([]); const [searchTerm, setSearchTerm] = useState(null); @@ -172,6 +166,35 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa setFieldValueRef = setFieldValue; } + + /******************************************************************************* + ** + *******************************************************************************/ + const filterInlinePossibleValues = (searchTerm: string, possibleValues: QPossibleValue[]): QPossibleValue[] => + { + return possibleValues.filter(pv => pv.label?.toLowerCase().startsWith(searchTerm)); + } + + + /*************************************************************************** + ** + ***************************************************************************/ + const loadResults = async (): Promise => + { + if(possibleValues) + { + return filterInlinePossibleValues(searchTerm, possibleValues) + } + else + { + return await qController.possibleValues(tableName, processName, possibleValueSourceName ?? fieldName, searchTerm ?? "", null, otherValues, useCase); + } + } + + + /*************************************************************************** + ** + ***************************************************************************/ useEffect(() => { if (firstRender) @@ -195,7 +218,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa (async () => { // console.log(`doing a search with ${searchTerm}`); - const results: QPossibleValue[] = await qController.possibleValues(tableName, processName, possibleValueSourceName ?? fieldName, searchTerm ?? "", null, otherValues, useCase); + const results: QPossibleValue[] = await loadResults(); if (tableMetaData == null && tableName) { @@ -218,7 +241,10 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa }; }, [searchTerm]); - // todo - finish... call it in onOpen? + + /*************************************************************************** + ** todo - finish... call it in onOpen? + ***************************************************************************/ const reloadIfOtherValuesAreChanged = () => { if (JSON.stringify(Object.fromEntries(otherValues)) != otherValuesWhenResultsWereLoaded) @@ -227,8 +253,10 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa { setLoading(true); setOptions([]); + console.log("Refreshing possible values..."); - const results: QPossibleValue[] = await qController.possibleValues(tableName, processName, possibleValueSourceName ?? fieldName, searchTerm ?? "", null, otherValues, useCase); + const results: QPossibleValue[] = await loadResults(); + setLoading(false); setOptions([...results]); setOtherValuesWhenResultsWereLoaded(JSON.stringify(Object.fromEntries(otherValues))); @@ -236,6 +264,10 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa } }; + + /*************************************************************************** + ** + ***************************************************************************/ const inputChanged = (event: React.SyntheticEvent, value: string, reason: string) => { // console.log(`input changed. Reason: ${reason}, setting search term to ${value}`); @@ -246,11 +278,19 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa } }; + + /*************************************************************************** + ** + ***************************************************************************/ const handleBlur = (x: any) => { setSearchTerm(null); }; + + /*************************************************************************** + ** + ***************************************************************************/ const handleChanged = (event: React.SyntheticEvent, value: any | any[], reason: string, details?: string) => { // console.log("handleChanged. value is:"); @@ -274,6 +314,10 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa } }; + + /*************************************************************************** + ** + ***************************************************************************/ const filterOptions = (options: { id: any; label: string; }[], state: FilterOptionsState<{ id: any; label: string; }>): { id: any; label: string; }[] => { ///////////////////////////////////////////////////////////////////////////////// @@ -283,6 +327,10 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa return (options); }; + + /*************************************************************************** + ** + ***************************************************************************/ // @ts-ignore const renderOption = (props: Object, option: any, {selected}) => { @@ -331,6 +379,10 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa ); }; + + /*************************************************************************** + ** + ***************************************************************************/ const bulkEditSwitchChanged = () => { const newSwitchValue = !switchChecked; @@ -351,7 +403,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa const autocomplete = ( - {!isDisabled &&
{msg}} />
} + {!isDisabled &&
{msg}} />
}
} diff --git a/src/qqq/components/horseshoe/Footer.tsx b/src/qqq/components/horseshoe/Footer.tsx index 3345809..fdc183f 100644 --- a/src/qqq/components/horseshoe/Footer.tsx +++ b/src/qqq/components/horseshoe/Footer.tsx @@ -64,13 +64,14 @@ function Footer({company, links}: Props): JSX.Element { href && name && diff --git a/src/qqq/components/processes/ProcessSummaryResults.tsx b/src/qqq/components/processes/ProcessSummaryResults.tsx index 67bd586..01a451b 100644 --- a/src/qqq/components/processes/ProcessSummaryResults.tsx +++ b/src/qqq/components/processes/ProcessSummaryResults.tsx @@ -84,7 +84,7 @@ function ProcessSummaryResults({ ); return ( - + diff --git a/src/qqq/components/processes/ValidationReview.tsx b/src/qqq/components/processes/ValidationReview.tsx index 361d333..80767e4 100644 --- a/src/qqq/components/processes/ValidationReview.tsx +++ b/src/qqq/components/processes/ValidationReview.tsx @@ -273,7 +273,7 @@ function ValidationReview({ ); return ( - + diff --git a/src/qqq/components/query/FilterCriteriaRowValues.tsx b/src/qqq/components/query/FilterCriteriaRowValues.tsx index 793497a..0e4fa18 100644 --- a/src/qqq/components/query/FilterCriteriaRowValues.tsx +++ b/src/qqq/components/query/FilterCriteriaRowValues.tsx @@ -367,13 +367,11 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC ) : ( valueChangeHandler(null, 0, value)} variant="standard" @@ -402,8 +400,7 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC } return - + - + diff --git a/src/qqq/components/sharing/ShareModal.tsx b/src/qqq/components/sharing/ShareModal.tsx index 1a83082..2c7e73f 100644 --- a/src/qqq/components/sharing/ShareModal.tsx +++ b/src/qqq/components/sharing/ShareModal.tsx @@ -391,10 +391,9 @@ export default function ShareModal({open, onClose, tableMetaData, record}: Share boolean; + values?: { [key: string]: any }; } /******************************************************************************* ** Widget which is a list of Blocks. *******************************************************************************/ -export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetProps): JSX.Element +export default function CompositeWidget({widgetMetaData, data, actionCallback, values}: CompositeWidgetProps): JSX.Element { if (!data || !data.blocks) { @@ -74,6 +82,12 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP boxStyle.flexWrap = "wrap"; boxStyle.gap = "0.5rem"; } + else if (layout == "FLEX_ROW") + { + boxStyle.display = "flex"; + boxStyle.flexDirection = "row"; + boxStyle.gap = "0.5rem"; + } else if (layout == "FLEX_ROW_SPACE_BETWEEN") { boxStyle.display = "flex"; @@ -81,6 +95,14 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP boxStyle.justifyContent = "space-between"; boxStyle.gap = "0.25rem"; } + else if (layout == "FLEX_ROW_CENTER") + { + boxStyle.display = "flex"; + boxStyle.flexDirection = "row"; + boxStyle.justifyContent = "center"; + boxStyle.gap = "0.25rem"; + boxStyle.flexWrap = "wrap"; + } else if (layout == "TABLE_SUB_ROW_DETAILS") { boxStyle.display = "flex"; @@ -105,6 +127,19 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP boxStyle = {...boxStyle, ...data.styleOverrides}; } + if (data.styles?.backgroundColor) + { + boxStyle.backgroundColor = ProcessWidgetBlockUtils.processColorFromStyleMap(data.styles.backgroundColor); + } + + if (data.styles?.padding) + { + boxStyle.paddingTop = data.styles?.padding.top + "px" + boxStyle.paddingBottom = data.styles?.padding.bottom + "px" + boxStyle.paddingLeft = data.styles?.padding.left + "px" + boxStyle.paddingRight = data.styles?.padding.right + "px" + } + let overlayStyle: any = {}; if (data?.overlayStyleOverrides) @@ -112,7 +147,7 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP overlayStyle = {...overlayStyle, ...data.overlayStyleOverrides}; } - return ( + const content = ( <> { data?.overlayHtml && @@ -122,7 +157,7 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP { data.blocks.map((block: BlockData, index) => ( - + )) } @@ -130,4 +165,53 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP ); + if (data.modalMode) + { + const [isModalOpen, setIsModalOpen] = useState(values && (values[data.blockId] == true)); + + /*************************************************************************** + ** + ***************************************************************************/ + const controlCallback = (newValue: boolean) => + { + setIsModalOpen(newValue); + }; + + /*************************************************************************** + ** + ***************************************************************************/ + const modalOnClose = (event: object, reason: string) => + { + values[data.blockId] = false; + setIsModalOpen(false); + actionCallback({blockTypeName: "BUTTON", values: {}}, {controlCode: `hideModal:${data.blockId}`}); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // register the control-callback function - so when buttons are clicked, we can be told // + ////////////////////////////////////////////////////////////////////////////////////////// + useEffect(() => + { + if (actionCallback) + { + actionCallback(null, { + registerControlCallbackName: data.blockId, + registerControlCallbackFunction: controlCallback + }); + } + }, []); + + return ( + + + {content} + + + ); + } + else + { + return content; + } + } diff --git a/src/qqq/components/widgets/DashboardWidgets.tsx b/src/qqq/components/widgets/DashboardWidgets.tsx index 38fe772..a77e21e 100644 --- a/src/qqq/components/widgets/DashboardWidgets.tsx +++ b/src/qqq/components/widgets/DashboardWidgets.tsx @@ -29,6 +29,7 @@ import parse from "html-react-parser"; import QContext from "QContext"; import MDTypography from "qqq/components/legacy/MDTypography"; import TabPanel from "qqq/components/misc/TabPanel"; +import {BlockData} from "qqq/components/widgets/blocks/BlockModels"; import BarChart from "qqq/components/widgets/charts/barchart/BarChart"; import HorizontalBarChart from "qqq/components/widgets/charts/barchart/HorizontalBarChart"; import DefaultLineChart from "qqq/components/widgets/charts/linechart/DefaultLineChart"; @@ -71,6 +72,9 @@ interface Props childUrlParams?: string; parentWidgetMetaData?: QWidgetMetaData; wrapWidgetsInTabPanels: boolean; + actionCallback?: (blockData: BlockData) => boolean; + initialWidgetDataList: any[]; + values?: {[key: string]: any}; } DashboardWidgets.defaultProps = { @@ -82,11 +86,14 @@ DashboardWidgets.defaultProps = { childUrlParams: "", parentWidgetMetaData: null, wrapWidgetsInTabPanels: false, + actionCallback: null, + initialWidgetDataList: null, + values: {} }; -function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, record, omitWrappingGridContainer, areChildren, childUrlParams, parentWidgetMetaData, wrapWidgetsInTabPanels}: Props): JSX.Element +function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, record, omitWrappingGridContainer, areChildren, childUrlParams, parentWidgetMetaData, wrapWidgetsInTabPanels, actionCallback, initialWidgetDataList, values}: Props): JSX.Element { - const [widgetData, setWidgetData] = useState([] as any[]); + const [widgetData, setWidgetData] = useState(initialWidgetDataList == null ? [] as any[] : initialWidgetDataList); const [widgetCounter, setWidgetCounter] = useState(0); const [, forceUpdate] = useReducer((x) => x + 1, 0); @@ -114,7 +121,15 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco useEffect(() => { + if(initialWidgetDataList && initialWidgetDataList.length > 0) + { + // todo actually, should this check each element of the array, down in the loop? yeah, when we need to, do it that way. + console.log("We already have initial widget data, so not fetching from backend."); + return + } + setWidgetData([]); + for (let i = 0; i < widgetMetaDataList.length; i++) { const widgetMetaData = widgetMetaDataList[i]; @@ -563,7 +578,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco labelAdditionalComponentsRight={labelAdditionalComponentsRight} labelAdditionalComponentsLeft={labelAdditionalComponentsLeft} > - + ) } diff --git a/src/qqq/components/widgets/WidgetBlock.tsx b/src/qqq/components/widgets/WidgetBlock.tsx index fab8f6d..448bb2f 100644 --- a/src/qqq/components/widgets/WidgetBlock.tsx +++ b/src/qqq/components/widgets/WidgetBlock.tsx @@ -22,6 +22,9 @@ import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData"; import {Alert, Skeleton} from "@mui/material"; +import ButtonBlock from "qqq/components/widgets/blocks/ButtonBlock"; +import AudioBlock from "qqq/components/widgets/blocks/AudioBlock"; +import InputFieldBlock from "qqq/components/widgets/blocks/InputFieldBlock"; import React from "react"; import BigNumberBlock from "qqq/components/widgets/blocks/BigNumberBlock"; import {BlockData} from "qqq/components/widgets/blocks/BlockModels"; @@ -32,19 +35,22 @@ import TableSubRowDetailRowBlock from "qqq/components/widgets/blocks/TableSubRow import TextBlock from "qqq/components/widgets/blocks/TextBlock"; import UpOrDownNumberBlock from "qqq/components/widgets/blocks/UpOrDownNumberBlock"; import CompositeWidget from "qqq/components/widgets/CompositeWidget"; +import ImageBlock from "./blocks/ImageBlock"; interface WidgetBlockProps { widgetMetaData: QWidgetMetaData; block: BlockData; + actionCallback?: (blockData: BlockData, eventValues?: {[name: string]: any}) => boolean; + values?: { [key: string]: any }; } /******************************************************************************* ** Component to render a single Block in the widget framework! *******************************************************************************/ -export default function WidgetBlock({widgetMetaData, block}: WidgetBlockProps): JSX.Element +export default function WidgetBlock({widgetMetaData, block, actionCallback, values}: WidgetBlockProps): JSX.Element { if(!block) { @@ -64,7 +70,7 @@ export default function WidgetBlock({widgetMetaData, block}: WidgetBlockProps): if(block.blockTypeName == "COMPOSITE") { // @ts-ignore - special case for composite type block... - return (); + return (); } switch(block.blockTypeName) @@ -83,6 +89,14 @@ export default function WidgetBlock({widgetMetaData, block}: WidgetBlockProps): return (); case "BIG_NUMBER": return (); + case "INPUT_FIELD": + return (); + case "BUTTON": + return (); + case "AUDIO": + return (); + case "IMAGE": + return (); default: return (Unsupported block type: {block.blockTypeName}) } diff --git a/src/qqq/components/widgets/blocks/AudioBlock.tsx b/src/qqq/components/widgets/blocks/AudioBlock.tsx new file mode 100644 index 0000000..210eaaf --- /dev/null +++ b/src/qqq/components/widgets/blocks/AudioBlock.tsx @@ -0,0 +1,40 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import Box from "@mui/material/Box"; +import BlockElementWrapper from "qqq/components/widgets/blocks/BlockElementWrapper"; +import {StandardBlockComponentProps} from "qqq/components/widgets/blocks/BlockModels"; +import DumpJsonBox from "qqq/utils/DumpJsonBox"; +import React from "react"; + +/******************************************************************************* + ** Block that renders ... an audio tag + ** + **