Implement url management, clan up UrlEntry (#3858)

* UrlEntry clean up, fix types

* Changeset
This commit is contained in:
Patryk Andrzejewski 2023-07-05 13:28:46 +02:00 committed by GitHub
parent e37c8ce44c
commit 97e4401897
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 113 additions and 79 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---
Implement url management for filters, clean up types

6
package-lock.json generated
View file

@ -20767,8 +20767,8 @@
}, },
"node_modules/extend": { "node_modules/extend": {
"version": "3.0.2", "version": "3.0.2",
"license": "MIT", "devOptional": true,
"optional": true "license": "MIT"
}, },
"node_modules/extend-shallow": { "node_modules/extend-shallow": {
"version": "3.0.2", "version": "3.0.2",
@ -50194,7 +50194,7 @@
}, },
"extend": { "extend": {
"version": "3.0.2", "version": "3.0.2",
"optional": true "devOptional": true
}, },
"extend-shallow": { "extend-shallow": {
"version": "3.0.2", "version": "3.0.2",

View file

@ -20,7 +20,8 @@ import {
_GetProductTypesChoicesQueryVariables, _GetProductTypesChoicesQueryVariables,
} from "@dashboard/graphql"; } from "@dashboard/graphql";
import { ItemOption } from "../FilterElement/ConditionSelected"; import { ItemOption } from "../FilterElement/ConditionValue";
export interface Handler { export interface Handler {
client: ApolloClient<unknown>; client: ApolloClient<unknown>;

View file

@ -1,5 +1,5 @@
import { AttributeInputType } from "../FilterElement/ConditionOptions"; import { AttributeInputType } from "../FilterElement/ConditionOptions";
import { ItemOption } from "../FilterElement/ConditionSelected"; import { ItemOption } from "../FilterElement/ConditionValue";
import { UrlToken } from "../ValueProvider/UrlToken"; import { UrlToken } from "../ValueProvider/UrlToken";
interface AttributeDTO { interface AttributeDTO {

View file

@ -1,18 +1,6 @@
import { getDefaultByControlName } from "../controlsType"; import { getDefaultByControlName } from "../controlsType";
import { ConditionItem } from "./ConditionOptions"; import { ConditionItem } from "./ConditionOptions";
import { ConditionValue } from "./ConditionValue";
export interface ItemOption {
label: string;
value: string;
slug: string;
}
export type ConditionValue =
| ItemOption
| ItemOption[]
| string
| string[]
| [string, string];
export class ConditionSelected { export class ConditionSelected {

View file

@ -0,0 +1,25 @@
export interface ItemOption {
label: string;
value: string;
slug: string;
}
export type ConditionValue =
| ItemOption
| ItemOption[]
| string
| string[]
| [string, string];
export const slugFromConditionValue = (rawEntry: ConditionValue): string | string[] => {
if (typeof rawEntry === "string") {
return rawEntry;
}
if (Array.isArray(rawEntry)) {
return rawEntry.map(el => (typeof el === "string" ? el : el.slug));
}
return rawEntry.slug;
};

View file

@ -1,10 +1,11 @@
/* eslint-disable @typescript-eslint/member-ordering */ /* eslint-disable @typescript-eslint/member-ordering */
import { InitialStateResponse } from "../API/InitialStateResponse"; import { InitialStateResponse } from "../API/InitialStateResponse";
import { LeftOperand } from "./../useLeftOperands"; import { LeftOperand } from "./../useLeftOperands";
import { CONDITIONS, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken"; import { UrlEntry, UrlToken } from "./../ValueProvider/UrlToken";
import { Condition } from "./Condition"; import { Condition } from "./Condition";
import { ConditionItem, ConditionOptions } from "./ConditionOptions"; import { ConditionItem, ConditionOptions } from "./ConditionOptions";
import { ConditionSelected, ConditionValue, ItemOption } from "./ConditionSelected"; import { ConditionSelected } from "./ConditionSelected";
import { ConditionValue, ItemOption } from "./ConditionValue";
interface ExpressionValue { interface ExpressionValue {
value: string; value: string;
@ -12,30 +13,6 @@ interface ExpressionValue {
type: string; type: string;
} }
const createStaticEntry = (rawEntry: ConditionValue) => {
if (typeof rawEntry === "string") {
return rawEntry;
}
if (Array.isArray(rawEntry)) {
return rawEntry.map(el => (typeof el === "string" ? el : el.slug));
}
return rawEntry.slug;
};
const createAttributeEntry = (rawEntry: ConditionValue) => {
if (typeof rawEntry === "string") {
return rawEntry;
}
if (Array.isArray(rawEntry)) {
return rawEntry.map(el => (typeof el === "string" ? el : el.slug));
}
return rawEntry.slug;
};
export class FilterElement { export class FilterElement {
private constructor( private constructor(
public value: ExpressionValue, public value: ExpressionValue,
@ -119,24 +96,11 @@ export class FilterElement {
} }
public asUrlEntry(): UrlEntry { public asUrlEntry(): UrlEntry {
const { conditionValue } = this.condition.selected;
const conditionIndex = CONDITIONS.findIndex(
el => conditionValue && el === conditionValue.label,
);
if (this.isAttribute()) { if (this.isAttribute()) {
return { return UrlEntry.forAttribute(this.condition.selected, this.value.value)
[`a${conditionIndex}.${this.value.value}`]: createAttributeEntry(
this.condition.selected.value,
),
};
} }
return { return UrlEntry.forStatic(this.condition.selected, this.value.value)
[`s${conditionIndex}.${this.value.value}`]: createStaticEntry(
this.condition.selected.value,
),
};
} }
public static fromValueEntry(valueEntry: any) { public static fromValueEntry(valueEntry: any) {

View file

@ -6,7 +6,7 @@ import { useRef } from "react";
import { InitialStateResponse } from "../../API/InitialStateResponse"; import { InitialStateResponse } from "../../API/InitialStateResponse";
import { FilterElement } from "../../FilterElement"; import { FilterElement } from "../../FilterElement";
import { FilterContainer } from "../../useFilterContainer"; import { FilterContainer } from "../../useFilterContainer";
import { UrlToken } from "../UrlToken"; import { UrlEntry, UrlToken } from "../UrlToken";
import { import {
emptyFetchingParams, emptyFetchingParams,
FetchingParams, FetchingParams,
@ -38,7 +38,9 @@ const mapToTokens = (urlEntries: Array<ParsedQs | string>): TokenArray =>
return mapToTokens(entry); return mapToTokens(entry);
} }
return UrlToken.fromUrlEntry(entry); return UrlToken.fromUrlEntry(
UrlEntry.fromQs(entry)
);
}) as TokenArray; }) as TokenArray;
const tokenizeUrl = (urlParams: string) => { const tokenizeUrl = (urlParams: string) => {

View file

@ -1,46 +1,94 @@
// @ts-strict-ignore import { ParsedQs } from "qs";
import { ConditionSelected } from "../FilterElement/ConditionSelected";
import { slugFromConditionValue } from "../FilterElement/ConditionValue";
export const CONDITIONS = ["is", "equals", "in", "between", "lower", "greater"]; export const CONDITIONS = ["is", "equals", "in", "between", "lower", "greater"];
const STATIC_TO_LOAD = ["category", "collection", "channel", "producttype"]; const STATIC_TO_LOAD = ["category", "collection", "channel", "producttype"];
type TokenType = "a" | "s"; export const TokenType = {
ATTRIBUTE: "a",
STATIC: "s"
} as const
export type TokenTypeValue = (typeof TokenType)[keyof typeof TokenType]
// export type UrlEntry = Record<string, string | string[]>
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class UrlEntry { export class UrlEntry {
constructor(key: string, value: string | string[]) { constructor(key: string, value: string | string[]) {
this[key] = value; (this as unknown as Record<string, string | string[]>)[key] = value;
} }
public static fromQs(entry: ParsedQs) {
const key = Object.keys(entry)[0]
const value = entry[key] as string | string[]
return new UrlEntry(key, value)
}
public static forAttribute (condition: ConditionSelected, paramName: string) {
return UrlEntry.fromConditionSelected(condition, paramName, TokenType.ATTRIBUTE)
}
public static forStatic (condition: ConditionSelected, paramName: string) {
return UrlEntry.fromConditionSelected(condition, paramName, TokenType.STATIC)
}
public getInfo () {
const [key, value] = Object.entries(this)[0] as [
string,
string | string[],
];
const [identifier, entryName] = key.split(".");
const [type, control] = identifier.split("") as [TokenTypeValue, number];
const conditionKid = CONDITIONS[control]
return { key, value, entryName, type, conditionKid }
}
private static fromConditionSelected (
condition: ConditionSelected,
paramName: string,
tokenSlug: TokenTypeValue
) {
const { conditionValue } = condition;
const conditionIndex = CONDITIONS.findIndex(
el => conditionValue && el === conditionValue.label,
);
return new UrlEntry(
`${tokenSlug}${conditionIndex}.${paramName}`,
slugFromConditionValue(condition.value)
)
}
} }
export class UrlToken { export class UrlToken {
private constructor( private constructor(
public name: string, public name: string,
public value: string | string[], public value: string | string[],
public type: TokenType, public type: TokenTypeValue,
public conditionKind: string, public conditionKind: string,
) {} ) {}
public static fromUrlEntry(entry: UrlEntry) { public static fromUrlEntry(entry: UrlEntry) {
const [key, value] = Object.entries(entry)[0] as [ const {
string, entryName,
string | string[], value,
]; type,
const [identifier, entryName] = key.split("."); conditionKid
const [type, control] = identifier.split("") as [TokenType, string]; } = entry.getInfo()
return new UrlToken(entryName, value, type, CONDITIONS[control]); return new UrlToken(entryName, value, type, conditionKid);
} }
public isStatic() { public isStatic() {
return this.type === "s"; return this.type === TokenType.STATIC;
} }
public isAttribute() { public isAttribute() {
return this.type === "a"; return this.type === TokenType.ATTRIBUTE;
} }
public isLoadable() { public isLoadable() {

View file

@ -1,5 +1,6 @@
// @ts-strict-ignore // @ts-strict-ignore
import { ConditionValue } from "./FilterElement/ConditionSelected";
import { ConditionValue } from "./FilterElement/ConditionValue";
export const CONTROL_DEFAULTS = { export const CONTROL_DEFAULTS = {
text: "", text: "",

View file

@ -9,7 +9,7 @@ import {
getLeftOperatorOptions, getLeftOperatorOptions,
getRightOperatorOptionsByQuery, getRightOperatorOptionsByQuery,
} from "./API/getAPIOptions"; } from "./API/getAPIOptions";
import { ConditionValue } from "./FilterElement/ConditionSelected"; import { ConditionValue } from "./FilterElement/ConditionValue";
import { useFilterContainer } from "./useFilterContainer"; import { useFilterContainer } from "./useFilterContainer";
import { useLeftOperands } from "./useLeftOperands"; import { useLeftOperands } from "./useLeftOperands";
import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider"; import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider";

View file

@ -2,7 +2,7 @@
import { useState } from "react"; import { useState } from "react";
import { FilterElement } from "./FilterElement"; import { FilterElement } from "./FilterElement";
import { ConditionValue, ItemOption } from "./FilterElement/ConditionSelected"; import { ConditionValue, ItemOption } from "./FilterElement/ConditionValue";
export type FilterContainer = Array<string | FilterElement | FilterContainer>; export type FilterContainer = Array<string | FilterElement | FilterContainer>;