Skip to content
62 changes: 62 additions & 0 deletions dev-test/backends/default-workflow-status/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
backend:
name: test-repo

publish_mode: editorial_workflow
default_workflow_status: pending_publish
media_folder: static/media
public_folder: /media
collections:
- name: posts
label: Posts
label_singular: 'Post'
folder: content/posts
create: true
slug: '{{year}}-{{month}}-{{day}}-{{slug}}'
fields:
- label: Template
name: template
widget: hidden
default: post
- label: Title
name: title
widget: string
- label: 'Cover Image'
name: 'image'
widget: 'image'
required: false
- label: Publish Date
name: date
widget: datetime
- label: Description
name: description
widget: text
- label: Category
name: category
widget: string
- label: Body
name: body
widget: markdown
- label: Tags
name: tags
widget: list
- name: pages
label: Pages
label_singular: 'Page'
folder: content/pages
create: true
slug: '{{slug}}'
fields:
- label: Template
name: template
widget: hidden
default: page
- label: Title
name: title
widget: string
- label: Draft
name: draft
widget: boolean
default: true
- label: Body
name: body
widget: markdown
41 changes: 41 additions & 0 deletions dev-test/backends/default-workflow-status/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />

<title>Netlify CMS Development Test</title>
</head>
<body>
<script src="dist/netlify-cms.js"></script>
<script>
var PostPreview = createClass({
render: function() {
var entry = this.props.entry;
return h(
'div',
{},
h('div', { className: 'cover' }, h('h1', {}, entry.getIn(['data', 'title']))),
h('p', {}, h('small', {}, 'Written ' + entry.getIn(['data', 'date']))),
h('div', { className: 'text' }, this.props.widgetFor('body')),
);
},
});

var PagePreview = createClass({
render: function() {
var entry = this.props.entry;
return h(
'div',
{},
h('div', { className: 'cover' }, h('h1', {}, entry.getIn(['data', 'title']))),
h('p', {}, h('small', {}, 'Written ' + entry.getIn(['data', 'date']))),
h('div', { className: 'text' }, this.props.widgetFor('body')),
);
},
});

CMS.registerPreviewTemplate('posts', PostPreview);
CMS.registerPreviewTemplate('pages', PagePreview);
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions packages/decap-cms-core/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ declare module 'decap-cms-core' {

export type CmsPublishMode = 'simple' | 'editorial_workflow' | '';

export type CmsPublishWorkflowStatus = 'draft' | 'pending_review' | 'pending_publish';

export type CmsSlugEncoding = 'unicode' | 'ascii';

export interface CmsI18nConfig {
Expand Down Expand Up @@ -388,6 +390,7 @@ declare module 'decap-cms-core' {
media_folder_relative?: boolean;
media_library?: CmsMediaLibrary;
publish_mode?: CmsPublishMode;
default_workflow_status?: CmsPublishWorkflowStatus;
load_config_file?: boolean;
integrations?: {
hooks: string[];
Expand Down
28 changes: 28 additions & 0 deletions packages/decap-cms-core/src/actions/__tests__/config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
detectProxyServer,
handleLocalBackend,
} from '../config';
import { Statues } from '../../constants/publishModes';

jest.spyOn(console, 'log').mockImplementation(() => {});
jest.spyOn(console, 'warn').mockImplementation(() => {});
Expand Down Expand Up @@ -44,6 +45,7 @@ describe('config', () => {
local_backend: true
site_url: https://www.decapcms.org
publish_mode: editorial_workflow
default_workflow_status: pending_publish
media_folder: website/static/img
public_folder: img
docs_collection: &docs_collection
Expand All @@ -69,6 +71,7 @@ describe('config', () => {
local_backend: true,
site_url: 'https://www.decapcms.org',
publish_mode: 'editorial_workflow',
default_workflow_status: 'pending_publish',
media_folder: 'website/static/img',
public_folder: 'img',
docs_collection: {
Expand Down Expand Up @@ -120,6 +123,31 @@ describe('config', () => {
});
});

describe('default_workflow_status', () => {
it('should set default_workflow_status to "draft" by default if publish_mode is "editorial_workflow"', () => {
const config = {
publish_mode: 'editorial_workflow',
};
expect(applyDefaults(config).default_workflow_status).toEqual(Statues.DRAFT);
});

it('should set default_workflow_status to "draft" if the given one is unknown', () => {
const config = {
publish_mode: 'editorial_workflow',
default_workflow_status: 'unknown',
};
expect(applyDefaults(config).default_workflow_status).toEqual(Statues.DRAFT);
});

it('should set default_workflow_status from config', () => {
const config = {
publish_mode: 'editorial_workflow',
default_workflow_status: Statues.PENDING_REVIEW,
};
expect(applyDefaults(config).default_workflow_status).toEqual(Statues.PENDING_REVIEW);
});
});

describe('public_folder', () => {
it('should set public_folder based on media_folder if not set', () => {
expect(
Expand Down
14 changes: 13 additions & 1 deletion packages/decap-cms-core/src/actions/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import deepmerge from 'deepmerge';
import { produce } from 'immer';
import { trimStart, trim, isEmpty } from 'lodash';

import { SIMPLE as SIMPLE_PUBLISH_MODE } from '../constants/publishModes';
import {
EDITORIAL_WORKFLOW,
SIMPLE as SIMPLE_PUBLISH_MODE,
Statues,
} from '../constants/publishModes';
import { validateConfig } from '../constants/configSchema';
import { selectDefaultSortableFields } from '../reducers/collections';
import { getIntegrations, selectIntegration } from '../reducers/integrations';
Expand Down Expand Up @@ -210,6 +214,14 @@ export function applyDefaults(originalConfig: CmsConfig) {
config.slug = config.slug || {};
config.collections = config.collections || [];

if (config.publish_mode === EDITORIAL_WORKFLOW) {
config.default_workflow_status =
config.default_workflow_status &&
Object.values(Statues).includes(config.default_workflow_status)
? config.default_workflow_status
: Statues.DRAFT;
}

// Use `site_url` as default `display_url`.
if (!config.display_url && config.site_url) {
config.display_url = config.site_url;
Expand Down
5 changes: 2 additions & 3 deletions packages/decap-cms-core/src/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { basename, join, extname, dirname } from 'path';
import { stringTemplate } from 'decap-cms-lib-widgets';

import { resolveFormat } from './formats/formats';
import { selectUseWorkflow } from './reducers/config';
import { selectUseWorkflow, selectDefaultWorkflowStatus } from './reducers/config';
import { selectMediaFilePath, selectEntry } from './reducers/entries';
import { selectIntegration } from './reducers/integrations';
import {
Expand All @@ -33,7 +33,6 @@ import { createEntry } from './valueObjects/Entry';
import { sanitizeChar } from './lib/urlHelper';
import { getBackend, invokeEvent } from './lib/registry';
import { commitMessageFormatter, slugFormatter, previewUrlFormatter } from './lib/formatters';
import { status } from './constants/publishModes';
import { FOLDER, FILES } from './constants/collectionTypes';
import { selectCustomPath } from './reducers/entryDraft';
import {
Expand Down Expand Up @@ -354,7 +353,7 @@ export class Backend {
this.implementation = implementation.init(this.config, {
useWorkflow: selectUseWorkflow(this.config),
updateUserCredentials: this.updateUserCredentials,
initialWorkflowStatus: status.first(),
initialWorkflowStatus: selectDefaultWorkflowStatus(this.config),
});
this.backendName = backendName;
this.authStore = authStore;
Expand Down
6 changes: 6 additions & 0 deletions packages/decap-cms-core/src/constants/configSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import ajvErrors from 'ajv-errors';
import { v4 as uuid } from 'uuid';

import { Statues } from './publishModes';
import { frontmatterFormats, extensionFormatters } from '../formats/formats';
import { getWidgets } from '../lib/registry';
import { I18N_STRUCTURE, I18N_FIELD } from '../lib/i18n';
Expand Down Expand Up @@ -178,6 +179,11 @@ function getConfigSchema() {
enum: ['simple', 'editorial_workflow', ''],
examples: ['editorial_workflow'],
},
default_workflow_status: {
type: 'string',
enum: Object.values(Statues),
examples: [Statues.PENDING_PUBLISH],
},
slug: {
type: 'object',
properties: {
Expand Down
3 changes: 2 additions & 1 deletion packages/decap-cms-core/src/constants/publishModes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const Statues = {
DRAFT: 'draft',
PENDING_REVIEW: 'pending_review',
PENDING_PUBLISH: 'pending_publish',
};
} as const;

// Available status
export const status = OrderedMap(Statues);
Expand All @@ -20,3 +20,4 @@ export const statusDescriptions = Map({
});

export type Status = keyof typeof Statues;
export type StatusValues = (typeof Statues)[Status];
6 changes: 5 additions & 1 deletion packages/decap-cms-core/src/reducers/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { produce } from 'immer';

import { CONFIG_REQUEST, CONFIG_SUCCESS, CONFIG_FAILURE } from '../actions/config';
import { EDITORIAL_WORKFLOW } from '../constants/publishModes';
import { EDITORIAL_WORKFLOW, status } from '../constants/publishModes';

import type { ConfigAction } from '../actions/config';
import type { CmsConfig } from '../types/redux';
Expand Down Expand Up @@ -35,4 +35,8 @@ export function selectUseWorkflow(state: CmsConfig) {
return state.publish_mode === EDITORIAL_WORKFLOW;
}

export function selectDefaultWorkflowStatus(state: CmsConfig) {
return state.default_workflow_status || status.first();
}

export default config;
3 changes: 3 additions & 0 deletions packages/decap-cms-core/src/types/redux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { Search } from '../reducers/search';
import type { GlobalUI } from '../reducers/globalUI';
import type { NotificationsState } from '../reducers/notifications';
import type { formatExtensions } from '../formats/formats';
import type { StatusValues as PublishStatusValues } from '../constants/publishModes';

export type CmsBackendType =
| 'azure'
Expand Down Expand Up @@ -402,6 +403,7 @@ export interface CmsConfig {
media_folder_relative?: boolean;
media_library?: CmsMediaLibrary;
publish_mode?: CmsPublishMode;
default_workflow_status?: PublishStatusValues;
load_config_file?: boolean;
integrations?: {
hooks: string[];
Expand Down Expand Up @@ -457,6 +459,7 @@ export type Config = StaticallyTypedRecord<{
media_folder: string;
public_folder: string;
publish_mode?: string;
default_workflow_status?: string;
media_library: StaticallyTypedRecord<{ name: string }> & { name: string };
locale?: string;
slug: SlugConfig;
Expand Down