Copy filters automatically to GraphiQL playground (#3385)
This commit is contained in:
parent
9690313d16
commit
82d15f4441
13 changed files with 287 additions and 45 deletions
|
@ -26,6 +26,7 @@ All notable, unreleased changes to this project will be documented in this file.
|
|||
- Add DevMode panel (trigger: CMD+') - #3333 by @zaiste
|
||||
- Migrate to `es2020` for TypeScript - #3386 by @zaiste
|
||||
- Fix styling for GraphiQL on the webhook page - #3389 by @zaiste
|
||||
- Copy filters automatically to GraphiQL playground - #3385 by @zaiste
|
||||
|
||||
## 3.4
|
||||
|
||||
|
|
|
@ -8010,6 +8010,10 @@
|
|||
"vEYtiq": {
|
||||
"string": "Category Name"
|
||||
},
|
||||
"vEwjub": {
|
||||
"context": "button",
|
||||
"string": "Open in GraphiQL"
|
||||
},
|
||||
"vM9quW": {
|
||||
"context": "order payment",
|
||||
"string": "Paid with Gift Card"
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import useAppState from "@dashboard/hooks/useAppState";
|
||||
import { DevModeQuery } from "@dashboard/orders/queries";
|
||||
import { getFilterVariables } from "@dashboard/orders/views/OrderList/filters";
|
||||
import { LinearProgress } from "@material-ui/core";
|
||||
import { useActionBar } from "@saleor/macaw-ui";
|
||||
import { Box } from "@saleor/macaw-ui/next";
|
||||
import React, { useState } from "react";
|
||||
import { useLocation } from "react-router";
|
||||
|
||||
import { DevModePanel } from "../DevModePanel/DevModePanel";
|
||||
import { useDevModeContext } from "../DevModePanel/hooks";
|
||||
|
@ -11,6 +14,7 @@ import Navigator from "../Navigator";
|
|||
import { Sidebar } from "../Sidebar";
|
||||
import { contentMaxWidth } from "./consts";
|
||||
import { useStyles } from "./styles";
|
||||
import { extractQueryParams } from "./util";
|
||||
|
||||
interface AppLayoutProps {
|
||||
children: React.ReactNode;
|
||||
|
@ -23,9 +27,32 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
|||
const [appState] = useAppState();
|
||||
const [isNavigatorVisible, setNavigatorVisibility] = useState(false);
|
||||
|
||||
const { isDevModeVisible, setDevModeVisibility } = useDevModeContext();
|
||||
const {
|
||||
isDevModeVisible,
|
||||
setDevModeVisibility,
|
||||
setDevModeContent,
|
||||
setVariables,
|
||||
} = useDevModeContext();
|
||||
|
||||
useDevModeKeyTrigger(() => setDevModeVisibility(!isDevModeVisible));
|
||||
const params = extractQueryParams(useLocation().search);
|
||||
|
||||
useDevModeKeyTrigger(({ shift }) => {
|
||||
if (shift) {
|
||||
setDevModeContent(DevModeQuery);
|
||||
const variables = JSON.stringify(
|
||||
{
|
||||
filter: getFilterVariables(params),
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
setVariables(variables);
|
||||
} else {
|
||||
setDevModeContent("");
|
||||
setVariables("");
|
||||
}
|
||||
setDevModeVisibility(!isDevModeVisible);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
25
src/components/AppLayout/util.test.ts
Normal file
25
src/components/AppLayout/util.test.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { extractQueryParams } from "./util";
|
||||
|
||||
describe("extractQueryParams", () => {
|
||||
test("parses a query string with an explicitly indexed list into an object of key-value pairs", () => {
|
||||
const queryString =
|
||||
"q=apple&color[0]=red&color[1]=green&shape[]=round&shape[]=oval";
|
||||
const expected = {
|
||||
q: "apple",
|
||||
color: ["red", "green"],
|
||||
shape: ["round", "oval"],
|
||||
};
|
||||
expect(extractQueryParams(queryString)).toEqual(expected);
|
||||
});
|
||||
|
||||
test("parses a query string into an object of key-value pairs (overwrites non array elements!)", () => {
|
||||
const queryString =
|
||||
"q=apple&color=red&color=green&shape[]=round&shape[]=oval";
|
||||
const expected = {
|
||||
q: "apple",
|
||||
color: "green",
|
||||
shape: ["round", "oval"],
|
||||
};
|
||||
expect(extractQueryParams(queryString)).toEqual(expected);
|
||||
});
|
||||
});
|
23
src/components/AppLayout/util.ts
Normal file
23
src/components/AppLayout/util.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
export const extractQueryParams = (queryString: string) => {
|
||||
const urlSearchParams = new URLSearchParams(queryString);
|
||||
const queryParams = {};
|
||||
|
||||
urlSearchParams.forEach((value, key) => {
|
||||
const arrayKeyRegex = /^(.+)\[\d*\]$/;
|
||||
const match = key.match(arrayKeyRegex);
|
||||
|
||||
if (match) {
|
||||
const arrayKey = match[1];
|
||||
|
||||
if (!queryParams.hasOwnProperty(arrayKey)) {
|
||||
queryParams[arrayKey] = [];
|
||||
}
|
||||
|
||||
queryParams[arrayKey].push(value);
|
||||
} else {
|
||||
queryParams[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return queryParams;
|
||||
};
|
|
@ -1,10 +1,14 @@
|
|||
import { useEffect } from "react";
|
||||
|
||||
export const useDevModeKeyTrigger = (callback?: () => void) => {
|
||||
type DevModeKeyTriggerCallback = ({ shift }: { shift: boolean }) => void;
|
||||
|
||||
export const useDevModeKeyTrigger = (callback?: DevModeKeyTriggerCallback) => {
|
||||
useEffect(() => {
|
||||
const handler = (event: KeyboardEvent) => {
|
||||
if (event.metaKey && event.code === "Quote") {
|
||||
callback();
|
||||
if (event.shiftKey && event.metaKey && event.code === "Quote") {
|
||||
callback({ shift: true });
|
||||
} else if (event.metaKey && event.code === "Quote") {
|
||||
callback({ shift: false });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -9993,6 +9993,99 @@ export function useChannelUsabilityDataLazyQuery(baseOptions?: ApolloReactHooks.
|
|||
export type ChannelUsabilityDataQueryHookResult = ReturnType<typeof useChannelUsabilityDataQuery>;
|
||||
export type ChannelUsabilityDataLazyQueryHookResult = ReturnType<typeof useChannelUsabilityDataLazyQuery>;
|
||||
export type ChannelUsabilityDataQueryResult = Apollo.QueryResult<Types.ChannelUsabilityDataQuery, Types.ChannelUsabilityDataQueryVariables>;
|
||||
export const OrderDetailsGraphiQlDocument = gql`
|
||||
query OrderDetailsGraphiQL($id: ID!) {
|
||||
order(id: $id) {
|
||||
id
|
||||
number
|
||||
status
|
||||
isShippingRequired
|
||||
canFinalize
|
||||
created
|
||||
customerNote
|
||||
paymentStatus
|
||||
userEmail
|
||||
isPaid
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useOrderDetailsGraphiQlQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useOrderDetailsGraphiQlQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useOrderDetailsGraphiQlQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useOrderDetailsGraphiQlQuery({
|
||||
* variables: {
|
||||
* id: // value for 'id'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useOrderDetailsGraphiQlQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.OrderDetailsGraphiQlQuery, Types.OrderDetailsGraphiQlQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return ApolloReactHooks.useQuery<Types.OrderDetailsGraphiQlQuery, Types.OrderDetailsGraphiQlQueryVariables>(OrderDetailsGraphiQlDocument, options);
|
||||
}
|
||||
export function useOrderDetailsGraphiQlLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.OrderDetailsGraphiQlQuery, Types.OrderDetailsGraphiQlQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return ApolloReactHooks.useLazyQuery<Types.OrderDetailsGraphiQlQuery, Types.OrderDetailsGraphiQlQueryVariables>(OrderDetailsGraphiQlDocument, options);
|
||||
}
|
||||
export type OrderDetailsGraphiQlQueryHookResult = ReturnType<typeof useOrderDetailsGraphiQlQuery>;
|
||||
export type OrderDetailsGraphiQlLazyQueryHookResult = ReturnType<typeof useOrderDetailsGraphiQlLazyQuery>;
|
||||
export type OrderDetailsGraphiQlQueryResult = Apollo.QueryResult<Types.OrderDetailsGraphiQlQuery, Types.OrderDetailsGraphiQlQueryVariables>;
|
||||
export const DevModeRunDocument = gql`
|
||||
query DevModeRun($filter: OrderFilterInput, $sortBy: OrderSortingInput) {
|
||||
orders(first: 10, filter: $filter, sortBy: $sortBy) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
number
|
||||
status
|
||||
isShippingRequired
|
||||
canFinalize
|
||||
created
|
||||
customerNote
|
||||
paymentStatus
|
||||
userEmail
|
||||
isPaid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useDevModeRunQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useDevModeRunQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useDevModeRunQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useDevModeRunQuery({
|
||||
* variables: {
|
||||
* filter: // value for 'filter'
|
||||
* sortBy: // value for 'sortBy'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDevModeRunQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<Types.DevModeRunQuery, Types.DevModeRunQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return ApolloReactHooks.useQuery<Types.DevModeRunQuery, Types.DevModeRunQueryVariables>(DevModeRunDocument, options);
|
||||
}
|
||||
export function useDevModeRunLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.DevModeRunQuery, Types.DevModeRunQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return ApolloReactHooks.useLazyQuery<Types.DevModeRunQuery, Types.DevModeRunQueryVariables>(DevModeRunDocument, options);
|
||||
}
|
||||
export type DevModeRunQueryHookResult = ReturnType<typeof useDevModeRunQuery>;
|
||||
export type DevModeRunLazyQueryHookResult = ReturnType<typeof useDevModeRunLazyQuery>;
|
||||
export type DevModeRunQueryResult = Apollo.QueryResult<Types.DevModeRunQuery, Types.DevModeRunQueryVariables>;
|
||||
export const PageTypeUpdateDocument = gql`
|
||||
mutation PageTypeUpdate($id: ID!, $input: PageTypeUpdateInput!) {
|
||||
pageTypeUpdate(id: $id, input: $input) {
|
||||
|
|
|
@ -8640,6 +8640,21 @@ export type ChannelUsabilityDataQueryVariables = Exact<{
|
|||
|
||||
export type ChannelUsabilityDataQuery = { __typename: 'Query', products: { __typename: 'ProductCountableConnection', totalCount: number | null } | null };
|
||||
|
||||
export type OrderDetailsGraphiQlQueryVariables = Exact<{
|
||||
id: Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type OrderDetailsGraphiQlQuery = { __typename: 'Query', order: { __typename: 'Order', id: string, number: string, status: OrderStatus, isShippingRequired: boolean, canFinalize: boolean, created: any, customerNote: string, paymentStatus: PaymentChargeStatusEnum, userEmail: string | null, isPaid: boolean } | null };
|
||||
|
||||
export type DevModeRunQueryVariables = Exact<{
|
||||
filter?: InputMaybe<OrderFilterInput>;
|
||||
sortBy?: InputMaybe<OrderSortingInput>;
|
||||
}>;
|
||||
|
||||
|
||||
export type DevModeRunQuery = { __typename: 'Query', orders: { __typename: 'OrderCountableConnection', edges: Array<{ __typename: 'OrderCountableEdge', node: { __typename: 'Order', id: string, number: string, status: OrderStatus, isShippingRequired: boolean, canFinalize: boolean, created: any, customerNote: string, paymentStatus: PaymentChargeStatusEnum, userEmail: string | null, isPaid: boolean } }> } | null };
|
||||
|
||||
export type PageTypeUpdateMutationVariables = Exact<{
|
||||
id: Scalars['ID'];
|
||||
input: PageTypeUpdateInput;
|
||||
|
|
|
@ -78,6 +78,7 @@ const props: OrderListPageProps = {
|
|||
...sortPageProps.sort,
|
||||
sort: OrderListUrlSortField.number,
|
||||
},
|
||||
params: {},
|
||||
};
|
||||
|
||||
storiesOf("Orders / Order list", module)
|
||||
|
|
|
@ -7,11 +7,17 @@ import { LimitsInfo } from "@dashboard/components/AppLayout/LimitsInfo";
|
|||
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||
import { ButtonWithSelect } from "@dashboard/components/ButtonWithSelect";
|
||||
import CardMenu from "@dashboard/components/CardMenu";
|
||||
import { useDevModeContext } from "@dashboard/components/DevModePanel/hooks";
|
||||
import FilterBar from "@dashboard/components/FilterBar";
|
||||
import { ListPageLayout } from "@dashboard/components/Layouts";
|
||||
import { OrderListQuery, RefreshLimitsQuery } from "@dashboard/graphql";
|
||||
import { sectionNames } from "@dashboard/intl";
|
||||
import { OrderListUrlSortField } from "@dashboard/orders/urls";
|
||||
import { DevModeQuery } from "@dashboard/orders/queries";
|
||||
import {
|
||||
OrderListUrlQueryParams,
|
||||
OrderListUrlSortField,
|
||||
} from "@dashboard/orders/urls";
|
||||
import { getFilterVariables } from "@dashboard/orders/views/OrderList/filters";
|
||||
import {
|
||||
FilterPageProps,
|
||||
PageListProps,
|
||||
|
@ -40,6 +46,7 @@ export interface OrderListPageProps
|
|||
orders: RelayToFlat<OrderListQuery["orders"]>;
|
||||
onSettingsOpen: () => void;
|
||||
onAdd: () => void;
|
||||
params: OrderListUrlQueryParams;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
|
@ -65,6 +72,7 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
|||
onTabChange,
|
||||
onTabDelete,
|
||||
onTabSave,
|
||||
params,
|
||||
...listProps
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
@ -78,6 +86,24 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
|||
const extensionMenuItems = mapToMenuItems(ORDER_OVERVIEW_MORE_ACTIONS);
|
||||
const extensionCreateButtonItems = mapToMenuItems(ORDER_OVERVIEW_CREATE);
|
||||
|
||||
const context = useDevModeContext();
|
||||
|
||||
const openPlaygroundURL = () => {
|
||||
context.setDevModeContent(DevModeQuery);
|
||||
const variables = JSON.stringify(
|
||||
{
|
||||
filter: getFilterVariables(params),
|
||||
// TODO add sorting: Issue #3409
|
||||
// strange error when uncommenting this line
|
||||
// sortBy: getSortQueryVariables(params)
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
context.setVariables(variables);
|
||||
context.setDevModeVisibility(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<ListPageLayout>
|
||||
<TopNav title={intl.formatMessage(sectionNames.orders)}>
|
||||
|
@ -85,6 +111,14 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
|||
<CardMenu
|
||||
className={classes.settings}
|
||||
menuItems={[
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: "vEwjub",
|
||||
defaultMessage: "Open in GraphiQL",
|
||||
description: "button",
|
||||
}),
|
||||
onSelect: openPlaygroundURL,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: "WbV1Xm",
|
||||
|
|
|
@ -201,7 +201,8 @@ export const channelUsabilityData = gql`
|
|||
}
|
||||
`;
|
||||
|
||||
export const defaultGraphiQLQuery = `query OrderDetails($id: ID!) {
|
||||
export const defaultGraphiQLQuery = /* GraphQL */ `
|
||||
query OrderDetailsGraphiQL($id: ID!) {
|
||||
order(id: $id) {
|
||||
id
|
||||
number
|
||||
|
@ -214,4 +215,26 @@ export const defaultGraphiQLQuery = `query OrderDetails($id: ID!) {
|
|||
userEmail
|
||||
isPaid
|
||||
}
|
||||
}`;
|
||||
}
|
||||
`;
|
||||
|
||||
export const DevModeQuery = /* GraphQL */ `
|
||||
query DevModeRun($filter: OrderFilterInput, $sortBy: OrderSortingInput) {
|
||||
orders(first: 10, filter: $filter, sortBy: $sortBy) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
number
|
||||
status
|
||||
isShippingRequired
|
||||
canFinalize
|
||||
created
|
||||
customerNote
|
||||
paymentStatus
|
||||
userEmail
|
||||
isPaid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -93,11 +93,8 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
|
|||
|
||||
const currentTab = getFiltersCurrentTab(params, tabs);
|
||||
|
||||
const [
|
||||
changeFilters,
|
||||
resetFilters,
|
||||
handleSearchChange,
|
||||
] = createFilterHandlers({
|
||||
const [changeFilters, resetFilters, handleSearchChange] =
|
||||
createFilterHandlers({
|
||||
createUrl: orderListUrl,
|
||||
getFilterQueryParam,
|
||||
navigate,
|
||||
|
@ -178,6 +175,7 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
|
|||
tabs={getFilterTabs().map(tab => tab.name)}
|
||||
onAll={resetFilters}
|
||||
onSettingsOpen={() => navigate(orderSettingsPath)}
|
||||
params={params}
|
||||
/>
|
||||
<SaveFilterTabDialog
|
||||
open={params.action === "save-search"}
|
||||
|
|
|
@ -108,7 +108,7 @@ export function getFilterVariables(
|
|||
params: OrderListUrlFilters,
|
||||
): OrderFilterInput {
|
||||
return {
|
||||
channels: (params.channel as unknown) as string[],
|
||||
channels: params.channel as unknown as string[],
|
||||
created: getGteLteVariables({
|
||||
gte: params.createdFrom,
|
||||
lte: params.createdTo,
|
||||
|
@ -198,18 +198,12 @@ export function getFilterQueryParam(
|
|||
}
|
||||
}
|
||||
|
||||
export const {
|
||||
deleteFilterTab,
|
||||
getFilterTabs,
|
||||
saveFilterTab,
|
||||
} = createFilterTabUtils<OrderListUrlFilters>(ORDER_FILTERS_KEY);
|
||||
export const { deleteFilterTab, getFilterTabs, saveFilterTab } =
|
||||
createFilterTabUtils<OrderListUrlFilters>(ORDER_FILTERS_KEY);
|
||||
|
||||
export const {
|
||||
areFiltersApplied,
|
||||
getActiveFilters,
|
||||
getFiltersCurrentTab,
|
||||
} = createFilterUtils<OrderListUrlQueryParams, OrderListUrlFilters>({
|
||||
export const { areFiltersApplied, getActiveFilters, getFiltersCurrentTab } =
|
||||
createFilterUtils<OrderListUrlQueryParams, OrderListUrlFilters>({
|
||||
...OrderListUrlFiltersEnum,
|
||||
...OrderListUrlFiltersWithMultipleValues,
|
||||
...OrderListFitersWithKeyValueValues,
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue