Experimental filters: small bugfixes (#4019)

This commit is contained in:
Krzysztof Żuraw 2023-07-27 10:34:59 +02:00 committed by GitHub
parent d9c600452c
commit be6adb28d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 103 additions and 73 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---
Experimental filters: fix small issues

14
package-lock.json generated
View file

@ -27,7 +27,7 @@
"@material-ui/lab": "^4.0.0-alpha.61",
"@material-ui/styles": "^4.11.4",
"@reach/auto-id": "^0.16.0",
"@saleor/macaw-ui": "0.8.0-pre.111",
"@saleor/macaw-ui": "0.8.0-pre.112",
"@saleor/sdk": "0.6.0",
"@sentry/react": "^6.0.0",
"@types/faker": "^5.1.6",
@ -8795,9 +8795,9 @@
}
},
"node_modules/@saleor/macaw-ui": {
"version": "0.8.0-pre.111",
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.111.tgz",
"integrity": "sha512-MvanJYWg7ASHc4Qq+XbXYJ7HgubyRjOuD4j3plTBopyNrAMXNie7h4TOgBjuL3FYTTAM6gUt4CwQPnwWe378eA==",
"version": "0.8.0-pre.112",
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.112.tgz",
"integrity": "sha512-USVepQkr3t4/6WWTyHOJ+vj6bxoPHUI0m7e13ZF012YJT1c+ORRtJtYnnKdxazCDl7GjEH1shDJmpexQmtqPJQ==",
"dependencies": {
"@dessert-box/react": "^0.4.0",
"@floating-ui/react-dom-interactions": "^0.5.0",
@ -41264,9 +41264,9 @@
}
},
"@saleor/macaw-ui": {
"version": "0.8.0-pre.111",
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.111.tgz",
"integrity": "sha512-MvanJYWg7ASHc4Qq+XbXYJ7HgubyRjOuD4j3plTBopyNrAMXNie7h4TOgBjuL3FYTTAM6gUt4CwQPnwWe378eA==",
"version": "0.8.0-pre.112",
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.112.tgz",
"integrity": "sha512-USVepQkr3t4/6WWTyHOJ+vj6bxoPHUI0m7e13ZF012YJT1c+ORRtJtYnnKdxazCDl7GjEH1shDJmpexQmtqPJQ==",
"requires": {
"@dessert-box/react": "^0.4.0",
"@floating-ui/react-dom-interactions": "^0.5.0",

View file

@ -34,7 +34,7 @@
"@material-ui/lab": "^4.0.0-alpha.61",
"@material-ui/styles": "^4.11.4",
"@reach/auto-id": "^0.16.0",
"@saleor/macaw-ui": "0.8.0-pre.111",
"@saleor/macaw-ui": "0.8.0-pre.112",
"@saleor/sdk": "0.6.0",
"@sentry/react": "^6.0.0",
"@types/faker": "^5.1.6",

View file

@ -36,7 +36,7 @@ export const ListFilters = <TFilterKeys extends string = string>({
<>
<Box
display="grid"
gridTemplateColumns={2}
__gridTemplateColumns="auto 1fr"
gap={4}
paddingBottom={2}
paddingX={6}

View file

@ -1,6 +1,6 @@
import { AttributeInputTypeEnum } from "@dashboard/graphql";
import { createBoleanOption } from "../constants";
import { createBooleanOption } from "../constants";
import { AttributeInputType } from "../FilterElement/ConditionOptions";
import { ItemOption } from "../FilterElement/ConditionValue";
import { UrlToken } from "../ValueProvider/UrlToken";
@ -58,7 +58,7 @@ export class InitialStateResponse implements InitialState {
if (token.isAttribute()) {
const attr = this.attribute[token.name];
return attr.inputType === "BOOLEAN"
? createBoleanOption(
? createBooleanOption(
token.value === "true",
AttributeInputTypeEnum.BOOLEAN,
)

View file

@ -36,16 +36,17 @@ const isStaticBoolean = (rowType: RowType) => {
"isPublished",
"isVisibleInListing",
"hasCategory",
"giftCard"
].includes(rowType)
}
"giftCard",
"price",
].includes(rowType);
};
const createAPIHandler = (
selectedRow: FilterElement,
client: ApolloClient<unknown>,
inputValue: string,
): Handler => {
const rowType = selectedRow.rowType()
const rowType = selectedRow.rowType();
if (rowType === "attribute" && selectedRow.value.type === "BOOLEAN") {
return new BooleanValuesHandler([
@ -53,15 +54,15 @@ const createAPIHandler = (
label: "Yes",
value: "true",
type: AttributeInputTypeEnum.BOOLEAN,
slug: "true"
slug: "true",
},
{
label: "No",
value: "false",
type: AttributeInputTypeEnum.BOOLEAN,
slug: "false"
}
])
slug: "false",
},
]);
}
if (rowType === "attribute") {
@ -78,15 +79,15 @@ const createAPIHandler = (
label: "Yes",
value: "true",
type: rowType,
slug: "true"
slug: "true",
},
{
label: "No",
value: "false",
type: rowType,
slug: "false"
}
])
slug: "false",
},
]);
}
if (rowType === "collection") {

View file

@ -2,15 +2,35 @@ import { gql } from "@apollo/client";
export const initialDynamicLeftOperands = gql`
query _GetDynamicLeftOperands($first: Int!, $query: String!) {
attributes(first: $first, filter: { type: PRODUCT_TYPE, search: $query }) {
attributes(
first: $first
search: $query
where: {
type: { eq: PRODUCT_TYPE }
inputType: {
oneOf: [
DROPDOWN
MULTISELECT
BOOLEAN
NUMERIC
DATE
DATE_TIME
SWATCH
]
}
}
) {
edges {
node {
id
name
slug
inputType
__typename
}
__typename
}
__typename
}
}
`;

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { InitialStateResponse } from "../API/InitialStateResponse";
import { LeftOperand } from "../LeftOperandsProvider";
import { UrlToken } from "./../ValueProvider/UrlToken";
@ -26,7 +25,7 @@ export class Condition {
}
public isEmpty() {
return this.options.isEmpty() || this.selected.isEmpty()
return this.options.isEmpty() || this.selected.isEmpty();
}
public static createEmpty() {
@ -81,7 +80,7 @@ export class Condition {
if (token.isAttribute()) {
const attribute = response.attributeByName(token.name);
const options = ConditionOptions.fromAtributeType(attribute.inputType);
const option = options.find(item => item.label === token.conditionKind)!
const option = options.find(item => item.label === token.conditionKind)!;
const value = response.filterByUrlToken(token);
return new Condition(

View file

@ -1,10 +1,13 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { InitialStateResponse } from "../API/InitialStateResponse";
import { RowType, STATIC_OPTIONS } from "../constants";
import { LeftOperand } from "../LeftOperandsProvider";
import { TokenType, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken";
import { Condition } from "./Condition";
import { ConditionItem, ConditionOptions, StaticElementName } from "./ConditionOptions";
import {
ConditionItem,
ConditionOptions,
StaticElementName,
} from "./ConditionOptions";
import { ConditionSelected } from "./ConditionSelected";
import { ConditionValue, ItemOption } from "./ConditionValue";
import { Constraint } from "./Constraint";
@ -14,22 +17,18 @@ class ExpressionValue {
public value: string,
public label: string,
public type: string,
) { }
) {}
public isEmpty() {
return this.value.length === 0 || this.label.length === 0
return this.value.length === 0 || this.label.length === 0;
}
public static fromSlug(slug: string) {
const option = STATIC_OPTIONS.find(o => o.slug === slug)
const option = STATIC_OPTIONS.find(o => o.slug === slug);
if (!option) return ExpressionValue.emptyStatic()
if (!option) return ExpressionValue.emptyStatic();
return new ExpressionValue(
option.slug,
option.label,
option.type,
);
return new ExpressionValue(option.slug, option.label, option.type);
}
public static fromLeftOperand(leftOperand: LeftOperand) {
@ -75,10 +74,10 @@ export class FilterElement {
public loading: boolean,
public constraint?: Constraint,
) {
const newConstraint = Constraint.fromSlug(this.value.value)
const newConstraint = Constraint.fromSlug(this.value.value);
if (newConstraint) {
this.constraint = newConstraint
this.constraint = newConstraint;
}
}
@ -126,7 +125,7 @@ export class FilterElement {
}
public isEmpty() {
return this.value.isEmpty() || this.condition.isEmpty()
return this.value.isEmpty() || this.condition.isEmpty();
}
public isStatic() {
@ -150,14 +149,13 @@ export class FilterElement {
}
public setConstraint(constraint: Constraint) {
this.constraint = constraint
this.constraint = constraint;
}
public clearConstraint() {
this.constraint = undefined
this.constraint = undefined;
}
public asUrlEntry(): UrlEntry {
if (this.isAttribute()) {
return UrlEntry.forAttribute(this.condition.selected, this.value.value);
@ -167,10 +165,12 @@ export class FilterElement {
}
public static isCompatible(element: unknown): element is FilterElement {
return typeof element === "object" &&
return (
typeof element === "object" &&
!Array.isArray(element) &&
element !== null &&
'value' in element
"value" in element
);
}
public static fromValueEntry(valueEntry: any) {
@ -216,7 +216,7 @@ export class FilterElement {
export const hasEmptyRows = (container: FilterContainer) => {
return container
.filter(FilterElement.isCompatible)
.some((e: FilterElement) => e.isEmpty())
}
.some((e: FilterElement) => e.isEmpty());
};
export type FilterContainer = Array<string | FilterElement | FilterContainer>;

View file

@ -1,6 +1,6 @@
import { ParsedQs } from "qs";
import { getAtributeInputType } from "../constants";
import { getAttributeInputType } from "../constants";
import { ConditionSelected } from "../FilterElement/ConditionSelected";
import { slugFromConditionValue } from "../FilterElement/ConditionValue";
@ -15,7 +15,7 @@ const STATIC_TO_LOAD = [
"isPublished",
"isVisibleInListing",
"hasCategory",
"giftCard"
"giftCard",
];
export const TokenType = {
@ -28,18 +28,17 @@ export const TokenType = {
STATIC: "s",
} as const;
export type TokenTypeValue = (typeof TokenType)[keyof typeof TokenType];
const resolveTokenType = (name: string): TokenTypeValue => {
const key = `ATTRIBUTE_${name}` as keyof typeof TokenType
const key = `ATTRIBUTE_${name}` as keyof typeof TokenType;
if (key in TokenType) {
return TokenType[key]
return TokenType[key];
}
return TokenType.STATIC
}
return TokenType.STATIC;
};
export class UrlEntry {
constructor(key: string, value: string | string[]) {
@ -54,14 +53,10 @@ export class UrlEntry {
}
public static forAttribute(condition: ConditionSelected, paramName: string) {
const inputType = getAtributeInputType(condition.conditionValue)
const tokenSlug = resolveTokenType(inputType || "")
const inputType = getAttributeInputType(condition.conditionValue);
const tokenSlug = resolveTokenType(inputType || "");
return UrlEntry.fromConditionSelected(
condition,
paramName,
tokenSlug,
);
return UrlEntry.fromConditionSelected(condition, paramName, tokenSlug);
}
public static forStatic(condition: ConditionSelected, paramName: string) {
@ -120,15 +115,18 @@ export class UrlToken {
}
public isAttribute() {
const result = Object.entries(TokenType)
.find(([_, slug]) => slug === this.type)
const result = Object.entries(TokenType).find(
([_, slug]) => slug === this.type,
);
return result && result[0].includes("ATTRIBUTE")
return result && result[0].includes("ATTRIBUTE");
}
public hasDynamicValues() {
return TokenType.ATTRIBUTE_DROPDOWN === this.type
|| TokenType.ATTRIBUTE_MULTISELECT === this.type
return (
TokenType.ATTRIBUTE_DROPDOWN === this.type ||
TokenType.ATTRIBUTE_MULTISELECT === this.type
);
}
public isLoadable() {

View file

@ -97,7 +97,7 @@ export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = {
SWATCH: [{ type: "multiselect", label: "in", value: "input-2" }],
};
export const getAtributeInputType = (item: ConditionItem | null) => {
export const getAttributeInputType = (item: ConditionItem | null) => {
const result = Object.entries(ATTRIBUTE_INPUT_TYPE_CONDITIONS).find(
([_, value]) =>
value.find(
@ -129,7 +129,7 @@ export const createBooleanOptions = (type?: string): ItemOption[] => [
booleanOptionFalse(type),
];
export const createBoleanOption = (
export const createBooleanOption = (
flag: boolean,
type?: string,
): ItemOption => {

View file

@ -3,7 +3,7 @@ import { ConditionValue } from "./FilterElement/ConditionValue";
export const CONTROL_DEFAULTS = {
text: "",
number: "",
"number.range": [] as unknown as [string, string],
"number.range": ["", ""] as [string, string],
multiselect: [] as ConditionValue,
select: "",
combobox: "",

View file

@ -1,15 +1,15 @@
import unionBy from "lodash/unionBy";
import { useState } from "react";
import { STATIC_OPTIONS } from "./constants";
import { LeftOperand, LeftOperandsProvider } from "./LeftOperandsProvider";
export const useFilterLeftOperandsProvider = (): LeftOperandsProvider => {
const [operands, setOperands] = useState<LeftOperand[]>(STATIC_OPTIONS);
return {
operands,
setOperands: (options: LeftOperand[]) =>
setOperands(prev => [...prev, ...options]),
setOperands(prev => unionBy([...prev, ...options], "value")),
};
};

View file

@ -5460,15 +5460,22 @@ export type AddressValidationRulesLazyQueryHookResult = ReturnType<typeof useAdd
export type AddressValidationRulesQueryResult = Apollo.QueryResult<Types.AddressValidationRulesQuery, Types.AddressValidationRulesQueryVariables>;
export const _GetDynamicLeftOperandsDocument = gql`
query _GetDynamicLeftOperands($first: Int!, $query: String!) {
attributes(first: $first, filter: {type: PRODUCT_TYPE, search: $query}) {
attributes(
first: $first
search: $query
where: {type: {eq: PRODUCT_TYPE}, inputType: {oneOf: [DROPDOWN, MULTISELECT, BOOLEAN, NUMERIC, DATE, DATE_TIME, SWATCH]}}
) {
edges {
node {
id
name
slug
inputType
__typename
}
__typename
}
__typename
}
}
`;