Skip to content

Commit

Permalink
feat(QueryBuilder): opt-out of confirmation dialogs
Browse files Browse the repository at this point in the history
  • Loading branch information
MEsteves22 committed Nov 27, 2023
1 parent 45a0313 commit e2c8c5d
Show file tree
Hide file tree
Showing 13 changed files with 77 additions and 39 deletions.
2 changes: 2 additions & 0 deletions packages/core/src/components/QueryBuilder/Context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ export interface HvQueryBuilderContextValue {
labels: HvQueryBuilderLabels;
initialTouched: boolean;
readOnly: boolean;
disableConfirmation: boolean;
renderers?: HvQueryBuilderRenderers;
}

Expand All @@ -336,6 +337,7 @@ export const HvQueryBuilderContext = createContext<HvQueryBuilderContextValue>({
maxDepth: 1,
labels: defaultLabels,
initialTouched: false,
disableConfirmation: false,
readOnly: false,
});

Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/components/QueryBuilder/QueryBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export interface HvQueryBuilderProps {
readOnly?: boolean;
/** Renderers for custom attribute types. */
renderers?: HvQueryBuilderRenderers;
/** Whether to opt-out of the confirmation dialogs shown before removing rules and rule groups. Default to `false`. */
disableConfirmation?: boolean;
/** A Jss Object used to override or extend the styles applied. */
classes?: HvQueryBuilderClasses;
}
Expand All @@ -69,6 +71,7 @@ export const HvQueryBuilder = (props: HvQueryBuilderProps) => {
renderers,
query,
onChange,
disableConfirmation = false,
operators = defaultOperators,
combinators = defaultCombinators,
maxDepth = 1,
Expand Down Expand Up @@ -107,6 +110,7 @@ export const HvQueryBuilder = (props: HvQueryBuilderProps) => {
initialTouched: initialState,
readOnly,
renderers,
disableConfirmation,
}),
[
attributes,
Expand All @@ -117,6 +121,7 @@ export const HvQueryBuilder = (props: HvQueryBuilderProps) => {
readOnly,
initialState,
renderers,
disableConfirmation,
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ export const Attribute = ({
disabled,
isInvalid,
}: AttributeProps) => {
const context = useQueryBuilderContext();

const { dispatchAction, attributes, operators, labels, readOnly } = context;
const { dispatchAction, attributes, operators, labels, readOnly } =
useQueryBuilderContext();

const values = useMemo(() => {
if (!attributes) return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ export const Operator = ({
attribute,
operator,
}: OperatorProps) => {
const context = useQueryBuilderContext();

const { dispatchAction, attributes, operators, labels, readOnly } = context;
const { dispatchAction, attributes, operators, labels, readOnly } =
useQueryBuilderContext();

const value = operator ?? null;

Expand Down
27 changes: 18 additions & 9 deletions packages/core/src/components/QueryBuilder/Rule/Rule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,23 @@ export const Rule = (props: RuleProps) => {
isInvalid,
classes: classesProp,
} = useDefaultProps("HvQueryBuilderRule", props);

const { classes, cx } = useClasses(classesProp);

const context = useQueryBuilderContext();
const {
askAction,
dispatchAction,
attributes,
operators,
labels,
readOnly,
disableConfirmation,
} = useQueryBuilderContext();

const theme = useTheme();

const isMdDown = useMediaQuery(theme.breakpoints.down("md"));

const { askAction, attributes, operators, labels, readOnly } = context;

const availableOperators = useMemo(() => {
const attributeSpec =
attribute != null && attributes ? attributes[attribute] : null;
Expand Down Expand Up @@ -117,12 +124,14 @@ export const Rule = (props: RuleProps) => {
<HvButton
icon
aria-label={labels.rule.delete.ariaLabel}
onClick={() => {
askAction({
actions: [{ type: "remove-node", id }],
dialog: labels.rule.delete,
});
}}
onClick={() =>
disableConfirmation
? dispatchAction({ type: "remove-node", id })
: askAction({
actions: [{ type: "remove-node", id }],
dialog: labels.rule.delete,
})
}
disabled={readOnly}
>
<DeleteIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ export interface BooleanValueProps {
}

export const BooleanValue = ({ id, value = true }: BooleanValueProps) => {
const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;
const { labels, dispatchAction, readOnly } = useQueryBuilderContext();

const values = ["true", "false"].map((v) => ({
id: v,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ export const DateTimeValue = ({

const isRange = valueIsRange(operator);

const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;
const { labels, dispatchAction, readOnly } = useQueryBuilderContext();

const elementId = uniqueId(`datetime${id}`);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ export const NumericValue = ({
const { classes, cx } = useClasses();

const isRange = operator === "range";
const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;
const { labels, dispatchAction, readOnly } = useQueryBuilderContext();

const theme = useTheme();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ export const TextValue = ({
}: TextValueProps) => {
const { classes } = useClasses();

const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;
const { labels, dispatchAction, readOnly } = useQueryBuilderContext();

const [touched, setTouched] = useState(initialTouched);

const isValid = value != null && value.toString().trim() !== "";

let status: HvFormStatus = isValid ? "valid" : "invalid";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ export const Value = ({
operator,
value: valueProp,
}: ValueProps) => {
const context = useQueryBuilderContext();
const { attributes, initialTouched, renderers } = context;
const { attributes, initialTouched, renderers } = useQueryBuilderContext();

const value =
attribute && attributes ? { ...attributes[attribute] } : { type: null };
Expand Down
32 changes: 20 additions & 12 deletions packages/core/src/components/QueryBuilder/RuleGroup/RuleGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@ export const RuleGroup = ({
}: RuleGroupProps) => {
const { classes, cx } = useClasses(classesProp);

const context = useQueryBuilderContext();
const {
dispatchAction,
askAction,
maxDepth,
combinators,
labels,
readOnly,
disableConfirmation,
} = useQueryBuilderContext();

const { dispatchAction, askAction, maxDepth, combinators, labels, readOnly } =
context;
const normalizedMaxDepth = maxDepth - 1;

const actionButtons = (
Expand Down Expand Up @@ -128,15 +134,17 @@ export const RuleGroup = ({
<HvButton
icon
className={classes.removeButton}
onClick={() => {
askAction({
actions: [{ type: "remove-node", id }],
dialog:
level === 0 && labels.query?.delete != null
? labels.query.delete
: labels.group.delete,
});
}}
onClick={() =>
disableConfirmation
? dispatchAction({ type: "remove-node", id })
: askAction({
actions: [{ type: "remove-node", id }],
dialog:
level === 0 && labels.query?.delete != null
? labels.query.delete
: labels.group.delete,
})
}
aria-label={
level === 0 && labels.query?.delete?.ariaLabel
? labels.query?.delete?.ariaLabel
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { useState } from "react";
import { HvQueryBuilder } from "@hitachivantara/uikit-react-core";
import { css } from "@emotion/css";
import {
HvQueryBuilder,
HvButton,
theme,
} from "@hitachivantara/uikit-react-core";
import { Topics } from "@hitachivantara/uikit-react-icons";

import queryToMongo from "./queryToMongo";

Expand Down Expand Up @@ -76,9 +82,19 @@ const initialQuery = {

export const InitialQuery = () => {
const [mongoQuery, setMongoQuery] = useState(queryToMongo(initialQuery));
const [disable, setDisable] = useState(false);

return (
<>
<HvButton
variant="secondarySubtle"
startIcon={<Topics />}
onClick={() => setDisable(!disable)}
className={css({ marginBottom: theme.space.sm })}
>
{disable ? "Show" : "Hide"} confirmation dialogs
</HvButton>

<HvQueryBuilder
attributes={attributes}
query={initialQuery}
Expand All @@ -89,6 +105,7 @@ export const InitialQuery = () => {
console.log("error: ", error.toString());
}
}}
disableConfirmation={disable}
/>
<pre>{JSON.stringify(mongoQuery, null, 2)}</pre>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const meta: Meta<typeof HvQueryBuilder> = {
export default meta;

export const Main: StoryObj<HvQueryBuilderProps> = {
args: { disableConfirmation: false },
argTypes: {
classes: { control: { disable: true } },
attributes: { control: { disable: true } },
Expand All @@ -46,7 +47,8 @@ export const InitialQuery: StoryObj<HvQueryBuilderProps> = {
parameters: {
docs: {
description: {
story: "Query Builder that parses the query to Mongo",
story:
"Query Builder that parses the query to Mongo. You can also control whether you want the confirmation dialogs, which are shown before removing rules and rule groups, to appear or not by clicking on the button. This button controls the `disableConfirmation` property of the query builder.",
},
source: {
code: InitialQueryRaw,
Expand Down

0 comments on commit e2c8c5d

Please sign in to comment.