Attach permission variables to all queries (#1000)
* [SALEOR-2190] Attach permission variables to all queries * Fix TS linter issues * Update package-lock
This commit is contained in:
parent
2cd4ea9529
commit
a7736e2bf9
24 changed files with 28496 additions and 968 deletions
|
@ -21,8 +21,15 @@
|
|||
"default": "array-simple"
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/ban-types": "error",
|
||||
"@typescript-eslint/class-name-casing": "error",
|
||||
"@typescript-eslint/ban-types": [
|
||||
"error",
|
||||
{
|
||||
"extendDefaults": true,
|
||||
"types": {
|
||||
"{}": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/consistent-type-assertions": "error",
|
||||
"@typescript-eslint/consistent-type-definitions": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": "off",
|
||||
|
@ -128,7 +135,7 @@
|
|||
"no-multiple-empty-lines": "off",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-redeclare": "off",
|
||||
"no-return-await": "error",
|
||||
"no-sequences": "error",
|
||||
"no-shadow": [
|
||||
|
@ -155,7 +162,7 @@
|
|||
"radix": "error",
|
||||
"simple-import-sort/sort": ["error"],
|
||||
"sort-imports": "off", // imports are handled by simple-import-sort/sort
|
||||
"sort-keys": "warn",
|
||||
"sort-keys": "off",
|
||||
"space-before-function-paren": "off",
|
||||
"spaced-comment": "error",
|
||||
"use-isnan": "error",
|
||||
|
|
|
@ -1879,10 +1879,6 @@
|
|||
"src_dot_components_dot_ErrorPage_dot_3182212440": {
|
||||
"string": "We've encountered a problem..."
|
||||
},
|
||||
"src_dot_components_dot_FileUpload_dot_3050254265": {
|
||||
"context": "upload file, button",
|
||||
"string": "Upload"
|
||||
},
|
||||
"src_dot_components_dot_FilterBar_dot_2173195312": {
|
||||
"context": "button",
|
||||
"string": "Delete Search"
|
||||
|
|
29224
package-lock.json
generated
29224
package-lock.json
generated
File diff suppressed because it is too large
Load diff
11
package.json
11
package.json
|
@ -26,8 +26,8 @@
|
|||
"@material-ui/icons": "^4.5.1",
|
||||
"@material-ui/styles": "^4.5.2",
|
||||
"@saleor/macaw-ui": "^0.1.1-9",
|
||||
"@types/faker": "^5.1.6",
|
||||
"@sentry/react": "^6.0.0",
|
||||
"@types/faker": "^5.1.6",
|
||||
"apollo": "^2.21.2",
|
||||
"apollo-cache-inmemory": "^1.6.5",
|
||||
"apollo-client": "^2.6.8",
|
||||
|
@ -45,7 +45,6 @@
|
|||
"editorjs-undo": "^0.1.4",
|
||||
"faker": "^5.1.0",
|
||||
"fast-array-diff": "^0.2.0",
|
||||
"fsevents": "^1.2.9",
|
||||
"fuzzaldrin": "^2.1.0",
|
||||
"graphql": "^14.4.2",
|
||||
"graphql-tag": "^2.11.0",
|
||||
|
@ -76,7 +75,7 @@
|
|||
"react-sortable-tree": "^2.6.2",
|
||||
"semver-compare": "^1.0.0",
|
||||
"slugify": "^1.4.6",
|
||||
"typescript": "^3.9.7",
|
||||
"typescript": "^4.2.3",
|
||||
"url-join": "^4.0.1",
|
||||
"use-react-router": "^1.0.7"
|
||||
},
|
||||
|
@ -91,7 +90,7 @@
|
|||
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
|
||||
"@babel/preset-env": "^7.5.4",
|
||||
"@babel/preset-react": "^7.7.4",
|
||||
"@babel/preset-typescript": "^7.7.4",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@babel/runtime": "^7.7.6",
|
||||
"@pollyjs/adapter-node-http": "^5.0.0",
|
||||
"@pollyjs/core": "^5.0.0",
|
||||
|
@ -123,8 +122,8 @@
|
|||
"@types/storybook__react": "^4.0.2",
|
||||
"@types/url-join": "^4.0.0",
|
||||
"@types/webappsec-credential-management": "^0.5.1",
|
||||
"@typescript-eslint/eslint-plugin": "^2.12.0",
|
||||
"@typescript-eslint/parser": "^2.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.16.1",
|
||||
"@typescript-eslint/parser": "^4.16.1",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"babel-jest": "^23.6.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
|
|
2
react-intl.d.ts
vendored
2
react-intl.d.ts
vendored
|
@ -13,7 +13,7 @@ declare module "react-intl" {
|
|||
MessageDescriptor
|
||||
>;
|
||||
type PrimitiveType = string | number | boolean | null | undefined | Date;
|
||||
type FormatXMLElementFn = (...args: any[]) => string | object;
|
||||
type FormatXMLElementFn = (...args: any[]) => string | {};
|
||||
export interface IntlFormatters
|
||||
extends Omit<ReactIntl.IntlFormatters, "formatMessage"> {
|
||||
formatMessage(
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
const useStyles = makeStyles(
|
||||
{
|
||||
fileUploadField: {
|
||||
display: "none"
|
||||
},
|
||||
root: {
|
||||
display: "flex"
|
||||
},
|
||||
textField: {
|
||||
flex: 1
|
||||
}
|
||||
},
|
||||
{ name: "FileUpload" }
|
||||
);
|
||||
|
||||
interface FileUploadProps {
|
||||
disabled?: boolean;
|
||||
name?: string;
|
||||
value?: any;
|
||||
onChange?(event: React.ChangeEvent<any>);
|
||||
}
|
||||
|
||||
const FileUpload: React.FC<FileUploadProps> = props => {
|
||||
const { disabled, name, value, onChange } = props;
|
||||
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<input
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
ref={ref => (this.upload = ref)}
|
||||
className={classes.fileUploadField}
|
||||
type="file"
|
||||
value={value}
|
||||
/>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
disabled={disabled}
|
||||
onChange={undefined}
|
||||
value={value}
|
||||
/>
|
||||
<Button disabled={disabled} onClick={() => this.upload.click()}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Upload"
|
||||
description="upload file, button"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
FileUpload.displayName = "FileUpload";
|
||||
export default FileUpload;
|
|
@ -1,2 +0,0 @@
|
|||
export { default } from "./FileUpload";
|
||||
export * from "./FileUpload";
|
|
@ -303,7 +303,7 @@ export const searchPageProps: SearchPageProps = {
|
|||
onSearchChange: () => undefined
|
||||
};
|
||||
|
||||
export const filterPageProps: FilterPageProps<string, object> = {
|
||||
export const filterPageProps: FilterPageProps<string, {}> = {
|
||||
...searchPageProps,
|
||||
...tabPageProps,
|
||||
filterOpts: {},
|
||||
|
|
|
@ -4,20 +4,28 @@ import gql from "graphql-tag";
|
|||
import { Home, HomeVariables } from "./types/Home";
|
||||
|
||||
const home = gql`
|
||||
query Home($channel: String!) {
|
||||
salesToday: ordersTotal(period: TODAY, channel: $channel) {
|
||||
query Home(
|
||||
$channel: String!
|
||||
$PERMISSION_MANAGE_PRODUCTS: Boolean!
|
||||
$PERMISSION_MANAGE_ORDERS: Boolean!
|
||||
) {
|
||||
salesToday: ordersTotal(period: TODAY, channel: $channel)
|
||||
@include(if: $PERMISSION_MANAGE_ORDERS) {
|
||||
gross {
|
||||
amount
|
||||
currency
|
||||
}
|
||||
}
|
||||
ordersToday: orders(created: TODAY, channel: $channel) {
|
||||
ordersToday: orders(created: TODAY, channel: $channel)
|
||||
@include(if: $PERMISSION_MANAGE_ORDERS) {
|
||||
totalCount
|
||||
}
|
||||
ordersToFulfill: orders(status: READY_TO_FULFILL, channel: $channel) {
|
||||
ordersToFulfill: orders(status: READY_TO_FULFILL, channel: $channel)
|
||||
@include(if: $PERMISSION_MANAGE_ORDERS) {
|
||||
totalCount
|
||||
}
|
||||
ordersToCapture: orders(status: READY_TO_CAPTURE, channel: $channel) {
|
||||
ordersToCapture: orders(status: READY_TO_CAPTURE, channel: $channel)
|
||||
@include(if: $PERMISSION_MANAGE_ORDERS) {
|
||||
totalCount
|
||||
}
|
||||
productsOutOfStock: products(
|
||||
|
@ -30,7 +38,7 @@ const home = gql`
|
|||
period: TODAY
|
||||
first: 5
|
||||
channel: $channel
|
||||
) {
|
||||
) @include(if: $PERMISSION_MANAGE_PRODUCTS) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
|
@ -57,7 +65,8 @@ const home = gql`
|
|||
}
|
||||
}
|
||||
}
|
||||
activities: homepageEvents(last: 10) {
|
||||
activities: homepageEvents(last: 10)
|
||||
@include(if: $PERMISSION_MANAGE_ORDERS) {
|
||||
edges {
|
||||
node {
|
||||
amount
|
||||
|
|
|
@ -136,4 +136,6 @@ export interface Home {
|
|||
|
||||
export interface HomeVariables {
|
||||
channel: string;
|
||||
PERMISSION_MANAGE_PRODUCTS: boolean;
|
||||
PERMISSION_MANAGE_ORDERS: boolean;
|
||||
}
|
||||
|
|
|
@ -26,10 +26,10 @@ const HomeSection = () => {
|
|||
|
||||
return (
|
||||
<HomePage
|
||||
activities={data?.activities.edges.map(edge => edge.node).reverse()}
|
||||
orders={data?.ordersToday.totalCount}
|
||||
sales={data?.salesToday.gross}
|
||||
topProducts={data?.productTopToday.edges.map(edge => edge.node)}
|
||||
activities={data?.activities?.edges.map(edge => edge.node).reverse()}
|
||||
orders={data?.ordersToday?.totalCount}
|
||||
sales={data?.salesToday?.gross}
|
||||
topProducts={data?.productTopToday?.edges.map(edge => edge.node)}
|
||||
onProductClick={(productId, variantId) =>
|
||||
navigate(productVariantEditUrl(productId, variantId))
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ const HomeSection = () => {
|
|||
})
|
||||
)
|
||||
}
|
||||
ordersToCapture={data?.ordersToCapture.totalCount}
|
||||
ordersToFulfill={data?.ordersToFulfill.totalCount}
|
||||
ordersToCapture={data?.ordersToCapture?.totalCount}
|
||||
ordersToFulfill={data?.ordersToFulfill?.totalCount}
|
||||
productsOutOfStock={data?.productsOutOfStock.totalCount}
|
||||
userName={getUserName(user, true)}
|
||||
userPermissions={user?.userPermissions}
|
||||
|
|
|
@ -6,10 +6,33 @@ import { useEffect } from "react";
|
|||
import { QueryResult, useQuery as useBaseQuery } from "react-apollo";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { User_userPermissions } from "../fragments/types/User";
|
||||
import { PrefixedPermissions } from "../types/extendedTypes";
|
||||
import { PermissionEnum } from "../types/globalTypes";
|
||||
import useAppState from "./useAppState";
|
||||
import useNotifier from "./useNotifier";
|
||||
import useUser from "./useUser";
|
||||
|
||||
const getPermissionKey = (permission: string) =>
|
||||
`PERMISSION_${permission}` as PrefixedPermissions;
|
||||
|
||||
const allPermissions = Object.keys(PermissionEnum).reduce(
|
||||
(prev, code) => ({
|
||||
...prev,
|
||||
[getPermissionKey(code)]: false
|
||||
}),
|
||||
{} as Record<PrefixedPermissions, boolean>
|
||||
);
|
||||
|
||||
const getUserPermissions = (userPermissions: User_userPermissions[]) =>
|
||||
userPermissions.reduce(
|
||||
(prev, permission) => ({
|
||||
...prev,
|
||||
[getPermissionKey(permission.code)]: true
|
||||
}),
|
||||
{} as Record<PrefixedPermissions, boolean>
|
||||
);
|
||||
|
||||
export interface LoadMore<TData, TVariables> {
|
||||
loadMore: (
|
||||
mergeFunc: (prev: TData, next: TData) => TData,
|
||||
|
@ -25,7 +48,7 @@ type UseQueryOpts<TVariables> = Partial<{
|
|||
variables: TVariables;
|
||||
}>;
|
||||
type UseQueryHook<TData, TVariables> = (
|
||||
opts: UseQueryOpts<TVariables>
|
||||
opts: UseQueryOpts<Omit<TVariables, PrefixedPermissions>>
|
||||
) => UseQueryResult<TData, TVariables>;
|
||||
|
||||
function makeQuery<TData, TVariables>(
|
||||
|
@ -40,6 +63,15 @@ function makeQuery<TData, TVariables>(
|
|||
const intl = useIntl();
|
||||
const [, dispatchAppState] = useAppState();
|
||||
const user = useUser();
|
||||
const userPermissions = getUserPermissions(
|
||||
user.user?.userPermissions || []
|
||||
);
|
||||
|
||||
const variablesWithPermissions = {
|
||||
...variables,
|
||||
...allPermissions,
|
||||
...userPermissions
|
||||
};
|
||||
|
||||
const queryData = useBaseQuery(query, {
|
||||
context: {
|
||||
|
@ -56,7 +88,7 @@ function makeQuery<TData, TVariables>(
|
|||
intl
|
||||
),
|
||||
skip,
|
||||
variables
|
||||
variables: variablesWithPermissions
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -82,7 +114,7 @@ function makeQuery<TData, TVariables>(
|
|||
}
|
||||
return mergeFunc(previousResults, fetchMoreResult);
|
||||
},
|
||||
variables: { ...variables, ...extraVariables }
|
||||
variables: { ...variablesWithPermissions, ...extraVariables }
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
@ -3,16 +3,16 @@ import { removeAtIndex } from "@saleor/utils/lists";
|
|||
import useStateFromProps from "./useStateFromProps";
|
||||
|
||||
export type FormsetChange<TValue = any> = (id: string, value: TValue) => void;
|
||||
export interface FormsetAtomicData<TData = object, TValue = any> {
|
||||
export interface FormsetAtomicData<TData = {}, TValue = any> {
|
||||
data: TData;
|
||||
id: string;
|
||||
label: string;
|
||||
value: TValue;
|
||||
}
|
||||
export type FormsetData<TData = object, TValue = any> = Array<
|
||||
export type FormsetData<TData = {}, TValue = any> = Array<
|
||||
FormsetAtomicData<TData, TValue>
|
||||
>;
|
||||
export interface UseFormsetOutput<TData = object, TValue = any> {
|
||||
export interface UseFormsetOutput<TData = {}, TValue = any> {
|
||||
add: (data: FormsetAtomicData<TData, TValue>) => void;
|
||||
change: FormsetChange<TValue>;
|
||||
data: FormsetData<TData, TValue>;
|
||||
|
@ -21,7 +21,7 @@ export interface UseFormsetOutput<TData = object, TValue = any> {
|
|||
set: (data: FormsetData<TData, TValue>) => void;
|
||||
remove: (id: string) => void;
|
||||
}
|
||||
function useFormset<TData = object, TValue = any>(
|
||||
function useFormset<TData = {}, TValue = any>(
|
||||
initial: FormsetData<TData, TValue>
|
||||
): UseFormsetOutput<TData, TValue> {
|
||||
const [data, setData] = useStateFromProps<FormsetData<TData, TValue>>(
|
||||
|
|
|
@ -245,7 +245,7 @@ export function only<T>(obj: T, key: keyof T): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
export function empty(obj: object): boolean {
|
||||
export function empty(obj: {}): boolean {
|
||||
return Object.keys(obj).every(key => obj[key] === undefined);
|
||||
}
|
||||
|
||||
|
@ -376,10 +376,7 @@ export function generateCode(charNum: number) {
|
|||
return result;
|
||||
}
|
||||
|
||||
export function findInEnum<TEnum extends object>(
|
||||
needle: string,
|
||||
haystack: TEnum
|
||||
) {
|
||||
export function findInEnum<TEnum extends {}>(needle: string, haystack: TEnum) {
|
||||
const match = Object.keys(haystack).find(key => key === needle);
|
||||
if (!!match) {
|
||||
return haystack[needle as keyof TEnum];
|
||||
|
@ -388,7 +385,7 @@ export function findInEnum<TEnum extends object>(
|
|||
throw new Error(`Key ${needle} not found in enum`);
|
||||
}
|
||||
|
||||
export function findValueInEnum<TEnum extends object>(
|
||||
export function findValueInEnum<TEnum extends {}>(
|
||||
needle: string,
|
||||
haystack: TEnum
|
||||
): TEnum[keyof TEnum] {
|
||||
|
|
|
@ -9,7 +9,6 @@ import TableHead from "@material-ui/core/TableHead";
|
|||
import TableRow from "@material-ui/core/TableRow";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { CSSProperties } from "@material-ui/styles";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Money from "@saleor/components/Money";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
|
@ -25,7 +24,7 @@ import { OrderRefundFormData } from "../OrderRefundPage/form";
|
|||
|
||||
const useStyles = makeStyles(
|
||||
theme => {
|
||||
const inputPadding: CSSProperties = {
|
||||
const inputPadding = {
|
||||
paddingBottom: theme.spacing(2),
|
||||
paddingTop: theme.spacing(2)
|
||||
};
|
||||
|
@ -84,7 +83,7 @@ const OrderRefundFulfilledProducts: React.FC<OrderRefundFulfilledProductsProps>
|
|||
onRefundedProductQuantityChange,
|
||||
onSetMaximalQuantities
|
||||
} = props;
|
||||
const classes = useStyles(props);
|
||||
const classes = useStyles({});
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
|
|
|
@ -9,7 +9,6 @@ import TableHead from "@material-ui/core/TableHead";
|
|||
import TableRow from "@material-ui/core/TableRow";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { CSSProperties } from "@material-ui/styles";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Money from "@saleor/components/Money";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
|
@ -24,7 +23,7 @@ import { OrderRefundFormData } from "../OrderRefundPage/form";
|
|||
|
||||
const useStyles = makeStyles(
|
||||
theme => {
|
||||
const inputPadding: CSSProperties = {
|
||||
const inputPadding = {
|
||||
paddingBottom: theme.spacing(2),
|
||||
paddingTop: theme.spacing(2)
|
||||
};
|
||||
|
@ -77,7 +76,7 @@ const OrderRefundUnfulfilledProducts: React.FC<OrderRefundUnfulfilledProductsPro
|
|||
onRefundedProductQuantityChange,
|
||||
onSetMaximalQuantities
|
||||
} = props;
|
||||
const classes = useStyles(props);
|
||||
const classes = useStyles({});
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import FileUpload from "@saleor/components/FileUpload";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import Decorator from "../../Decorator";
|
||||
|
||||
storiesOf("Components / FileUpload", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <FileUpload />)
|
||||
.add("other", () => <FileUpload />);
|
|
@ -96,7 +96,7 @@ export interface SearchProps {
|
|||
export interface SearchPageProps extends SearchProps {
|
||||
initialSearch: string;
|
||||
}
|
||||
export interface FilterPageProps<TKeys extends string, TOpts extends object>
|
||||
export interface FilterPageProps<TKeys extends string, TOpts extends {}>
|
||||
extends FilterProps<TKeys>,
|
||||
SearchPageProps,
|
||||
TabPageProps {
|
||||
|
|
3
src/types/extendedTypes.ts
Normal file
3
src/types/extendedTypes.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { PermissionEnum } from "./globalTypes";
|
||||
|
||||
export type PrefixedPermissions = `PERMISSION_${PermissionEnum}`;
|
|
@ -3,9 +3,9 @@ import { findValueInEnum } from "@saleor/misc";
|
|||
import isArray from "lodash-es/isArray";
|
||||
|
||||
function createFilterUtils<
|
||||
TQueryParams extends object,
|
||||
TFilters extends object
|
||||
>(filters: object) {
|
||||
TQueryParams extends {},
|
||||
TFilters extends {}
|
||||
>(filters: {}) {
|
||||
function getActiveFilters(params: TQueryParams): TFilters {
|
||||
return Object.keys(params)
|
||||
.filter(key => Object.keys(filters).includes(key))
|
||||
|
@ -35,11 +35,11 @@ export function dedupeFilter<T>(array: T[]): T[] {
|
|||
|
||||
export type GetFilterQueryParam<
|
||||
TFilterKeys extends string,
|
||||
TFilters extends object
|
||||
> = (filter: IFilterElement<TFilterKeys>, params?: object) => TFilters;
|
||||
TFilters extends {}
|
||||
> = (filter: IFilterElement<TFilterKeys>, params?: {}) => TFilters;
|
||||
export function getFilterQueryParams<
|
||||
TFilterKeys extends string,
|
||||
TUrlFilters extends object
|
||||
TUrlFilters extends {}
|
||||
>(
|
||||
filter: IFilter<TFilterKeys>,
|
||||
getFilterQueryParam: GetFilterQueryParam<TFilterKeys, TUrlFilters>
|
||||
|
@ -86,7 +86,7 @@ export function getSingleValueQueryParam<
|
|||
export function getSingleEnumValueQueryParam<
|
||||
TKey extends string,
|
||||
TUrlKey extends string,
|
||||
TEnum extends object
|
||||
TEnum extends {}
|
||||
>(param: IFilterElement<TKey>, key: TUrlKey, haystack: TEnum) {
|
||||
const { active, value } = param;
|
||||
|
||||
|
@ -104,7 +104,7 @@ export function getSingleEnumValueQueryParam<
|
|||
export function getMultipleEnumValueQueryParam<
|
||||
TKey extends string,
|
||||
TUrlKey extends string,
|
||||
TEnum extends object
|
||||
TEnum extends {}
|
||||
>(param: IFilterElement<TKey>, key: TUrlKey, haystack: TEnum) {
|
||||
const { active, value } = param;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ type CreateFilterHandlers<TFilterKeys extends string> = [
|
|||
|
||||
function createFilterHandlers<
|
||||
TFilterKeys extends string,
|
||||
TFilters extends object
|
||||
TFilters extends {}
|
||||
>(opts: {
|
||||
getFilterQueryParam: GetFilterQueryParam<TFilterKeys, TFilters>;
|
||||
navigate: UseNavigatorResult;
|
||||
|
|
|
@ -16,7 +16,7 @@ describe("Multiple file upload handler", () => {
|
|||
onStart: jest.fn()
|
||||
};
|
||||
const handle = createMultiFileUploadHandler(() => {
|
||||
const promise = new Promise(resolve => {
|
||||
const promise = new Promise<void>(resolve => {
|
||||
expect(cbs.onBeforeUpload).toBeCalledTimes(
|
||||
cbs.onAfterUpload.mock.calls.length + 1
|
||||
);
|
||||
|
@ -46,7 +46,7 @@ describe("Multiple file upload handler", () => {
|
|||
onStart: jest.fn()
|
||||
};
|
||||
const handle = createMultiFileUploadHandler((_, fileIndex) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
const promise = new Promise<void>((resolve, reject) => {
|
||||
if (fileIndex === 2) {
|
||||
reject();
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import isArray from "lodash-es/isArray";
|
||||
import { stringify } from "qs";
|
||||
|
||||
export function stringifyQs(params: object): string {
|
||||
export function stringifyQs(params: {}): string {
|
||||
return stringify(params, {
|
||||
indices: false
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { IFilter } from "@saleor/components/Filter";
|
||||
import clone from "lodash-es/clone";
|
||||
|
||||
export function getExistingKeys(o: object): string[] {
|
||||
export function getExistingKeys(o: {}): string[] {
|
||||
return Object.keys(o).filter(key => o[key] !== undefined && o[key] !== null);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue