Cover attributes based on inputType (#3945)
* Cover attributes based on inputType * Changeset * Remove logs * Lint
This commit is contained in:
parent
9a3c9de817
commit
4e8942f90e
8 changed files with 119 additions and 21 deletions
5
.changeset/rude-walls-tell.md
Normal file
5
.changeset/rude-walls-tell.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"saleor-dashboard": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Cover attributes based on input type
|
|
@ -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[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
Loading…
Reference in a new issue