diff --git a/public/index.html b/public/index.html
index 66fb271..03b5590 100644
--- a/public/index.html
+++ b/public/index.html
@@ -21,7 +21,7 @@ Coded by www.creative-tim.com
-
QQQ Material Dashboard
+
diff --git a/src/qqq/components/widgets/DashboardWidgets.tsx b/src/qqq/components/widgets/DashboardWidgets.tsx
index c7fb36e..0ee5951 100644
--- a/src/qqq/components/widgets/DashboardWidgets.tsx
+++ b/src/qqq/components/widgets/DashboardWidgets.tsx
@@ -243,7 +243,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
{
widgetMetaData.type === "html" && (
-
+
{
widgetData && widgetData[i] && widgetData[i].html ? (
diff --git a/src/qqq/components/widgets/Widget.tsx b/src/qqq/components/widgets/Widget.tsx
index 00e542a..320b916 100644
--- a/src/qqq/components/widgets/Widget.tsx
+++ b/src/qqq/components/widgets/Widget.tsx
@@ -142,7 +142,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element
{
const link = component as HeaderLink
return (
-
+
{link.to ? {link.label} : null}
);
@@ -153,7 +153,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element
const addNewRecordButton = component as AddNewRecordButton
return (
-
+
);
}
diff --git a/src/qqq/pages/apps/Home.tsx b/src/qqq/pages/apps/Home.tsx
index 6771285..f2bb0ae 100644
--- a/src/qqq/pages/apps/Home.tsx
+++ b/src/qqq/pages/apps/Home.tsx
@@ -173,7 +173,7 @@ function AppHome({app}: Props): JSX.Element
const widgetCount = widgets ? widgets.length : 0;
// eslint-disable-next-line no-nested-ternary
- const tileSizeLg = (widgetCount === 0 ? 3 : widgetCount === 1 ? 4 : 6);
+ const tileSizeLg = 3;
const handleDropdownOnChange = (value: string, index: number) =>
{
@@ -207,7 +207,7 @@ function AppHome({app}: Props): JSX.Element
{
app.sections ? (
-
+
{app.sections.map((section) => (
diff --git a/src/qqq/pages/records/query/GridFilterOperators.tsx b/src/qqq/pages/records/query/GridFilterOperators.tsx
index ff36692..d85a2ee 100644
--- a/src/qqq/pages/records/query/GridFilterOperators.tsx
+++ b/src/qqq/pages/records/query/GridFilterOperators.tsx
@@ -731,6 +731,73 @@ function InputPossibleValueSourceSingle(tableName: string, field: QFieldMetaData
}
+////////////////////////////////////////////////
+// input element for multiple possible values //
+////////////////////////////////////////////////
+function InputPossibleValueSourceMultiple(tableName: string, field: QFieldMetaData, props: GridFilterInputValueProps)
+{
+ const SUBMIT_FILTER_STROKE_TIME = 500;
+ const {item, applyValue, focusElementRef = null} = props;
+
+ console.log("Item.value? " + item.value);
+
+ const filterTimeout = useRef();
+ const [ selectedPossibleValues, setSelectedPossibleValues ] = useState(item.value as QPossibleValue[]);
+ const [ applying, setIsApplying ] = useState(false);
+
+ useEffect(() =>
+ {
+ return () =>
+ {
+ clearTimeout(filterTimeout.current);
+ };
+ }, []);
+
+ useEffect(() =>
+ {
+ const itemValue = item.value ?? null;
+ }, [ item.value ]);
+
+ const updateFilterValue = (value: QPossibleValue) =>
+ {
+ clearTimeout(filterTimeout.current);
+
+ setIsApplying(true);
+ filterTimeout.current = setTimeout(() =>
+ {
+ setIsApplying(false);
+ applyValue({...item, value: value});
+ }, SUBMIT_FILTER_STROKE_TIME);
+ };
+
+ const handleChange = (value: QPossibleValue) =>
+ {
+ updateFilterValue(value);
+ };
+
+ return (
+
+
+
+ );
+}
+
+
//////////////////////////////////
// possible value set operators //
//////////////////////////////////
@@ -749,6 +816,18 @@ export const buildQGridPvsOperators = (tableName: string, field: QFieldMetaData)
getApplyFilterFn: () => null,
InputComponent: (props: GridFilterInputValueProps) => InputPossibleValueSourceSingle(tableName, field, props)
},
+ {
+ label: "is any of",
+ value: "isAnyOf",
+ getApplyFilterFn: () => null,
+ InputComponent: (props: GridFilterInputValueProps) => InputPossibleValueSourceMultiple(tableName, field, props)
+ },
+ {
+ label: "is none of",
+ value: "isNone",
+ getApplyFilterFn: () => null,
+ InputComponent: (props: GridFilterInputValueProps) => InputPossibleValueSourceMultiple(tableName, field, props)
+ },
{
label: "is empty",
value: "isEmpty",
diff --git a/src/qqq/utils/qqq/FilterUtils.ts b/src/qqq/utils/qqq/FilterUtils.ts
index 8f04970..dbfb055 100644
--- a/src/qqq/utils/qqq/FilterUtils.ts
+++ b/src/qqq/utils/qqq/FilterUtils.ts
@@ -344,7 +344,8 @@ class FilterUtils
{
try
{
- const qQueryFilter = (filterString !== null) ? JSON.parse(filterString) : JSON.parse(searchParams.get("filter")) as QQueryFilter;
+ const filterJSON = (filterString !== null) ? JSON.parse(filterString) : JSON.parse(searchParams.get("filter"));
+ const qQueryFilter = filterJSON as QQueryFilter;
//////////////////////////////////////////////////////////////////
// translate from a qqq-style filter to one that the grid wants //
@@ -377,6 +378,53 @@ class FilterUtils
}
}
+ if (field && field.type == "DATE_TIME" && !values)
+ {
+ try
+ {
+ const criteria = filterJSON.criteria[i];
+ if (criteria && criteria.expression)
+ {
+ let value = new Date();
+ let amount = Number(criteria.expression.amount);
+ switch (criteria.expression.timeUnit)
+ {
+ case "MINUTES":
+ {
+ amount = amount * 60;
+ break;
+ }
+ case "HOURS":
+ {
+ amount = amount * 60 * 60;
+ break;
+ }
+ case "DAYS":
+ {
+ amount = amount * 60 * 60 * 24;
+ break;
+ }
+ default:
+ {
+ console.log("Unrecognized time unit: " + criteria.expression.timeUnit);
+ }
+ }
+
+ if (criteria.expression.operator == "MINUS")
+ {
+ amount = -amount;
+ }
+
+ value.setTime(value.getTime() + 1000 * amount);
+ values = [ValueUtils.formatDateTimeISO8601(value)];
+ }
+ }
+ catch (e)
+ {
+ console.log(e);
+ }
+ }
+
defaultFilter.items.push({
columnField: criteria.fieldName,
operatorValue: FilterUtils.qqqCriteriaOperatorToGrid(criteria.operator, field, values),
diff --git a/src/qqq/utils/qqq/ValueUtils.tsx b/src/qqq/utils/qqq/ValueUtils.tsx
index 080ff62..6c3f2ae 100644
--- a/src/qqq/utils/qqq/ValueUtils.tsx
+++ b/src/qqq/utils/qqq/ValueUtils.tsx
@@ -131,7 +131,7 @@ class ValueUtils
if (field.hasAdornment(AdornmentType.RENDER_HTML))
{
- return (parse(rawValue));
+ return (rawValue ? parse(rawValue) : "");
}
if (field.hasAdornment(AdornmentType.CHIP))
@@ -253,6 +253,16 @@ class ValueUtils
return (`${date.toString("yyyy-MM-dd hh:mm:ss")} ${date.getHours() < 12 ? "AM" : "PM"} ${date.getTimezone()}`);
}
+ public static formatDateTimeISO8601(date: Date)
+ {
+ if(!(date instanceof Date))
+ {
+ date = new Date(date)
+ }
+ // @ts-ignore
+ return (`${date.toString("yyyy-MM-ddThh:mm:ssZ")}`);
+ }
+
public static getFullWeekday(date: Date)
{
if(!(date instanceof Date))