Enable save button on page pages (#2325)
* Enable save button on page edit pages * Update e2e page create tests * Update page create tests snapshots * Update changelog with enable save button * Update messages of pages views * Update page details messages
This commit is contained in:
parent
aceae75ce7
commit
43fb52bc56
19 changed files with 469 additions and 176 deletions
|
@ -13,6 +13,7 @@ All notable, unreleased changes to this project will be documented in this file.
|
||||||
- Handle form errors before product creation - #2299 by @orzechdev
|
- Handle form errors before product creation - #2299 by @orzechdev
|
||||||
- Fix no product error on unconfirmed order lines - #2324 by @orzechdev
|
- Fix no product error on unconfirmed order lines - #2324 by @orzechdev
|
||||||
- Enable save button on discount pages - #2319 by @orzechdev
|
- Enable save button on discount pages - #2319 by @orzechdev
|
||||||
|
- Enable save button on page pages - #2325 by @orzechdev
|
||||||
|
|
||||||
## 3.4
|
## 3.4
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export const PAGES_LIST = {
|
export const PAGES_LIST = {
|
||||||
createPageButton: '[data-test-id="create-page"]'
|
createPageButton: '[data-test-id="create-page"]',
|
||||||
|
dialogPageTypeInput: "[data-test-id='dialog-page-type']",
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,17 @@ export const attributesTypes = {
|
||||||
BOOLEAN: addBooleanAttributeValue,
|
BOOLEAN: addBooleanAttributeValue,
|
||||||
NUMERIC: addNumericAttributeValue,
|
NUMERIC: addNumericAttributeValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function fillUpPageTypeDialog({ pageTypeName }) {
|
||||||
|
const organization = {};
|
||||||
|
return cy
|
||||||
|
.fillAutocompleteSelect(PAGES_LIST.dialogPageTypeInput, pageTypeName)
|
||||||
|
.then(selected => {
|
||||||
|
organization.pageType = selected;
|
||||||
|
return organization;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function createPage({
|
export function createPage({
|
||||||
pageName,
|
pageName,
|
||||||
pageTypeName,
|
pageTypeName,
|
||||||
|
@ -52,6 +63,9 @@ function openCreatePageAndFillUpGeneralFields({
|
||||||
}) {
|
}) {
|
||||||
cy.visit(urlList.pages)
|
cy.visit(urlList.pages)
|
||||||
.get(PAGES_LIST.createPageButton)
|
.get(PAGES_LIST.createPageButton)
|
||||||
|
.click();
|
||||||
|
fillUpPageTypeDialog({ pageTypeName });
|
||||||
|
cy.get(BUTTON_SELECTORS.submit)
|
||||||
.click()
|
.click()
|
||||||
.get(PAGE_DETAILS.nameInput)
|
.get(PAGE_DETAILS.nameInput)
|
||||||
.type(pageName);
|
.type(pageName);
|
||||||
|
|
|
@ -2059,6 +2059,10 @@
|
||||||
"context": "invoice create date prefix",
|
"context": "invoice create date prefix",
|
||||||
"string": "created"
|
"string": "created"
|
||||||
},
|
},
|
||||||
|
"F0N1SC": {
|
||||||
|
"context": "dialog header",
|
||||||
|
"string": "Select a page type"
|
||||||
|
},
|
||||||
"F3Upht": {
|
"F3Upht": {
|
||||||
"string": "Product type deleted"
|
"string": "Product type deleted"
|
||||||
},
|
},
|
||||||
|
@ -2596,6 +2600,10 @@
|
||||||
"context": "section header",
|
"context": "section header",
|
||||||
"string": "You are about to install {name}"
|
"string": "You are about to install {name}"
|
||||||
},
|
},
|
||||||
|
"Id9vlh": {
|
||||||
|
"context": "page seo options description",
|
||||||
|
"string": "Add search engine title and description to make this page easier to find"
|
||||||
|
},
|
||||||
"IeoGgH": {
|
"IeoGgH": {
|
||||||
"context": "variant created success message",
|
"context": "variant created success message",
|
||||||
"string": "Variant created"
|
"string": "Variant created"
|
||||||
|
@ -4211,6 +4219,10 @@
|
||||||
"context": "dialog content",
|
"context": "dialog content",
|
||||||
"string": "Removed sale"
|
"string": "Removed sale"
|
||||||
},
|
},
|
||||||
|
"V45+rx": {
|
||||||
|
"context": "input label",
|
||||||
|
"string": "Page type"
|
||||||
|
},
|
||||||
"V8FhTt": {
|
"V8FhTt": {
|
||||||
"context": "collection label",
|
"context": "collection label",
|
||||||
"string": "Hidden"
|
"string": "Hidden"
|
||||||
|
@ -5890,9 +5902,6 @@
|
||||||
"context": "product availability",
|
"context": "product availability",
|
||||||
"string": "Hide in product listings"
|
"string": "Hide in product listings"
|
||||||
},
|
},
|
||||||
"jZbT0O": {
|
|
||||||
"string": "Add search engine title and description to make this page easier to find"
|
|
||||||
},
|
|
||||||
"jd/LWa": {
|
"jd/LWa": {
|
||||||
"string": "Voucher applies to all countries"
|
"string": "Voucher applies to all countries"
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,6 +35,7 @@ import { useIntl } from "react-intl";
|
||||||
import PageInfo from "../PageInfo";
|
import PageInfo from "../PageInfo";
|
||||||
import PageOrganizeContent from "../PageOrganizeContent";
|
import PageOrganizeContent from "../PageOrganizeContent";
|
||||||
import PageForm, { PageData, PageUpdateHandlers } from "./form";
|
import PageForm, { PageData, PageUpdateHandlers } from "./form";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
|
||||||
export interface PageDetailsPageProps {
|
export interface PageDetailsPageProps {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
@ -68,7 +69,7 @@ export interface PageDetailsPageProps {
|
||||||
|
|
||||||
const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
|
const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
|
||||||
loading,
|
loading,
|
||||||
errors,
|
errors: apiErrors,
|
||||||
page,
|
page,
|
||||||
pageTypes: pageTypeChoiceList,
|
pageTypes: pageTypeChoiceList,
|
||||||
referencePages,
|
referencePages,
|
||||||
|
@ -142,148 +143,136 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
|
||||||
{({
|
{({
|
||||||
change,
|
change,
|
||||||
data,
|
data,
|
||||||
|
validationErrors,
|
||||||
handlers,
|
handlers,
|
||||||
submit,
|
submit,
|
||||||
isSaveDisabled,
|
|
||||||
attributeRichTextGetters,
|
attributeRichTextGetters,
|
||||||
}) => (
|
}) => {
|
||||||
<Container>
|
const errors = [...apiErrors, ...validationErrors];
|
||||||
<Backlink href={pageListUrl()}>
|
|
||||||
{intl.formatMessage(sectionNames.pages)}
|
return (
|
||||||
</Backlink>
|
<Container>
|
||||||
<PageHeader
|
<Backlink href={pageListUrl()}>
|
||||||
title={
|
{intl.formatMessage(sectionNames.pages)}
|
||||||
!pageExists
|
</Backlink>
|
||||||
? intl.formatMessage({
|
<PageHeader
|
||||||
id: "gr53VQ",
|
title={
|
||||||
defaultMessage: "Create Page",
|
!pageExists ? intl.formatMessage(messages.title) : page?.title
|
||||||
description: "page header",
|
|
||||||
})
|
|
||||||
: page?.title
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Grid>
|
|
||||||
<div>
|
|
||||||
<PageInfo
|
|
||||||
data={data}
|
|
||||||
disabled={loading}
|
|
||||||
errors={errors}
|
|
||||||
onChange={change}
|
|
||||||
/>
|
|
||||||
<CardSpacer />
|
|
||||||
<SeoForm
|
|
||||||
errors={errors}
|
|
||||||
allowEmptySlug={!pageExists}
|
|
||||||
description={data.seoDescription}
|
|
||||||
disabled={loading}
|
|
||||||
descriptionPlaceholder={""} // TODO: Cast description to string and trim it
|
|
||||||
onChange={change}
|
|
||||||
slug={data.slug}
|
|
||||||
slugPlaceholder={data.title}
|
|
||||||
title={data.seoTitle}
|
|
||||||
titlePlaceholder={data.title}
|
|
||||||
helperText={intl.formatMessage({
|
|
||||||
id: "jZbT0O",
|
|
||||||
defaultMessage:
|
|
||||||
"Add search engine title and description to make this page easier to find",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<CardSpacer />
|
|
||||||
{data.attributes.length > 0 && (
|
|
||||||
<Attributes
|
|
||||||
attributes={data.attributes}
|
|
||||||
attributeValues={attributeValues}
|
|
||||||
disabled={loading}
|
|
||||||
loading={loading}
|
|
||||||
errors={errors}
|
|
||||||
onChange={handlers.selectAttribute}
|
|
||||||
onMultiChange={handlers.selectAttributeMulti}
|
|
||||||
onFileChange={handlers.selectAttributeFile}
|
|
||||||
onReferencesRemove={handlers.selectAttributeReference}
|
|
||||||
onReferencesAddClick={onAssignReferencesClick}
|
|
||||||
onReferencesReorder={handlers.reorderAttributeValue}
|
|
||||||
fetchAttributeValues={fetchAttributeValues}
|
|
||||||
fetchMoreAttributeValues={fetchMoreAttributeValues}
|
|
||||||
onAttributeSelectBlur={onAttributeSelectBlur}
|
|
||||||
richTextGetters={attributeRichTextGetters}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<CardSpacer />
|
|
||||||
<Metadata data={data} onChange={handlers.changeMetadata} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<VisibilityCard
|
|
||||||
data={data}
|
|
||||||
errors={errors}
|
|
||||||
disabled={loading}
|
|
||||||
messages={{
|
|
||||||
hiddenLabel: intl.formatMessage({
|
|
||||||
id: "/TK7QD",
|
|
||||||
defaultMessage: "Hidden",
|
|
||||||
description: "page label",
|
|
||||||
}),
|
|
||||||
hiddenSecondLabel: intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "GZgjK7",
|
|
||||||
defaultMessage: "will be visible from {date}",
|
|
||||||
description: "page",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: localizeDate(data.publicationDate),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
visibleLabel: intl.formatMessage({
|
|
||||||
id: "X26jCC",
|
|
||||||
defaultMessage: "Visible",
|
|
||||||
description: "page label",
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
onChange={change}
|
|
||||||
/>
|
|
||||||
<CardSpacer />
|
|
||||||
<PageOrganizeContent
|
|
||||||
data={data}
|
|
||||||
errors={errors}
|
|
||||||
disabled={loading}
|
|
||||||
pageTypes={pageTypes}
|
|
||||||
pageType={data.pageType}
|
|
||||||
pageTypeInputDisplayValue={data.pageType?.name || ""}
|
|
||||||
onPageTypeChange={handlers.selectPageType}
|
|
||||||
fetchPageTypes={fetchPageTypes}
|
|
||||||
fetchMorePageTypes={fetchMorePageTypes}
|
|
||||||
canChangeType={!page?.pageType}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
<Savebar
|
|
||||||
disabled={isSaveDisabled}
|
|
||||||
state={saveButtonBarState}
|
|
||||||
onCancel={() => navigate(pageListUrl())}
|
|
||||||
onDelete={page === null ? undefined : onRemove}
|
|
||||||
onSubmit={submit}
|
|
||||||
/>
|
|
||||||
{canOpenAssignReferencesAttributeDialog && (
|
|
||||||
<AssignAttributeValueDialog
|
|
||||||
entityType={getReferenceAttributeEntityTypeFromAttribute(
|
|
||||||
assignReferencesAttributeId,
|
|
||||||
data.attributes,
|
|
||||||
)}
|
|
||||||
confirmButtonState={"default"}
|
|
||||||
products={referenceProducts}
|
|
||||||
pages={referencePages}
|
|
||||||
hasMore={handlers.fetchMoreReferences?.hasMore}
|
|
||||||
open={canOpenAssignReferencesAttributeDialog}
|
|
||||||
onFetch={handlers.fetchReferences}
|
|
||||||
onFetchMore={handlers.fetchMoreReferences?.onFetchMore}
|
|
||||||
loading={handlers.fetchMoreReferences?.loading}
|
|
||||||
onClose={onCloseDialog}
|
|
||||||
onSubmit={attributeValues =>
|
|
||||||
handleAssignReferenceAttribute(attributeValues, data, handlers)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
<Grid>
|
||||||
</Container>
|
<div>
|
||||||
)}
|
<PageInfo
|
||||||
|
data={data}
|
||||||
|
disabled={loading}
|
||||||
|
errors={errors}
|
||||||
|
onChange={change}
|
||||||
|
/>
|
||||||
|
<CardSpacer />
|
||||||
|
<SeoForm
|
||||||
|
errors={errors}
|
||||||
|
allowEmptySlug={!pageExists}
|
||||||
|
description={data.seoDescription}
|
||||||
|
disabled={loading}
|
||||||
|
descriptionPlaceholder={""} // TODO: Cast description to string and trim it
|
||||||
|
onChange={change}
|
||||||
|
slug={data.slug}
|
||||||
|
slugPlaceholder={data.title}
|
||||||
|
title={data.seoTitle}
|
||||||
|
titlePlaceholder={data.title}
|
||||||
|
helperText={intl.formatMessage(
|
||||||
|
messages.seoOptionsDescription,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<CardSpacer />
|
||||||
|
{data.attributes.length > 0 && (
|
||||||
|
<Attributes
|
||||||
|
attributes={data.attributes}
|
||||||
|
attributeValues={attributeValues}
|
||||||
|
disabled={loading}
|
||||||
|
loading={loading}
|
||||||
|
errors={errors}
|
||||||
|
onChange={handlers.selectAttribute}
|
||||||
|
onMultiChange={handlers.selectAttributeMulti}
|
||||||
|
onFileChange={handlers.selectAttributeFile}
|
||||||
|
onReferencesRemove={handlers.selectAttributeReference}
|
||||||
|
onReferencesAddClick={onAssignReferencesClick}
|
||||||
|
onReferencesReorder={handlers.reorderAttributeValue}
|
||||||
|
fetchAttributeValues={fetchAttributeValues}
|
||||||
|
fetchMoreAttributeValues={fetchMoreAttributeValues}
|
||||||
|
onAttributeSelectBlur={onAttributeSelectBlur}
|
||||||
|
richTextGetters={attributeRichTextGetters}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<CardSpacer />
|
||||||
|
<Metadata data={data} onChange={handlers.changeMetadata} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<VisibilityCard
|
||||||
|
data={data}
|
||||||
|
errors={errors}
|
||||||
|
disabled={loading}
|
||||||
|
messages={{
|
||||||
|
hiddenLabel: intl.formatMessage(messages.hiddenLabel),
|
||||||
|
hiddenSecondLabel: intl.formatMessage(
|
||||||
|
messages.hiddenSecondLabel,
|
||||||
|
{
|
||||||
|
date: localizeDate(data.publicationDate),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
visibleLabel: intl.formatMessage(messages.visibleLabel),
|
||||||
|
}}
|
||||||
|
onChange={change}
|
||||||
|
/>
|
||||||
|
<CardSpacer />
|
||||||
|
<PageOrganizeContent
|
||||||
|
data={data}
|
||||||
|
errors={errors}
|
||||||
|
disabled={loading}
|
||||||
|
pageTypes={pageTypes}
|
||||||
|
pageType={data.pageType}
|
||||||
|
pageTypeInputDisplayValue={data.pageType?.name || ""}
|
||||||
|
onPageTypeChange={handlers.selectPageType}
|
||||||
|
fetchPageTypes={fetchPageTypes}
|
||||||
|
fetchMorePageTypes={fetchMorePageTypes}
|
||||||
|
canChangeType={!page?.pageType}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
<Savebar
|
||||||
|
disabled={loading}
|
||||||
|
state={saveButtonBarState}
|
||||||
|
onCancel={() => navigate(pageListUrl())}
|
||||||
|
onDelete={page === null ? undefined : onRemove}
|
||||||
|
onSubmit={submit}
|
||||||
|
/>
|
||||||
|
{canOpenAssignReferencesAttributeDialog && (
|
||||||
|
<AssignAttributeValueDialog
|
||||||
|
entityType={getReferenceAttributeEntityTypeFromAttribute(
|
||||||
|
assignReferencesAttributeId,
|
||||||
|
data.attributes,
|
||||||
|
)}
|
||||||
|
confirmButtonState={"default"}
|
||||||
|
products={referenceProducts}
|
||||||
|
pages={referencePages}
|
||||||
|
hasMore={handlers.fetchMoreReferences?.hasMore}
|
||||||
|
open={canOpenAssignReferencesAttributeDialog}
|
||||||
|
onFetch={handlers.fetchReferences}
|
||||||
|
onFetchMore={handlers.fetchMoreReferences?.onFetchMore}
|
||||||
|
loading={handlers.fetchMoreReferences?.loading}
|
||||||
|
onClose={onCloseDialog}
|
||||||
|
onSubmit={attributeValues =>
|
||||||
|
handleAssignReferenceAttribute(
|
||||||
|
attributeValues,
|
||||||
|
data,
|
||||||
|
handlers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}}
|
||||||
</PageForm>
|
</PageForm>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { useExitFormDialog } from "@saleor/components/Form/useExitFormDialog";
|
||||||
import { MetadataFormData } from "@saleor/components/Metadata";
|
import { MetadataFormData } from "@saleor/components/Metadata";
|
||||||
import {
|
import {
|
||||||
PageDetailsFragment,
|
PageDetailsFragment,
|
||||||
|
PageErrorWithAttributesFragment,
|
||||||
SearchPagesQuery,
|
SearchPagesQuery,
|
||||||
SearchPageTypesQuery,
|
SearchPageTypesQuery,
|
||||||
SearchProductsQuery,
|
SearchProductsQuery,
|
||||||
|
@ -39,6 +40,7 @@ import {
|
||||||
getAttributeInputFromPageType,
|
getAttributeInputFromPageType,
|
||||||
} from "@saleor/pages/utils/data";
|
} from "@saleor/pages/utils/data";
|
||||||
import { createPageTypeSelectHandler } from "@saleor/pages/utils/handlers";
|
import { createPageTypeSelectHandler } from "@saleor/pages/utils/handlers";
|
||||||
|
import { validatePageCreateData } from "@saleor/pages/utils/validation";
|
||||||
import { FetchMoreProps, RelayToFlat, ReorderEvent } from "@saleor/types";
|
import { FetchMoreProps, RelayToFlat, ReorderEvent } from "@saleor/types";
|
||||||
import getPublicationData from "@saleor/utils/data/getPublicationData";
|
import getPublicationData from "@saleor/utils/data/getPublicationData";
|
||||||
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
||||||
|
@ -47,7 +49,7 @@ import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTr
|
||||||
import { RichTextContext } from "@saleor/utils/richText/context";
|
import { RichTextContext } from "@saleor/utils/richText/context";
|
||||||
import { useMultipleRichText } from "@saleor/utils/richText/useMultipleRichText";
|
import { useMultipleRichText } from "@saleor/utils/richText/useMultipleRichText";
|
||||||
import useRichText from "@saleor/utils/richText/useRichText";
|
import useRichText from "@saleor/utils/richText/useRichText";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
export interface PageFormData extends MetadataFormData {
|
export interface PageFormData extends MetadataFormData {
|
||||||
isPublished: boolean;
|
isPublished: boolean;
|
||||||
|
@ -85,6 +87,7 @@ export interface UsePageUpdateFormOutput
|
||||||
extends CommonUseFormResultWithHandlers<PageData, PageUpdateHandlers>,
|
extends CommonUseFormResultWithHandlers<PageData, PageUpdateHandlers>,
|
||||||
RichTextProps {
|
RichTextProps {
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
|
validationErrors: PageErrorWithAttributesFragment[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UsePageUpdateFormRenderProps = Omit<
|
export type UsePageUpdateFormRenderProps = Omit<
|
||||||
|
@ -142,6 +145,9 @@ function usePageForm(
|
||||||
confirmLeave: true,
|
confirmLeave: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
const [validationErrors, setValidationErrors] = useState<
|
||||||
|
PageErrorWithAttributesFragment[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
const attributes = useFormset(
|
const attributes = useFormset(
|
||||||
pageExists
|
pageExists
|
||||||
|
@ -160,7 +166,11 @@ function usePageForm(
|
||||||
});
|
});
|
||||||
const attributesWithNewFileValue = useFormset<null, File>([]);
|
const attributesWithNewFileValue = useFormset<null, File>([]);
|
||||||
|
|
||||||
const { setExitDialogSubmitRef, setIsSubmitDisabled } = useExitFormDialog({
|
const {
|
||||||
|
setExitDialogSubmitRef,
|
||||||
|
setIsSubmitDisabled,
|
||||||
|
setIsDirty,
|
||||||
|
} = useExitFormDialog({
|
||||||
formId,
|
formId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -247,7 +257,15 @@ function usePageForm(
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = async (data: PageData) => {
|
const handleSubmit = async (data: PageData) => {
|
||||||
const errors = await onSubmit(data);
|
let errors = validatePageCreateData(data);
|
||||||
|
|
||||||
|
setValidationErrors(errors);
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
errors = await onSubmit(data);
|
||||||
|
|
||||||
if (!errors?.length && pageExists) {
|
if (!errors?.length && pageExists) {
|
||||||
attributesWithNewFileValue.set([]);
|
attributesWithNewFileValue.set([]);
|
||||||
|
@ -261,18 +279,34 @@ function usePageForm(
|
||||||
onSubmit: handleSubmit,
|
onSubmit: handleSubmit,
|
||||||
});
|
});
|
||||||
|
|
||||||
const submit = async () => handleFormSubmit(await getSubmitData());
|
const submit = async () => {
|
||||||
|
const errors = await handleFormSubmit(await getSubmitData());
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
setIsDirty(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
const valid = pageExists || !!opts.selectedPageType;
|
const valid = pageExists || !!opts.selectedPageType;
|
||||||
|
|
||||||
const isSaveDisabled = disabled || !valid;
|
const isSaveDisabled = disabled || !valid;
|
||||||
setIsSubmitDisabled(isSaveDisabled);
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
if (!pageExists) {
|
||||||
|
setIsDirty(true);
|
||||||
|
}
|
||||||
|
}, [isSaveDisabled]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data,
|
data,
|
||||||
|
validationErrors,
|
||||||
valid,
|
valid,
|
||||||
handlers: {
|
handlers: {
|
||||||
changeMetadata,
|
changeMetadata,
|
||||||
|
|
30
src/pages/components/PageDetailsPage/messages.ts
Normal file
30
src/pages/components/PageDetailsPage/messages.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
title: {
|
||||||
|
id: "gr53VQ",
|
||||||
|
defaultMessage: "Create Page",
|
||||||
|
description: "page header",
|
||||||
|
},
|
||||||
|
seoOptionsDescription: {
|
||||||
|
id: "Id9vlh",
|
||||||
|
defaultMessage:
|
||||||
|
"Add search engine title and description to make this page easier to find",
|
||||||
|
description: "page seo options description",
|
||||||
|
},
|
||||||
|
hiddenLabel: {
|
||||||
|
id: "/TK7QD",
|
||||||
|
defaultMessage: "Hidden",
|
||||||
|
description: "page label",
|
||||||
|
},
|
||||||
|
hiddenSecondLabel: {
|
||||||
|
id: "GZgjK7",
|
||||||
|
defaultMessage: "will be visible from {date}",
|
||||||
|
description: "page",
|
||||||
|
},
|
||||||
|
visibleLabel: {
|
||||||
|
id: "X26jCC",
|
||||||
|
defaultMessage: "Visible",
|
||||||
|
description: "page label",
|
||||||
|
},
|
||||||
|
});
|
|
@ -5,7 +5,6 @@ import PageHeader from "@saleor/components/PageHeader";
|
||||||
import { PageFragment } from "@saleor/graphql";
|
import { PageFragment } from "@saleor/graphql";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import {
|
import {
|
||||||
pageCreateUrl,
|
|
||||||
PageListUrlDialog,
|
PageListUrlDialog,
|
||||||
PageListUrlQueryParams,
|
PageListUrlQueryParams,
|
||||||
PageListUrlSortField,
|
PageListUrlSortField,
|
||||||
|
@ -28,11 +27,13 @@ export interface PageListPageProps
|
||||||
pages: PageFragment[];
|
pages: PageFragment[];
|
||||||
params: PageListUrlQueryParams;
|
params: PageListUrlQueryParams;
|
||||||
actionDialogOpts: PageListActionDialogOpts;
|
actionDialogOpts: PageListActionDialogOpts;
|
||||||
|
onAdd: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PageListPage: React.FC<PageListPageProps> = ({
|
const PageListPage: React.FC<PageListPageProps> = ({
|
||||||
params,
|
params,
|
||||||
actionDialogOpts,
|
actionDialogOpts,
|
||||||
|
onAdd,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -40,11 +41,7 @@ const PageListPage: React.FC<PageListPageProps> = ({
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.pages)}>
|
<PageHeader title={intl.formatMessage(sectionNames.pages)}>
|
||||||
<Button
|
<Button onClick={onAdd} variant="primary" data-test-id="create-page">
|
||||||
href={pageCreateUrl()}
|
|
||||||
variant="primary"
|
|
||||||
data-test-id="create-page"
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="AHRDWt"
|
id="AHRDWt"
|
||||||
defaultMessage="Create page"
|
defaultMessage="Create page"
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import Decorator from "@saleor/storybook/Decorator";
|
||||||
|
import { mapNodeToChoice } from "@saleor/utils/maps";
|
||||||
|
import { storiesOf } from "@storybook/react";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { pageTypesList } from "../../fixtures";
|
||||||
|
import PageTypePickerDialog, {
|
||||||
|
PageTypePickerDialogProps,
|
||||||
|
} from "./PageTypePickerDialog";
|
||||||
|
|
||||||
|
const pageTypes = mapNodeToChoice(pageTypesList);
|
||||||
|
|
||||||
|
const props: PageTypePickerDialogProps = {
|
||||||
|
pageTypes,
|
||||||
|
confirmButtonState: "default",
|
||||||
|
fetchPageTypes: () => undefined,
|
||||||
|
fetchMorePageTypes: {
|
||||||
|
hasMore: false,
|
||||||
|
loading: false,
|
||||||
|
onFetchMore: () => undefined,
|
||||||
|
},
|
||||||
|
onClose: () => undefined,
|
||||||
|
onConfirm: () => undefined,
|
||||||
|
open: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
storiesOf("Views / Pages / Page type dialog", module)
|
||||||
|
.addDecorator(Decorator)
|
||||||
|
.add("default", () => <PageTypePickerDialog {...props} />);
|
|
@ -0,0 +1,70 @@
|
||||||
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import SingleAutocompleteSelectField, {
|
||||||
|
SingleAutocompleteChoiceType,
|
||||||
|
} from "@saleor/components/SingleAutocompleteSelectField";
|
||||||
|
import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen";
|
||||||
|
import useStateFromProps from "@saleor/hooks/useStateFromProps";
|
||||||
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
|
import { FetchMoreProps } from "@saleor/types";
|
||||||
|
import React from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { messages } from "./messages";
|
||||||
|
|
||||||
|
export interface PageTypePickerDialogProps {
|
||||||
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
|
open: boolean;
|
||||||
|
pageTypes?: SingleAutocompleteChoiceType[];
|
||||||
|
fetchPageTypes: (data: string) => void;
|
||||||
|
fetchMorePageTypes: FetchMoreProps;
|
||||||
|
onClose: () => void;
|
||||||
|
onConfirm: (choice: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PageTypePickerDialog: React.FC<PageTypePickerDialogProps> = ({
|
||||||
|
confirmButtonState,
|
||||||
|
open,
|
||||||
|
pageTypes,
|
||||||
|
fetchPageTypes,
|
||||||
|
fetchMorePageTypes,
|
||||||
|
onClose,
|
||||||
|
onConfirm,
|
||||||
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const [choice, setChoice] = useStateFromProps("");
|
||||||
|
const pageTypeDisplayValue = pageTypes.find(
|
||||||
|
pageType => pageType.value === choice,
|
||||||
|
)?.label;
|
||||||
|
|
||||||
|
useModalDialogOpen(open, {
|
||||||
|
onClose: () => {
|
||||||
|
setChoice("");
|
||||||
|
fetchPageTypes("");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActionDialog
|
||||||
|
confirmButtonState={confirmButtonState}
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
onConfirm={() => onConfirm(choice)}
|
||||||
|
title={intl.formatMessage(messages.selectPageType)}
|
||||||
|
disabled={!choice}
|
||||||
|
>
|
||||||
|
<SingleAutocompleteSelectField
|
||||||
|
displayValue={pageTypeDisplayValue}
|
||||||
|
name="pageType"
|
||||||
|
label={intl.formatMessage(messages.pageType)}
|
||||||
|
choices={pageTypes}
|
||||||
|
value={choice}
|
||||||
|
onChange={e => setChoice(e.target.value)}
|
||||||
|
fetchChoices={fetchPageTypes}
|
||||||
|
data-test-id="dialog-page-type"
|
||||||
|
{...fetchMorePageTypes}
|
||||||
|
/>
|
||||||
|
</ActionDialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
PageTypePickerDialog.displayName = "PageTypePickerDialog";
|
||||||
|
export default PageTypePickerDialog;
|
2
src/pages/components/PageTypePickerDialog/index.ts
Normal file
2
src/pages/components/PageTypePickerDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./PageTypePickerDialog";
|
||||||
|
export { default } from "./PageTypePickerDialog";
|
14
src/pages/components/PageTypePickerDialog/messages.ts
Normal file
14
src/pages/components/PageTypePickerDialog/messages.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
pageType: {
|
||||||
|
id: "V45+rx",
|
||||||
|
defaultMessage: "Page type",
|
||||||
|
description: "input label",
|
||||||
|
},
|
||||||
|
selectPageType: {
|
||||||
|
id: "F0N1SC",
|
||||||
|
defaultMessage: "Select a page type",
|
||||||
|
description: "dialog header",
|
||||||
|
},
|
||||||
|
});
|
|
@ -3,6 +3,7 @@ import {
|
||||||
PageDetailsFragment,
|
PageDetailsFragment,
|
||||||
PageFragment,
|
PageFragment,
|
||||||
} from "@saleor/graphql";
|
} from "@saleor/graphql";
|
||||||
|
import { PageType } from "@saleor/sdk/dist/apollo/types";
|
||||||
|
|
||||||
import * as richTextEditorFixtures from "../components/RichTextEditor/fixtures.json";
|
import * as richTextEditorFixtures from "../components/RichTextEditor/fixtures.json";
|
||||||
|
|
||||||
|
@ -440,3 +441,18 @@ export const page: PageDetailsFragment = {
|
||||||
slug: "about",
|
slug: "about",
|
||||||
title: "About",
|
title: "About",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const pageTypesList: Array<Pick<PageType, "id" | "name">> = [
|
||||||
|
{
|
||||||
|
id: "1111ZHVjdFR5cGU6Nw==",
|
||||||
|
name: "General",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2222ZHVjdFR5cGU6Nw==",
|
||||||
|
name: "Subpages",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3333ZHVjdFR5cGU6Nw==",
|
||||||
|
name: "Blog",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { Route, RouteComponentProps, Switch } from "react-router-dom";
|
||||||
import { WindowTitle } from "../components/WindowTitle";
|
import { WindowTitle } from "../components/WindowTitle";
|
||||||
import {
|
import {
|
||||||
pageCreatePath,
|
pageCreatePath,
|
||||||
|
PageCreateUrlQueryParams,
|
||||||
pageListPath,
|
pageListPath,
|
||||||
PageListUrlQueryParams,
|
PageListUrlQueryParams,
|
||||||
PageListUrlSortField,
|
PageListUrlSortField,
|
||||||
|
@ -30,7 +31,7 @@ const PageList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
|
||||||
|
|
||||||
const PageCreate: React.FC<RouteComponentProps<any>> = ({ match }) => {
|
const PageCreate: React.FC<RouteComponentProps<any>> = ({ match }) => {
|
||||||
const qs = parseQs(location.search.substr(1));
|
const qs = parseQs(location.search.substr(1));
|
||||||
const params: PageUrlQueryParams = qs;
|
const params: PageCreateUrlQueryParams = qs;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageCreateComponent
|
<PageCreateComponent
|
||||||
|
|
|
@ -20,6 +20,7 @@ export type PageListUrlDialog =
|
||||||
| "publish"
|
| "publish"
|
||||||
| "unpublish"
|
| "unpublish"
|
||||||
| "remove"
|
| "remove"
|
||||||
|
| "create-page"
|
||||||
| TabActionDialog;
|
| TabActionDialog;
|
||||||
export enum PageListUrlSortField {
|
export enum PageListUrlSortField {
|
||||||
title = "title",
|
title = "title",
|
||||||
|
@ -49,10 +50,16 @@ export const pageListUrl = (params?: PageListUrlQueryParams) =>
|
||||||
|
|
||||||
export const pagePath = (id: string) => urlJoin(pagesSection, id);
|
export const pagePath = (id: string) => urlJoin(pagesSection, id);
|
||||||
export type PageUrlDialog = "remove" | "assign-attribute-value";
|
export type PageUrlDialog = "remove" | "assign-attribute-value";
|
||||||
|
export interface PageCreateUrlPageType {
|
||||||
|
"page-type-id"?: string;
|
||||||
|
}
|
||||||
export type PageUrlQueryParams = Dialog<PageUrlDialog> & SingleAction;
|
export type PageUrlQueryParams = Dialog<PageUrlDialog> & SingleAction;
|
||||||
|
export type PageCreateUrlQueryParams = Dialog<PageUrlDialog> &
|
||||||
|
SingleAction &
|
||||||
|
PageCreateUrlPageType;
|
||||||
export const pageUrl = (id: string, params?: PageUrlQueryParams) =>
|
export const pageUrl = (id: string, params?: PageUrlQueryParams) =>
|
||||||
pagePath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
pagePath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||||
|
|
||||||
export const pageCreatePath = urlJoin(pagesSection, "add");
|
export const pageCreatePath = urlJoin(pagesSection, "add");
|
||||||
export const pageCreateUrl = (params?: PageUrlQueryParams) =>
|
export const pageCreateUrl = (params?: PageCreateUrlQueryParams) =>
|
||||||
pageCreatePath + "?" + stringifyQs(params);
|
pageCreatePath + "?" + stringifyQs(params);
|
||||||
|
|
30
src/pages/utils/validation.ts
Normal file
30
src/pages/utils/validation.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import {
|
||||||
|
PageErrorCode,
|
||||||
|
PageErrorWithAttributesFragment,
|
||||||
|
} from "@saleor/graphql";
|
||||||
|
|
||||||
|
import { PageData } from "../components/PageDetailsPage/form";
|
||||||
|
|
||||||
|
const createEmptyRequiredError = (
|
||||||
|
field: string,
|
||||||
|
): PageErrorWithAttributesFragment => ({
|
||||||
|
__typename: "PageError",
|
||||||
|
code: PageErrorCode.REQUIRED,
|
||||||
|
field,
|
||||||
|
message: null,
|
||||||
|
attributes: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const validatePageCreateData = (data: PageData) => {
|
||||||
|
let errors: PageErrorWithAttributesFragment[] = [];
|
||||||
|
|
||||||
|
if (!data.pageType) {
|
||||||
|
errors = [...errors, createEmptyRequiredError("pageType")];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.title) {
|
||||||
|
errors = [...errors, createEmptyRequiredError("title")];
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
};
|
|
@ -10,6 +10,7 @@ import {
|
||||||
VALUES_PAGINATE_BY,
|
VALUES_PAGINATE_BY,
|
||||||
} from "@saleor/config";
|
} from "@saleor/config";
|
||||||
import {
|
import {
|
||||||
|
PageErrorWithAttributesFragment,
|
||||||
useFileUploadMutation,
|
useFileUploadMutation,
|
||||||
usePageCreateMutation,
|
usePageCreateMutation,
|
||||||
usePageTypeQuery,
|
usePageTypeQuery,
|
||||||
|
@ -31,11 +32,11 @@ import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import PageDetailsPage from "../components/PageDetailsPage";
|
import PageDetailsPage from "../components/PageDetailsPage";
|
||||||
import { PageSubmitData } from "../components/PageDetailsPage/form";
|
import { PageSubmitData } from "../components/PageDetailsPage/form";
|
||||||
import { pageCreateUrl, pageUrl, PageUrlQueryParams } from "../urls";
|
import { pageCreateUrl, PageCreateUrlQueryParams, pageUrl } from "../urls";
|
||||||
|
|
||||||
export interface PageCreateProps {
|
export interface PageCreateProps {
|
||||||
id: string;
|
id: string;
|
||||||
params: PageUrlQueryParams;
|
params: PageCreateUrlQueryParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PageCreate: React.FC<PageCreateProps> = ({ params }) => {
|
export const PageCreate: React.FC<PageCreateProps> = ({ params }) => {
|
||||||
|
@ -45,7 +46,15 @@ export const PageCreate: React.FC<PageCreateProps> = ({ params }) => {
|
||||||
const [updateMetadata] = useUpdateMetadataMutation({});
|
const [updateMetadata] = useUpdateMetadataMutation({});
|
||||||
const [updatePrivateMetadata] = useUpdatePrivateMetadataMutation({});
|
const [updatePrivateMetadata] = useUpdatePrivateMetadataMutation({});
|
||||||
|
|
||||||
const [selectedPageTypeId, setSelectedPageTypeId] = React.useState<string>();
|
const selectedPageTypeId = params["page-type-id"];
|
||||||
|
|
||||||
|
const handleSelectPageTypeId = (pageTypeId: string) =>
|
||||||
|
navigate(
|
||||||
|
pageCreateUrl({
|
||||||
|
...params,
|
||||||
|
"page-type-id": pageTypeId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loadMore: loadMorePageTypes,
|
loadMore: loadMorePageTypes,
|
||||||
|
@ -178,6 +187,10 @@ export const PageCreate: React.FC<PageCreateProps> = ({ params }) => {
|
||||||
onFetchMore: loadMoreAttributeValues,
|
onFetchMore: loadMoreAttributeValues,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const errors = getMutationErrors(
|
||||||
|
pageCreateOpts,
|
||||||
|
) as PageErrorWithAttributesFragment[];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WindowTitle
|
<WindowTitle
|
||||||
|
@ -189,7 +202,7 @@ export const PageCreate: React.FC<PageCreateProps> = ({ params }) => {
|
||||||
/>
|
/>
|
||||||
<PageDetailsPage
|
<PageDetailsPage
|
||||||
loading={pageCreateOpts.loading || uploadFileOpts.loading}
|
loading={pageCreateOpts.loading || uploadFileOpts.loading}
|
||||||
errors={pageCreateOpts.data?.pageCreate.errors || []}
|
errors={errors}
|
||||||
saveButtonBarState={pageCreateOpts.status}
|
saveButtonBarState={pageCreateOpts.status}
|
||||||
page={null}
|
page={null}
|
||||||
attributeValues={attributeValues}
|
attributeValues={attributeValues}
|
||||||
|
@ -214,7 +227,7 @@ export const PageCreate: React.FC<PageCreateProps> = ({ params }) => {
|
||||||
fetchMoreAttributeValues={fetchMoreAttributeValues}
|
fetchMoreAttributeValues={fetchMoreAttributeValues}
|
||||||
onCloseDialog={() => navigate(pageCreateUrl())}
|
onCloseDialog={() => navigate(pageCreateUrl())}
|
||||||
selectedPageType={selectedPageType?.pageType}
|
selectedPageType={selectedPageType?.pageType}
|
||||||
onSelectPageType={id => setSelectedPageTypeId(id)}
|
onSelectPageType={handleSelectPageTypeId}
|
||||||
onAttributeSelectBlur={searchAttributeReset}
|
onAttributeSelectBlur={searchAttributeReset}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { DialogContentText } from "@material-ui/core";
|
import { DialogContentText } from "@material-ui/core";
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
import { Button } from "@saleor/components/Button";
|
import { Button } from "@saleor/components/Button";
|
||||||
|
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
|
||||||
import {
|
import {
|
||||||
usePageBulkPublishMutation,
|
usePageBulkPublishMutation,
|
||||||
usePageBulkRemoveMutation,
|
usePageBulkRemoveMutation,
|
||||||
|
@ -17,16 +18,19 @@ import usePaginator, {
|
||||||
} from "@saleor/hooks/usePaginator";
|
} from "@saleor/hooks/usePaginator";
|
||||||
import { DeleteIcon, IconButton } from "@saleor/macaw-ui";
|
import { DeleteIcon, IconButton } from "@saleor/macaw-ui";
|
||||||
import { maybe } from "@saleor/misc";
|
import { maybe } from "@saleor/misc";
|
||||||
|
import PageTypePickerDialog from "@saleor/pages/components/PageTypePickerDialog";
|
||||||
|
import usePageTypeSearch from "@saleor/searches/usePageTypeSearch";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||||
import createSortHandler from "@saleor/utils/handlers/sortHandler";
|
import createSortHandler from "@saleor/utils/handlers/sortHandler";
|
||||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
import { mapEdgesToItems, mapNodeToChoice } from "@saleor/utils/maps";
|
||||||
import { getSortParams } from "@saleor/utils/sort";
|
import { getSortParams } from "@saleor/utils/sort";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import PageListPage from "../../components/PageListPage/PageListPage";
|
import PageListPage from "../../components/PageListPage/PageListPage";
|
||||||
import {
|
import {
|
||||||
|
pageCreateUrl,
|
||||||
pageListUrl,
|
pageListUrl,
|
||||||
PageListUrlDialog,
|
PageListUrlDialog,
|
||||||
PageListUrlQueryParams,
|
PageListUrlQueryParams,
|
||||||
|
@ -114,6 +118,20 @@ export const PageList: React.FC<PageListProps> = ({ params }) => {
|
||||||
|
|
||||||
const handleSort = createSortHandler(navigate, pageListUrl, params);
|
const handleSort = createSortHandler(navigate, pageListUrl, params);
|
||||||
|
|
||||||
|
const {
|
||||||
|
loadMore: loadMoreDialogPageTypes,
|
||||||
|
search: searchDialogPageTypes,
|
||||||
|
result: searchDialogPageTypesOpts,
|
||||||
|
} = usePageTypeSearch({
|
||||||
|
variables: DEFAULT_INITIAL_SEARCH_DATA,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchMoreDialogPageTypes = {
|
||||||
|
hasMore: searchDialogPageTypesOpts.data?.search?.pageInfo?.hasNextPage,
|
||||||
|
loading: searchDialogPageTypesOpts.loading,
|
||||||
|
onFetchMore: loadMoreDialogPageTypes,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PaginatorContext.Provider value={paginationValues}>
|
<PaginatorContext.Provider value={paginationValues}>
|
||||||
<PageListPage
|
<PageListPage
|
||||||
|
@ -121,6 +139,7 @@ export const PageList: React.FC<PageListProps> = ({ params }) => {
|
||||||
settings={settings}
|
settings={settings}
|
||||||
pages={mapEdgesToItems(data?.pages)}
|
pages={mapEdgesToItems(data?.pages)}
|
||||||
onUpdateListSettings={updateListSettings}
|
onUpdateListSettings={updateListSettings}
|
||||||
|
onAdd={() => openModal("create-page")}
|
||||||
onSort={handleSort}
|
onSort={handleSort}
|
||||||
actionDialogOpts={{
|
actionDialogOpts={{
|
||||||
open: openModal,
|
open: openModal,
|
||||||
|
@ -262,6 +281,23 @@ export const PageList: React.FC<PageListProps> = ({ params }) => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<PageTypePickerDialog
|
||||||
|
confirmButtonState="success"
|
||||||
|
open={params.action === "create-page"}
|
||||||
|
pageTypes={mapNodeToChoice(
|
||||||
|
mapEdgesToItems(searchDialogPageTypesOpts?.data?.search),
|
||||||
|
)}
|
||||||
|
fetchPageTypes={searchDialogPageTypes}
|
||||||
|
fetchMorePageTypes={fetchMoreDialogPageTypes}
|
||||||
|
onClose={closeModal}
|
||||||
|
onConfirm={pageTypeId =>
|
||||||
|
navigate(
|
||||||
|
pageCreateUrl({
|
||||||
|
"page-type-id": pageTypeId,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</PaginatorContext.Provider>
|
</PaginatorContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -158149,20 +158149,18 @@ exports[`Storyshots Views / Pages / Page list default 1`] = `
|
||||||
<div
|
<div
|
||||||
class="PageHeader-root-id"
|
class="PageHeader-root-id"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
aria-disabled="false"
|
|
||||||
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
|
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
|
||||||
data-test-id="create-page"
|
data-test-id="create-page"
|
||||||
href="/pages/add"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="MuiButton-label-id"
|
class="MuiButton-label-id"
|
||||||
>
|
>
|
||||||
Create page
|
Create page
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -158741,20 +158739,18 @@ exports[`Storyshots Views / Pages / Page list loading 1`] = `
|
||||||
<div
|
<div
|
||||||
class="PageHeader-root-id"
|
class="PageHeader-root-id"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
aria-disabled="false"
|
|
||||||
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
|
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
|
||||||
data-test-id="create-page"
|
data-test-id="create-page"
|
||||||
href="/pages/add"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="MuiButton-label-id"
|
class="MuiButton-label-id"
|
||||||
>
|
>
|
||||||
Create page
|
Create page
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -159136,20 +159132,18 @@ exports[`Storyshots Views / Pages / Page list no data 1`] = `
|
||||||
<div
|
<div
|
||||||
class="PageHeader-root-id"
|
class="PageHeader-root-id"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
aria-disabled="false"
|
|
||||||
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
|
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
|
||||||
data-test-id="create-page"
|
data-test-id="create-page"
|
||||||
href="/pages/add"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="MuiButton-label-id"
|
class="MuiButton-label-id"
|
||||||
>
|
>
|
||||||
Create page
|
Create page
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -159402,6 +159396,12 @@ exports[`Storyshots Views / Pages / Page list no data 1`] = `
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`Storyshots Views / Pages / Page type dialog default 1`] = `
|
||||||
|
<div
|
||||||
|
style="padding:24px"
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`Storyshots Views / Permission Groups / Permission Group Create default 1`] = `
|
exports[`Storyshots Views / Permission Groups / Permission Group Create default 1`] = `
|
||||||
<div
|
<div
|
||||||
style="padding:24px"
|
style="padding:24px"
|
||||||
|
|
Loading…
Reference in a new issue