Cover attributes based on inputType (#3945)

* Cover attributes based on inputType

* Changeset

* Remove logs

* Lint
This commit is contained in:
Patryk Andrzejewski 2023-07-18 14:55:56 +02:00 committed by GitHub
parent 9a3c9de817
commit 4e8942f90e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 21 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---
Cover attributes based on input type

View file

@ -1,3 +1,6 @@
import { AttributeInputTypeEnum } from "@dashboard/graphql";
import { createBoleanOption } from "../constants";
import { AttributeInputType } from "../FilterElement/ConditionOptions"; import { AttributeInputType } from "../FilterElement/ConditionOptions";
import { ItemOption } from "../FilterElement/ConditionValue"; import { ItemOption } from "../FilterElement/ConditionValue";
import { UrlToken } from "../ValueProvider/UrlToken"; import { UrlToken } from "../ValueProvider/UrlToken";
@ -46,12 +49,19 @@ export class InitialStateResponse implements InitialState {
} }
public filterByUrlToken(token: UrlToken) { public filterByUrlToken(token: UrlToken) {
if (token.isAttribute()) { if (token.isAttribute() && token.hasDynamicValues()) {
return this.attribute[token.name].choices.filter(({ value }) => return this.attribute[token.name].choices.filter(({ value }) =>
token.value.includes(value), token.value.includes(value),
); );
} }
if (token.isAttribute()) {
const attr = this.attribute[token.name]
return attr.inputType === "BOOLEAN"
? createBoleanOption(token.value === "true", AttributeInputTypeEnum.BOOLEAN)
: token.value
}
if (!token.isLoadable()) { if (!token.isLoadable()) {
return [token.value] as string[]; return [token.value] as string[];
} }

View file

@ -1,4 +1,5 @@
import { ApolloClient, useApolloClient } from "@apollo/client"; import { ApolloClient, useApolloClient } from "@apollo/client";
import { AttributeInputTypeEnum } from "@dashboard/graphql";
import { RowType } from "../constants"; import { RowType } from "../constants";
import { FilterContainer, FilterElement } from "../FilterElement"; import { FilterContainer, FilterElement } from "../FilterElement";
@ -46,6 +47,23 @@ const createAPIHandler = (
): Handler => { ): Handler => {
const rowType = selectedRow.rowType() const rowType = selectedRow.rowType()
if (rowType === "attribute" && selectedRow.value.type === "BOOLEAN") {
return new BooleanValuesHandler([
{
label: "Yes",
value: "true",
type: AttributeInputTypeEnum.BOOLEAN,
slug: "true"
},
{
label: "No",
value: "false",
type: AttributeInputTypeEnum.BOOLEAN,
slug: "false"
}
])
}
if (rowType === "attribute") { if (rowType === "attribute") {
return new AttributeChoicesHandler( return new AttributeChoicesHandler(
client, client,

View file

@ -85,7 +85,10 @@ export const createInitialStateFromData = (
(acc, { node }) => ({ (acc, { node }) => ({
...acc, ...acc,
[node.slug ?? ""]: { [node.slug ?? ""]: {
choices: createOptionsFromAPI(node.choices?.edges ?? []), choices:
node.inputType === "BOOLEAN"
? createBooleanOptions()
: createOptionsFromAPI(node.choices?.edges ?? []),
slug: node?.slug, slug: node?.slug,
value: node?.id, value: node?.id,
label: node?.name, label: node?.name,

View file

@ -4,6 +4,7 @@ import { LeftOperand } from "../LeftOperandsProvider";
import { UrlToken } from "./../ValueProvider/UrlToken"; import { UrlToken } from "./../ValueProvider/UrlToken";
import { ConditionOptions } from "./ConditionOptions"; import { ConditionOptions } from "./ConditionOptions";
import { ConditionSelected } from "./ConditionSelected"; import { ConditionSelected } from "./ConditionSelected";
import { ItemOption } from "./ConditionValue";
export class Condition { export class Condition {
private constructor( private constructor(
@ -46,7 +47,7 @@ export class Condition {
if (ConditionOptions.isStaticName(token.name)) { if (ConditionOptions.isStaticName(token.name)) {
const staticOptions = ConditionOptions.fromStaticElementName(token.name); const staticOptions = ConditionOptions.fromStaticElementName(token.name);
const selectedOption = staticOptions.findByLabel(token.conditionKind); const selectedOption = staticOptions.findByLabel(token.conditionKind);
const valueItems = response.filterByUrlToken(token); const valueItems = response.filterByUrlToken(token) as ItemOption[];
const value = const value =
selectedOption?.type === "multiselect" && valueItems.length > 0 selectedOption?.type === "multiselect" && valueItems.length > 0
? valueItems ? valueItems
@ -66,11 +67,12 @@ export class Condition {
if (token.isAttribute()) { if (token.isAttribute()) {
const attribute = response.attributeByName(token.name); const attribute = response.attributeByName(token.name);
const options = ConditionOptions.fromAtributeType(attribute.inputType); const options = ConditionOptions.fromAtributeType(attribute.inputType);
const option = options.find(item => item.label === token.conditionKind)!
const value = response.filterByUrlToken(token); const value = response.filterByUrlToken(token);
return new Condition( return new Condition(
options, options,
ConditionSelected.fromConditionItemAndValue(options.first(), value), ConditionSelected.fromConditionItemAndValue(option, value),
false, false,
); );
} }

View file

@ -1,4 +1,4 @@
import { UrlToken } from "../UrlToken"; import { TokenType, UrlToken } from "../UrlToken";
export interface FetchingParams { export interface FetchingParams {
category: string[]; category: string[];
@ -20,6 +20,10 @@ export const emptyFetchingParams: FetchingParams = {
const unique = <T>(array: Iterable<T>) => Array.from(new Set(array)); const unique = <T>(array: Iterable<T>) => Array.from(new Set(array));
const includedInParams = (c: UrlToken) =>
TokenType.ATTRIBUTE_DROPDOWN === c.type
|| TokenType.ATTRIBUTE_MULTISELECT === c.type
export const toFetchingParams = (p: FetchingParams, c: UrlToken) => { export const toFetchingParams = (p: FetchingParams, c: UrlToken) => {
const key = c.name as FetchingParamsKeys; const key = c.name as FetchingParamsKeys;
@ -31,12 +35,18 @@ export const toFetchingParams = (p: FetchingParams, c: UrlToken) => {
p.attribute[c.name] = []; p.attribute[c.name] = [];
} }
if (c.isAttribute()) { if (c.isAttribute() && includedInParams(c)) {
p.attribute[c.name] = unique(p.attribute[c.name].concat(c.value)); p.attribute[c.name] = unique(p.attribute[c.name].concat(c.value));
return p; return p;
} }
if (c.isAttribute() && !includedInParams(c)) {
p.attribute[c.name] = []
return p;
}
p[key] = unique(p[key].concat(c.value)); p[key] = unique(p[key].concat(c.value));
return p; return p;

View file

@ -1,5 +1,6 @@
import { ParsedQs } from "qs"; import { ParsedQs } from "qs";
import { getAtributeInputType } from "../constants";
import { ConditionSelected } from "../FilterElement/ConditionSelected"; import { ConditionSelected } from "../FilterElement/ConditionSelected";
import { slugFromConditionValue } from "../FilterElement/ConditionValue"; import { slugFromConditionValue } from "../FilterElement/ConditionValue";
@ -18,12 +19,28 @@ const STATIC_TO_LOAD = [
]; ];
export const TokenType = { export const TokenType = {
ATTRIBUTE: "a", ATTRIBUTE_DROPDOWN: "o",
ATTRIBUTE_MULTISELECT: "m",
ATTRIBUTE_NUMERIC: "n",
ATTRIBUTE_DATE_TIME: "t",
ATTRIBUTE_DATE: "d",
ATTRIBUTE_BOOLEAN: "b",
STATIC: "s", STATIC: "s",
} as const; } as const;
export type TokenTypeValue = (typeof TokenType)[keyof typeof TokenType]; export type TokenTypeValue = (typeof TokenType)[keyof typeof TokenType];
const resolveTokenType = (name: string): TokenTypeValue => {
const key = `ATTRIBUTE_${name}` as keyof typeof TokenType
if (key in TokenType) {
return TokenType[key]
}
return TokenType.STATIC
}
export class UrlEntry { export class UrlEntry {
constructor(key: string, value: string | string[]) { constructor(key: string, value: string | string[]) {
(this as unknown as Record<string, string | string[]>)[key] = value; (this as unknown as Record<string, string | string[]>)[key] = value;
@ -37,10 +54,13 @@ export class UrlEntry {
} }
public static forAttribute(condition: ConditionSelected, paramName: string) { public static forAttribute(condition: ConditionSelected, paramName: string) {
const inputType = getAtributeInputType(condition.conditionValue)
const tokenSlug = resolveTokenType(inputType || "")
return UrlEntry.fromConditionSelected( return UrlEntry.fromConditionSelected(
condition, condition,
paramName, paramName,
TokenType.ATTRIBUTE, tokenSlug,
); );
} }
@ -100,7 +120,15 @@ export class UrlToken {
} }
public isAttribute() { public isAttribute() {
return this.type === TokenType.ATTRIBUTE; const result = Object.entries(TokenType)
.find(([_, slug]) => slug === this.type)
return result && result[0].includes("ATTRIBUTE")
}
public hasDynamicValues() {
return TokenType.ATTRIBUTE_DROPDOWN === this.type
|| TokenType.ATTRIBUTE_MULTISELECT === this.type
} }
public isLoadable() { public isLoadable() {

View file

@ -1,3 +1,4 @@
import { ConditionItem } from "./FilterElement/ConditionOptions";
import { ItemOption } from "./FilterElement/ConditionValue"; import { ItemOption } from "./FilterElement/ConditionValue";
import { LeftOperand } from "./LeftOperandsProvider"; import { LeftOperand } from "./LeftOperandsProvider";
@ -58,18 +59,39 @@ export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = {
SWATCH: [{ type: "multiselect", label: "in", value: "input-2" }], SWATCH: [{ type: "multiselect", label: "in", value: "input-2" }],
}; };
export const getAtributeInputType = (item: ConditionItem | null) => {
const result = Object.entries(ATTRIBUTE_INPUT_TYPE_CONDITIONS)
.find(([_, value]) =>
value.find(entry => entry.type === item?.type && entry.label === item.label)
)
return result && result[0]
}
export type RowType = keyof typeof STATIC_CONDITIONS | "attribute" export type RowType = keyof typeof STATIC_CONDITIONS | "attribute"
export const createBooleanOptions = (): ItemOption[] => [ export const booleanOptionTrue = (type?: string) => ({
{ label: "Yes",
label: "Yes", value: "true",
value: "true", slug: "true",
slug: "true" ...({ type })
}, })
{
label: "No", export const booleanOptionFalse = (type?: string) => ({
value: "false", label: "No",
slug: "false" value: "false",
} slug: "false",
] ...({ type })
})
export const createBooleanOptions = (type?: string): ItemOption[] => [
booleanOptionTrue(type),
booleanOptionFalse(type)
]
export const createBoleanOption = (flag: boolean, type?: string): ItemOption => {
if (flag) return booleanOptionTrue(type)
return booleanOptionFalse(type)
}