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