Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,28 @@ const config = buildConfig({
});
```

## Stylizing the cards

```typescript
import { payloadWorkflow } from 'payload-workflow';
import type { BoardCardDefaultContentProps } from 'payload-workflow';
import { Link } from "react-router-dom";

const config = buildConfig({
collections: [ ... ],
plugins: [
payloadWorkflow({
'my-collection-slug': {
statuses: [ ... ],
cardContentComponent: ({admin, data, link}: BoardCardDefaultContentProps) => (
<Link to={link}>{ data.title }</Link>
)
}
})
],
});
```

## Differences with the draft/publish system of Payload.

The workflow plugin introduces a new field called `workflowStatus`. This field does not interact with the draft/publish
Expand All @@ -56,7 +78,7 @@ For example: Automatically publish the document when the `workflowStatus` has be
Upcoming Features / Ideas. Have a suggestion for the plugin? Feel free to open an issue or contribute!

- [X] Payload 2.0 support
- [ ] Customize card properties (currently displays `title` and `createdAt`)
- [X] Customize card properties (currently displays `title` and `createdAt`)
- [ ] Edit relationships directly from the card (e.g., assigning users to a document)
- [X] Toggleable column for posts without a workflow status (Currently, documents lacking `workflowStatus` aren't
visible on the board)
Expand Down
6 changes: 6 additions & 0 deletions dev/src/components/CategoryCard/CategoryCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from "react";
import { BoardCardDefaultContentProps } from "../../../../src";

const CategoryCard = ({ data }: BoardCardDefaultContentProps) => <div>{data.name}</div>

export default CategoryCard
11 changes: 11 additions & 0 deletions dev/src/payload.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Media from './collections/Media';
import { mongooseAdapter } from "@payloadcms/db-mongodb";
import { slateEditor } from "@payloadcms/richtext-slate";
import { webpackBundler } from "@payloadcms/bundler-webpack";
import CategoryCard from "./components/CategoryCard/CategoryCard";

import { payloadWorkflow } from "../../src/index";

Expand Down Expand Up @@ -59,6 +60,16 @@ export default buildConfig({
],
defaultStatus: 'draft',
hideNoStatusColumn: false
},
[Categories.slug]: {
statuses: [
{value: 'planned', label: 'Planned'},
{value: 'active', label: 'Active'},
{value: 'archived', label: 'Archived'},
],
defaultStatus: 'active',
hideNoStatusColumn: true,
cardContentComponent: CategoryCard
}
})
],
Expand Down
15 changes: 5 additions & 10 deletions src/components/BoardCard/BoardCard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { forwardRef } from 'react'
import { CollectionConfig } from "payload/types";
import { useConfig } from "payload/components/utilities";
import { formatDate } from "payload/dist/admin/utilities/formatDate";
import { Link } from 'react-router-dom';
import { usePluginConfig } from "../WorkflowViewConfigContext/WorkflowViewConfigContext";
import './sytles.scss';
import BoardCardDefaultContent from "../BoardCardDefaultContent/BoardCardDefaultContent";

const baseClass = 'board-card';

Expand All @@ -14,22 +14,17 @@ interface BoardCardProps {

const BoardCard = forwardRef((props: BoardCardProps, ref: React.Ref<any>) => {
const {collection, data, ...rest} = props
const {admin: {dateFormat}, routes: {admin: payloadAdmin}} = useConfig();
const {routes: {admin: payloadAdmin}} = useConfig();
const {slug, admin} = collection;
const {cardContentComponent: CardContent = BoardCardDefaultContent} = usePluginConfig();

return (
<div
className={ baseClass }
ref={ ref }
{ ...rest }
>
<div className={`${baseClass}__title`}>
<Link to={ `${ payloadAdmin }/collections/${ slug }/${ data.id }` }>
{ admin?.useAsTitle && data[admin.useAsTitle] }
{ !admin?.useAsTitle && data.id }
</Link>
</div>
<small>{ formatDate(data.createdAt, dateFormat) }</small>
<CardContent admin={admin} data={data} link={`${ payloadAdmin }/collections/${ slug }/${ data.id }`}/>
</div>
)
})
Expand Down
9 changes: 0 additions & 9 deletions src/components/BoardCard/sytles.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
@import "payload/scss";

.board-card {

&__title {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}

background: var(--theme-elevation-50);
padding: base(1.25) $baseline;
margin-bottom: 1rem;
Expand Down
29 changes: 29 additions & 0 deletions src/components/BoardCardDefaultContent/BoardCardDefaultContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { CollectionConfig } from "payload/types";
import { Link } from "react-router-dom";
import {formatDate} from "payload/dist/admin/utilities/formatDate";
import {useConfig} from "payload/components/utilities";

export interface BoardCardDefaultContentProps {
link: string
admin: CollectionConfig['admin']
data: any
}

const baseClass = 'board-card-content';

const BoardCardDefaultContent = ({admin, data, link}: BoardCardDefaultContentProps) => {
const {admin: {dateFormat}} = useConfig();

return (
<div className={baseClass}>
<Link to={link}>
{admin?.useAsTitle && data[admin.useAsTitle]}
{!admin?.useAsTitle && data.id}
</Link>
<div><small>{formatDate(data.createdAt, dateFormat)}</small></div>
</div>
)
}

export default BoardCardDefaultContent;
7 changes: 7 additions & 0 deletions src/components/BoardCardDefaultContent/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.board-card-content {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
50 changes: 26 additions & 24 deletions src/components/WorkflowView/WorkflowView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useConfig } from "payload/components/utilities";
import { SelectionProvider } from "payload/dist/admin/components/views/collections/List/SelectionProvider";
import { ListControls } from 'payload/dist/admin/components/elements/ListControls'
import DefaultList from "payload/dist/admin/components/views/collections/List/Default";
import {WorkflowViewConfigContext} from "../WorkflowViewConfigContext/WorkflowViewConfigContext";

const baseClass = 'scrumboard';

Expand Down Expand Up @@ -83,32 +84,33 @@ const WorkflowView = (config: PluginCollectionConfig) => (props: ListProps) => {
totalDocs={ data.totalDocs }
>
<Gutter className={ `${ baseClass }__wrap` }>
<WorkflowViewConfigContext.Provider value={config}>
<WorkflowViewHeader
hasCreatePermission={ hasCreatePermission }
newDocumentURL={ newDocumentURL }
pluralLabel={ pluralLabel }
isShowingWorkflow={ showingWorkflow }
onWorkflowViewSwitch={ () => setShowingWorkflow(false) }
/>

<WorkflowViewHeader
hasCreatePermission={ hasCreatePermission }
newDocumentURL={ newDocumentURL }
pluralLabel={ pluralLabel }
isShowingWorkflow={ showingWorkflow }
onWorkflowViewSwitch={ () => setShowingWorkflow(false) }
/>

<ListControls
collection={collection}
handleSearchChange={handleSearchChange}
handleSortChange={handleSortChange}
handleWhereChange={handleWhereChange}
modifySearchQuery={modifySearchParams}
resetParams={resetParams}
titleField={titleField}
/>
<ListControls
collection={collection}
handleSearchChange={handleSearchChange}
handleSortChange={handleSortChange}
handleWhereChange={handleWhereChange}
modifySearchQuery={modifySearchParams}
resetParams={resetParams}
titleField={titleField}
/>

<Board
collection={ collection }
documents={ data.docs }
hideNoStatusColumn={ config.hideNoStatusColumn }
statusDefinition={ statusDefinition }
onDocumentWorkflowStatusChange={ handleDocumentWorkflowStatusChange }
/>
<Board
collection={ collection }
documents={ data.docs }
hideNoStatusColumn={ config.hideNoStatusColumn }
statusDefinition={ statusDefinition }
onDocumentWorkflowStatusChange={ handleDocumentWorkflowStatusChange }
/>
</WorkflowViewConfigContext.Provider>
</Gutter>
</SelectionProvider>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React, {useContext} from "react";
import {PluginCollectionConfig} from "../../index";

export const WorkflowViewConfigContext = React.createContext<PluginCollectionConfig>(undefined)

export const usePluginConfig = () => useContext(WorkflowViewConfigContext);
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { Config, Plugin } from "payload/config";
import { CollectionConfig, OptionObject } from "payload/types";
import generateOrderRank from "./hooks/generateOrderRank";
import WorkflowView from "./components/WorkflowView/WorkflowView";
import { BoardCardDefaultContentProps } from "./components/BoardCardDefaultContent/BoardCardDefaultContent";

export interface PluginCollectionConfig {
statuses: OptionObject[],
defaultStatus?: string;
hideNoStatusColumn?: boolean;
cardContentComponent?: React.ElementType<BoardCardDefaultContentProps>
}

export type { BoardCardDefaultContentProps } from "./components/BoardCardDefaultContent/BoardCardDefaultContent";

const extendCollectionConfig = (
pluginConfig: Record<string, PluginCollectionConfig>,
collections: CollectionConfig[]
Expand Down