Turn grid view into a plugin

This commit is contained in:
DrMint 2023-08-23 20:42:32 +02:00
parent f454b22569
commit 3532dab712
9 changed files with 492 additions and 188 deletions

View File

@ -1,185 +0,0 @@
import { useWindowInfo } from "@faceless-ui/window-info";
import Button from "payload/dist/admin/components/elements/Button";
import DeleteMany from "payload/dist/admin/components/elements/DeleteMany";
import EditMany from "payload/dist/admin/components/elements/EditMany";
import Eyebrow from "payload/dist/admin/components/elements/Eyebrow";
import { Gutter } from "payload/dist/admin/components/elements/Gutter";
import ListControls from "payload/dist/admin/components/elements/ListControls";
import ListSelection from "payload/dist/admin/components/elements/ListSelection";
import Paginator from "payload/dist/admin/components/elements/Paginator";
import PerPage from "payload/dist/admin/components/elements/PerPage";
import Pill from "payload/dist/admin/components/elements/Pill";
import PublishMany from "payload/dist/admin/components/elements/PublishMany";
import { StaggeredShimmers } from "payload/dist/admin/components/elements/ShimmerEffect";
import UnpublishMany from "payload/dist/admin/components/elements/UnpublishMany";
import ViewDescription from "payload/dist/admin/components/elements/ViewDescription";
import Meta from "payload/dist/admin/components/utilities/Meta";
import { RelationshipProvider } from "payload/dist/admin/components/views/collections/List/RelationshipProvider";
import { SelectionProvider } from "payload/dist/admin/components/views/collections/List/SelectionProvider";
import { Props } from "payload/dist/admin/components/views/collections/List/types";
import formatFilesize from "payload/dist/uploads/formatFilesize";
import { getTranslation } from "payload/dist/utilities/getTranslation";
import React, { Fragment } from "react";
import { useTranslation } from "react-i18next";
import Grid from "./Grid";
const baseClass = "collection-list";
export const UploadsGridView: React.ComponentType<Props> = (props) => {
const {
collection,
collection: {
labels: { singular: singularLabel, plural: pluralLabel },
admin: {
description,
components: { BeforeList, BeforeListTable, AfterListTable, AfterList } = {},
} = {},
},
data,
newDocumentURL,
limit,
hasCreatePermission,
disableEyebrow,
modifySearchParams,
handleSortChange,
handleWhereChange,
handlePageChange,
handlePerPageChange,
customHeader,
resetParams,
} = props;
const {
breakpoints: { s: smallBreak },
} = useWindowInfo();
const { t, i18n } = useTranslation("general");
let formattedDocs = data.docs || [];
if (collection.upload) {
formattedDocs = formattedDocs?.map((doc) => {
return {
...doc,
filesize: formatFilesize(doc.filesize),
};
});
}
return (
<div className={baseClass}>
{Array.isArray(BeforeList) &&
BeforeList.map((Component, i) => <Component key={i} {...props} />)}
<Meta title={getTranslation(collection.labels.plural, i18n)} />
<SelectionProvider docs={data.docs} totalDocs={data.totalDocs}>
{!disableEyebrow && <Eyebrow />}
<Gutter className={`${baseClass}__wrap`}>
<header className={`${baseClass}__header`}>
{customHeader && customHeader}
{!customHeader && (
<Fragment>
<h1>{getTranslation(pluralLabel, i18n)}</h1>
{hasCreatePermission && (
<Pill
to={newDocumentURL}
aria-label={t("createNewLabel", {
label: getTranslation(singularLabel, i18n),
})}>
{t("createNew")}
</Pill>
)}
{!smallBreak && (
<ListSelection label={getTranslation(collection.labels.plural, i18n)} />
)}
{description && (
<div className={`${baseClass}__sub-header`}>
<ViewDescription description={description} />
</div>
)}
</Fragment>
)}
</header>
<ListControls
collection={collection}
modifySearchQuery={modifySearchParams}
handleSortChange={handleSortChange}
handleWhereChange={handleWhereChange}
resetParams={resetParams}
/>
{Array.isArray(BeforeListTable) &&
BeforeListTable.map((Component, i) => <Component key={i} {...props} />)}
{!data.docs && (
<StaggeredShimmers
className={[`${baseClass}__shimmer`, `${baseClass}__shimmer--rows`].join(" ")}
count={6}
/>
)}
{data.docs && data.docs.length > 0 && (
<RelationshipProvider>
<Grid data={formattedDocs} collection={collection} />
</RelationshipProvider>
)}
{data.docs && data.docs.length === 0 && (
<div className={`${baseClass}__no-results`}>
<p>{t("noResults", { label: getTranslation(pluralLabel, i18n) })}</p>
{hasCreatePermission && newDocumentURL && (
<Button el="link" to={newDocumentURL}>
{t("createNewLabel", { label: getTranslation(singularLabel, i18n) })}
</Button>
)}
</div>
)}
{Array.isArray(AfterListTable) &&
AfterListTable.map((Component, i) => <Component key={i} {...props} />)}
<div className={`${baseClass}__page-controls`}>
<Paginator
limit={data.limit}
totalPages={data.totalPages}
page={data.page}
hasPrevPage={data.hasPrevPage}
hasNextPage={data.hasNextPage}
prevPage={data.prevPage ?? undefined}
nextPage={data.nextPage ?? undefined}
numberOfNeighbors={1}
disableHistoryChange={modifySearchParams === false}
onChange={handlePageChange}
/>
{data?.totalDocs > 0 && (
<Fragment>
<div className={`${baseClass}__page-info`}>
{data.page ?? 1 * data.limit - (data.limit - 1)}-
{data.totalPages > 1 && data.totalPages !== data.page
? data.limit * (data.page ?? 1)
: data.totalDocs}{" "}
{t("of")} {data.totalDocs}
</div>
<PerPage
limits={collection?.admin?.pagination?.limits}
limit={limit}
modifySearchParams={modifySearchParams}
handleChange={handlePerPageChange}
resetPage={data.totalDocs <= data.pagingCounter}
/>
<div className={`${baseClass}__list-selection`}>
{smallBreak && (
<Fragment>
<ListSelection label={getTranslation(collection.labels.plural, i18n)} />
<div className={`${baseClass}__list-selection-actions`}>
<EditMany collection={collection} resetParams={resetParams} />
<PublishMany collection={collection} resetParams={resetParams} />
<UnpublishMany collection={collection} resetParams={resetParams} />
<DeleteMany collection={collection} resetParams={resetParams} />
</div>
</Fragment>
)}
</div>
</Fragment>
)}
</div>
</Gutter>
</SelectionProvider>
{Array.isArray(AfterList) &&
AfterList.map((Component, i) => <Component key={i} {...props} />)}
</div>
);
};

View File

@ -25,6 +25,7 @@ import { WeaponsThumbnails } from "./collections/WeaponsThumbnails/WeaponsThumbn
import { Icon } from "./components/Icon"; import { Icon } from "./components/Icon";
import { Logo } from "./components/Logo"; import { Logo } from "./components/Logo";
import { Collections } from "./constants"; import { Collections } from "./constants";
import { gridViewPlugin } from "./plugins/payload-grid-view";
export default buildConfig({ export default buildConfig({
serverURL: process.env.PAYLOAD_URI, serverURL: process.env.PAYLOAD_URI,
@ -70,4 +71,5 @@ export default buildConfig({
graphQL: { graphQL: {
disable: true, disable: true,
}, },
plugins: [gridViewPlugin],
}); });

View File

@ -0,0 +1,228 @@
import { useWindowInfo } from "@faceless-ui/window-info";
import Button from "payload/dist/admin/components/elements/Button";
import ColumnSelector from "payload/dist/admin/components/elements/ColumnSelector";
import DeleteMany from "payload/dist/admin/components/elements/DeleteMany";
import EditMany from "payload/dist/admin/components/elements/EditMany";
import { getTextFieldsToBeSearched } from "payload/dist/admin/components/elements/ListControls/getTextFieldsToBeSearched";
import { Props } from "payload/dist/admin/components/elements/ListControls/types";
import Pill from "payload/dist/admin/components/elements/Pill";
import PublishMany from "payload/dist/admin/components/elements/PublishMany";
import SearchFilter from "payload/dist/admin/components/elements/SearchFilter";
import SortComplex from "payload/dist/admin/components/elements/SortComplex";
import UnpublishMany from "payload/dist/admin/components/elements/UnpublishMany";
import WhereBuilder from "payload/dist/admin/components/elements/WhereBuilder";
import validateWhereQuery from "payload/dist/admin/components/elements/WhereBuilder/validateWhereQuery";
import Chevron from "payload/dist/admin/components/icons/Chevron";
import { useSearchParams } from "payload/dist/admin/components/utilities/SearchParams";
import { SanitizedCollectionConfig } from "payload/dist/collections/config/types";
import { fieldAffectsData } from "payload/dist/fields/config/types";
import flattenFields from "payload/dist/utilities/flattenTopLevelFields";
import { getTranslation } from "payload/dist/utilities/getTranslation";
import React, { useEffect, useState } from "react";
import AnimateHeight from "react-animate-height";
import { useTranslation } from "react-i18next";
const baseClass = "list-controls";
export type ViewMode = "grid" | "list";
const getUseAsTitle = (collection: SanitizedCollectionConfig) => {
const {
admin: { useAsTitle },
fields,
} = collection;
const topLevelFields = flattenFields(fields);
return topLevelFields.find((field) => fieldAffectsData(field) && field.name === useAsTitle);
};
/**
* The ListControls component is used to render the controls (search, filter, where)
* for a collection's list view. You can find those directly above the table which lists
* the collection's documents.
*/
const ListControls: React.FC<
Props & {
viewMode: ViewMode;
handleViewModeChange: (newMode: ViewMode) => void;
showViewModeToggle: boolean;
}
> = (props) => {
const {
collection,
enableColumns = true,
enableSort = false,
handleSortChange,
handleWhereChange,
modifySearchQuery = true,
resetParams = () => undefined,
viewMode,
handleViewModeChange,
collection: {
fields,
admin: { listSearchableFields },
},
showViewModeToggle,
} = props;
const params = useSearchParams();
const shouldInitializeWhereOpened = validateWhereQuery(params?.where);
const [titleField, setTitleField] = useState(getUseAsTitle(collection));
useEffect(() => {
setTitleField(getUseAsTitle(collection));
}, [collection]);
const [textFieldsToBeSearched] = useState(
getTextFieldsToBeSearched(listSearchableFields, fields)
);
const [visibleDrawer, setVisibleDrawer] = useState<"where" | "sort" | "columns" | undefined>(
shouldInitializeWhereOpened ? "where" : undefined
);
const { t, i18n } = useTranslation("general");
const {
breakpoints: { s: smallBreak },
} = useWindowInfo();
return (
<div className={baseClass}>
<div className={`${baseClass}__wrap`}>
<SearchFilter
fieldName={titleField && fieldAffectsData(titleField) ? titleField.name : undefined}
handleChange={handleWhereChange}
modifySearchQuery={modifySearchQuery}
fieldLabel={
titleField && fieldAffectsData(titleField)
? getTranslation(String(titleField.label ?? titleField.name), i18n)
: undefined
}
listSearchableFields={textFieldsToBeSearched}
/>
<div className={`${baseClass}__buttons`}>
<div className={`${baseClass}__buttons-wrap`}>
{!smallBreak && (
<React.Fragment>
<EditMany collection={collection} resetParams={resetParams} />
<PublishMany collection={collection} resetParams={resetParams} />
<UnpublishMany collection={collection} resetParams={resetParams} />
<DeleteMany collection={collection} resetParams={resetParams} />
</React.Fragment>
)}
{enableColumns && (
<Pill
pillStyle="light"
className={`${baseClass}__toggle-columns ${
visibleDrawer === "columns" ? `${baseClass}__buttons-active` : ""
}`}
onClick={() =>
setVisibleDrawer(visibleDrawer !== "columns" ? "columns" : undefined)
}
aria-expanded={visibleDrawer === "columns"}
aria-controls={`${baseClass}-columns`}
icon={<Chevron />}>
{t("columns")}
</Pill>
)}
<Pill
pillStyle="light"
className={`${baseClass}__toggle-where ${
visibleDrawer === "where" ? `${baseClass}__buttons-active` : ""
}`}
onClick={() => setVisibleDrawer(visibleDrawer !== "where" ? "where" : undefined)}
aria-expanded={visibleDrawer === "where"}
aria-controls={`${baseClass}-where`}
icon={<Chevron />}>
{t("filters")}
</Pill>
{enableSort && (
<Button
className={`${baseClass}__toggle-sort`}
buttonStyle={visibleDrawer === "sort" ? undefined : "secondary"}
onClick={() => setVisibleDrawer(visibleDrawer !== "sort" ? "sort" : undefined)}
aria-expanded={visibleDrawer === "sort"}
aria-controls={`${baseClass}-sort`}
icon="chevron"
iconStyle="none">
{t("sort")}
</Button>
)}
{showViewModeToggle && (
<div style={{ marginLeft: 10 }}>
<svg
onClick={() => handleViewModeChange("list")}
style={{
cursor: "pointer",
color:
viewMode === "list"
? "var(--theme-elevation-1000)"
: "var(--theme-elevation-500)",
}}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
preserveAspectRatio="none"
height="32"
width="28">
<path
fill="currentColor"
d="M333-242h432.5q12 0 22-10t10-22v-100.5H333V-242ZM162.5-586h145v-132h-113q-12 0-22 10t-10 22v100Zm0 187h145v-161.5h-145V-399Zm32 157h113v-132.5h-145V-274q0 12 10 22t22 10ZM333-399h464.5v-161.5H333V-399Zm0-187h464.5v-100q0-12-10-22t-22-10H333v132ZM194.28-216.5q-24.218 0-40.749-16.531Q137-249.562 137-273.802v-412.396q0-24.24 16.531-40.771Q170.062-743.5 194.28-743.5h571.44q24.218 0 40.749 16.531Q823-710.438 823-686.198v412.396q0 24.24-16.531 40.771Q789.938-216.5 765.72-216.5H194.28Z"
/>
</svg>
<svg
onClick={() => handleViewModeChange("grid")}
style={{
cursor: "pointer",
color:
viewMode === "grid"
? "var(--theme-elevation-1000)"
: "var(--theme-elevation-500)",
}}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
height="28"
width="28">
<path
fill="currentColor"
d="M176.5-519v-264.5h265V-519h-265Zm0 342.5v-265h265v265h-265ZM519-519v-264.5h264.5V-519H519Zm0 342.5v-265h264.5v265H519Zm-317-368h214V-758H202v213.5Zm342.5 0H758V-758H544.5v213.5Zm0 342.5H758v-214H544.5v214ZM202-202h214v-214H202v214Zm342.5-342.5Zm0 128.5ZM416-416Zm0-128.5Z"
/>
</svg>
</div>
)}
</div>
</div>
</div>
{enableColumns && (
<AnimateHeight
className={`${baseClass}__columns`}
height={visibleDrawer === "columns" ? "auto" : 0}
id={`${baseClass}-columns`}>
<ColumnSelector collection={collection} />
</AnimateHeight>
)}
<AnimateHeight
className={`${baseClass}__where`}
height={visibleDrawer === "where" ? "auto" : 0}
id={`${baseClass}-where`}>
<WhereBuilder
collection={collection}
modifySearchQuery={modifySearchQuery}
handleChange={handleWhereChange}
/>
</AnimateHeight>
{enableSort && (
<AnimateHeight
className={`${baseClass}__sort`}
height={visibleDrawer === "sort" ? "auto" : 0}
id={`${baseClass}-sort`}>
<SortComplex
modifySearchQuery={modifySearchQuery}
collection={collection}
handleChange={handleSortChange}
/>
</AnimateHeight>
)}
</div>
);
};
export default ListControls;

View File

@ -0,0 +1,202 @@
import { useWindowInfo } from "@faceless-ui/window-info";
import Button from "payload/dist/admin/components/elements/Button";
import DeleteMany from "payload/dist/admin/components/elements/DeleteMany";
import EditMany from "payload/dist/admin/components/elements/EditMany";
import Eyebrow from "payload/dist/admin/components/elements/Eyebrow";
import { Gutter } from "payload/dist/admin/components/elements/Gutter";
import ListSelection from "payload/dist/admin/components/elements/ListSelection";
import Paginator from "payload/dist/admin/components/elements/Paginator";
import PerPage from "payload/dist/admin/components/elements/PerPage";
import Pill from "payload/dist/admin/components/elements/Pill";
import PublishMany from "payload/dist/admin/components/elements/PublishMany";
import { StaggeredShimmers } from "payload/dist/admin/components/elements/ShimmerEffect";
import { Table } from "payload/dist/admin/components/elements/Table";
import UnpublishMany from "payload/dist/admin/components/elements/UnpublishMany";
import ViewDescription from "payload/dist/admin/components/elements/ViewDescription";
import Meta from "payload/dist/admin/components/utilities/Meta";
import { RelationshipProvider } from "payload/dist/admin/components/views/collections/List/RelationshipProvider";
import { SelectionProvider } from "payload/dist/admin/components/views/collections/List/SelectionProvider";
import { Props } from "payload/dist/admin/components/views/collections/List/types";
import formatFilesize from "payload/dist/uploads/formatFilesize";
import { getTranslation } from "payload/dist/utilities/getTranslation";
import React, { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import Grid from "./Grid";
import ListControls, { ViewMode } from "./ListControls";
const baseClass = "collection-list";
export type UploadsGridViewOptions = {
list?: boolean;
grid?: boolean;
};
export const UploadsGridView =
(options: UploadsGridViewOptions) =>
(props: Props): JSX.Element => {
const {
collection,
collection: {
labels: { singular: singularLabel, plural: pluralLabel },
admin: {
description,
components: { BeforeList, BeforeListTable, AfterListTable, AfterList } = {},
} = {},
},
data,
newDocumentURL,
limit,
hasCreatePermission,
disableEyebrow,
modifySearchParams,
handleSortChange,
handleWhereChange,
handlePageChange,
handlePerPageChange,
customHeader,
resetParams,
} = props;
const [viewMode, setViewMode] = useState<ViewMode>(options.grid === true ? "grid" : "list");
const {
breakpoints: { s: smallBreak },
} = useWindowInfo();
const { t, i18n } = useTranslation("general");
let formattedDocs = data.docs || [];
if (collection.upload) {
formattedDocs = formattedDocs?.map((doc) => {
return {
...doc,
filesize: formatFilesize(doc.filesize),
};
});
}
return (
<div className={baseClass}>
{Array.isArray(BeforeList) &&
BeforeList.map((Component, i) => <Component key={i} {...props} />)}
<Meta title={getTranslation(collection.labels.plural, i18n)} />
<SelectionProvider docs={data.docs} totalDocs={data.totalDocs}>
{!disableEyebrow && <Eyebrow />}
<Gutter className={`${baseClass}__wrap`}>
<header className={`${baseClass}__header`}>
{customHeader && customHeader}
{!customHeader && (
<Fragment>
<h1>{getTranslation(pluralLabel, i18n)}</h1>
{hasCreatePermission && (
<Pill
to={newDocumentURL}
aria-label={t("createNewLabel", {
label: getTranslation(singularLabel, i18n),
})}>
{t("createNew")}
</Pill>
)}
{!smallBreak && (
<ListSelection label={getTranslation(collection.labels.plural, i18n)} />
)}
{description && (
<div className={`${baseClass}__sub-header`}>
<ViewDescription description={description} />
</div>
)}
</Fragment>
)}
</header>
<ListControls
collection={collection}
modifySearchQuery={modifySearchParams}
handleSortChange={handleSortChange}
handleWhereChange={handleWhereChange}
handleViewModeChange={(newViewMode) => setViewMode(newViewMode)}
resetParams={resetParams}
viewMode={viewMode}
showViewModeToggle={options.list === true && options.grid === true}
/>
{Array.isArray(BeforeListTable) &&
BeforeListTable.map((Component, i) => <Component key={i} {...props} />)}
{!data.docs && (
<StaggeredShimmers
className={[`${baseClass}__shimmer`, `${baseClass}__shimmer--rows`].join(" ")}
count={6}
/>
)}
{data.docs && data.docs.length > 0 && (
<RelationshipProvider>
{viewMode === "grid" ? (
<Grid data={formattedDocs} collection={collection} />
) : (
<Table data={formattedDocs} />
)}
</RelationshipProvider>
)}
{data.docs && data.docs.length === 0 && (
<div className={`${baseClass}__no-results`}>
<p>{t("noResults", { label: getTranslation(pluralLabel, i18n) })}</p>
{hasCreatePermission && newDocumentURL && (
<Button el="link" to={newDocumentURL}>
{t("createNewLabel", { label: getTranslation(singularLabel, i18n) })}
</Button>
)}
</div>
)}
{Array.isArray(AfterListTable) &&
AfterListTable.map((Component, i) => <Component key={i} {...props} />)}
<div className={`${baseClass}__page-controls`}>
<Paginator
limit={data.limit}
totalPages={data.totalPages}
page={data.page}
hasPrevPage={data.hasPrevPage}
hasNextPage={data.hasNextPage}
prevPage={data.prevPage ?? undefined}
nextPage={data.nextPage ?? undefined}
numberOfNeighbors={1}
disableHistoryChange={modifySearchParams === false}
onChange={handlePageChange}
/>
{data?.totalDocs > 0 && (
<Fragment>
<div className={`${baseClass}__page-info`}>
{data.page ?? 1 * data.limit - (data.limit - 1)}-
{data.totalPages > 1 && data.totalPages !== data.page
? data.limit * (data.page ?? 1)
: data.totalDocs}{" "}
{t("of")} {data.totalDocs}
</div>
<PerPage
limits={collection?.admin?.pagination?.limits}
limit={limit}
modifySearchParams={modifySearchParams}
handleChange={handlePerPageChange}
resetPage={data.totalDocs <= data.pagingCounter}
/>
<div className={`${baseClass}__list-selection`}>
{smallBreak && (
<Fragment>
<ListSelection label={getTranslation(collection.labels.plural, i18n)} />
<div className={`${baseClass}__list-selection-actions`}>
<EditMany collection={collection} resetParams={resetParams} />
<PublishMany collection={collection} resetParams={resetParams} />
<UnpublishMany collection={collection} resetParams={resetParams} />
<DeleteMany collection={collection} resetParams={resetParams} />
</div>
</Fragment>
)}
</div>
</Fragment>
)}
</div>
</Gutter>
</SelectionProvider>
{Array.isArray(AfterList) &&
AfterList.map((Component, i) => <Component key={i} {...props} />)}
</div>
);
};

View File

@ -0,0 +1,53 @@
import { Plugin } from "payload/config";
import { CollectionAdminOptions } from "payload/dist/collections/config/types";
import { CollectionConfig } from "payload/types";
import { UploadsGridView, UploadsGridViewOptions } from "./components/UploadsGridView/UploadsGridView";
type Components = Required<CollectionAdminOptions>["components"];
type ViewsComponents = Required<Required<CollectionAdminOptions>["components"]>["views"];
type Options = {
isUploadEnabled: boolean;
gridView: UploadsGridViewOptions;
};
export type CollectionConfigWithGridView = CollectionConfig & {
custom?: { gridView?: UploadsGridViewOptions };
};
export const gridViewPlugin: Plugin = ({ collections, ...others }) => ({
collections: collections?.map(handleCollection),
...others,
});
const handleCollection = ({
admin,
...others
}: CollectionConfigWithGridView): CollectionConfig => ({
...others,
admin: handleAdmin(admin, {
isUploadEnabled: others.upload !== undefined,
gridView: others.custom?.gridView ?? { grid: true, list: true },
}),
});
const handleAdmin = (
{ components, ...others }: CollectionAdminOptions = {},
options: Options
): CollectionAdminOptions => ({
...others,
components: handleComponents(components, options),
});
const handleComponents = ({ views, ...others }: Components = {}, options: Options): Components => ({
...others,
views: handleViewsComponents(views, options),
});
const handleViewsComponents = (
{ List, ...others }: ViewsComponents = {},
{ isUploadEnabled, gridView }: Options
): ViewsComponents => ({
...others,
List: isUploadEnabled ? UploadsGridView(gridView) : List,
});

View File

@ -1,7 +1,13 @@
import { CollectionConfig } from "payload/types"; import { CollectionConfig } from "payload/types";
import { Collections } from "../constants"; import { Collections } from "../constants";
import { CollectionConfigWithGridView } from "../plugins/payload-grid-view";
export type BuildCollectionConfig = Omit<CollectionConfig, "slug" | "typescript" | "labels"> & { type CollectionConfigWithPlugins = CollectionConfig & CollectionConfigWithGridView;
export type BuildCollectionConfig = Omit<
CollectionConfigWithPlugins,
"slug" | "typescript" | "labels"
> & {
slug: Collections; slug: Collections;
labels: { singular: string; plural: string }; labels: { singular: string; plural: string };
}; };

View File

@ -1,6 +1,5 @@
import { ImageSize } from "payload/dist/uploads/types"; import { ImageSize } from "payload/dist/uploads/types";
import { CollectionConfig } from "payload/types"; import { CollectionConfig } from "payload/types";
import { UploadsGridView } from "../components/UploadsGridView/UploadsGridView";
import { CollectionGroups } from "../constants"; import { CollectionGroups } from "../constants";
import { createImageRegenerationEndpoint } from "../endpoints/createImageRegenerationEndpoint"; import { createImageRegenerationEndpoint } from "../endpoints/createImageRegenerationEndpoint";
import { BuildCollectionConfig, buildCollectionConfig } from "./collectionConfig"; import { BuildCollectionConfig, buildCollectionConfig } from "./collectionConfig";
@ -21,7 +20,6 @@ export const buildImageCollectionConfig = ({
disableDuplicate: true, disableDuplicate: true,
useAsTitle: "filename", useAsTitle: "filename",
group: CollectionGroups.Media, group: CollectionGroups.Media,
components: { views: { List: UploadsGridView } },
...admin, ...admin,
}, },
endpoints: [createImageRegenerationEndpoint(otherConfig.slug)], endpoints: [createImageRegenerationEndpoint(otherConfig.slug)],