chore: refactoring deploys (#5135)
This commit is contained in:
committed by
GitHub
parent
a0ae13a665
commit
822acd4585
@ -1,86 +0,0 @@
|
|||||||
import { actions as notifActions } from 'redux-notifications';
|
|
||||||
import { currentBackend } from 'coreSrc/backend';
|
|
||||||
import { selectDeployPreview } from 'Reducers';
|
|
||||||
|
|
||||||
const { notifSend } = notifActions;
|
|
||||||
|
|
||||||
export const DEPLOY_PREVIEW_REQUEST = 'DEPLOY_PREVIEW_REQUEST';
|
|
||||||
export const DEPLOY_PREVIEW_SUCCESS = 'DEPLOY_PREVIEW_SUCCESS';
|
|
||||||
export const DEPLOY_PREVIEW_FAILURE = 'DEPLOY_PREVIEW_FAILURE';
|
|
||||||
|
|
||||||
export function deployPreviewLoading(collection, slug) {
|
|
||||||
return {
|
|
||||||
type: DEPLOY_PREVIEW_REQUEST,
|
|
||||||
payload: {
|
|
||||||
collection: collection.get('name'),
|
|
||||||
slug,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deployPreviewLoaded(collection, slug, { url, status }) {
|
|
||||||
return {
|
|
||||||
type: DEPLOY_PREVIEW_SUCCESS,
|
|
||||||
payload: {
|
|
||||||
collection: collection.get('name'),
|
|
||||||
slug,
|
|
||||||
url,
|
|
||||||
status,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deployPreviewError(collection, slug) {
|
|
||||||
return {
|
|
||||||
type: DEPLOY_PREVIEW_FAILURE,
|
|
||||||
payload: {
|
|
||||||
collection: collection.get('name'),
|
|
||||||
slug,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests a deploy preview object from the registered backend.
|
|
||||||
*/
|
|
||||||
export function loadDeployPreview(collection, slug, entry, published, opts) {
|
|
||||||
return async (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const backend = currentBackend(state.config);
|
|
||||||
|
|
||||||
// Exit if currently fetching
|
|
||||||
const deployState = selectDeployPreview(state, collection, slug);
|
|
||||||
if (deployState && deployState.get('isFetching')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(deployPreviewLoading(collection, slug));
|
|
||||||
|
|
||||||
try {
|
|
||||||
/**
|
|
||||||
* `getDeploy` is for published entries, while `getDeployPreview` is for
|
|
||||||
* unpublished entries.
|
|
||||||
*/
|
|
||||||
const deploy = published
|
|
||||||
? backend.getDeploy(collection, slug, entry)
|
|
||||||
: await backend.getDeployPreview(collection, slug, entry, opts);
|
|
||||||
if (deploy) {
|
|
||||||
return dispatch(deployPreviewLoaded(collection, slug, deploy));
|
|
||||||
}
|
|
||||||
return dispatch(deployPreviewError(collection, slug));
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
dispatch(
|
|
||||||
notifSend({
|
|
||||||
message: {
|
|
||||||
details: error.message,
|
|
||||||
key: 'ui.toast.onFailToLoadDeployPreview',
|
|
||||||
},
|
|
||||||
kind: 'danger',
|
|
||||||
dismissAfter: 8000,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
dispatch(deployPreviewError(collection, slug));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
105
packages/netlify-cms-core/src/actions/deploys.ts
Normal file
105
packages/netlify-cms-core/src/actions/deploys.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { actions as notifActions } from 'redux-notifications';
|
||||||
|
import { ThunkDispatch } from 'redux-thunk';
|
||||||
|
import { AnyAction } from 'redux';
|
||||||
|
import { currentBackend } from '../backend';
|
||||||
|
import { selectDeployPreview } from '../reducers';
|
||||||
|
import { Collection, Entry, State } from '../types/redux';
|
||||||
|
|
||||||
|
const { notifSend } = notifActions;
|
||||||
|
|
||||||
|
export const DEPLOY_PREVIEW_REQUEST = 'DEPLOY_PREVIEW_REQUEST';
|
||||||
|
export const DEPLOY_PREVIEW_SUCCESS = 'DEPLOY_PREVIEW_SUCCESS';
|
||||||
|
export const DEPLOY_PREVIEW_FAILURE = 'DEPLOY_PREVIEW_FAILURE';
|
||||||
|
|
||||||
|
function deployPreviewLoading(collection: string, slug: string) {
|
||||||
|
return {
|
||||||
|
type: DEPLOY_PREVIEW_REQUEST,
|
||||||
|
payload: {
|
||||||
|
collection,
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deployPreviewLoaded(
|
||||||
|
collection: string,
|
||||||
|
slug: string,
|
||||||
|
deploy: { url: string | undefined; status: string },
|
||||||
|
) {
|
||||||
|
const { url, status } = deploy;
|
||||||
|
return {
|
||||||
|
type: DEPLOY_PREVIEW_SUCCESS,
|
||||||
|
payload: {
|
||||||
|
collection,
|
||||||
|
slug,
|
||||||
|
url,
|
||||||
|
status,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deployPreviewError(collection: string, slug: string) {
|
||||||
|
return {
|
||||||
|
type: DEPLOY_PREVIEW_FAILURE,
|
||||||
|
payload: {
|
||||||
|
collection,
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a deploy preview object from the registered backend.
|
||||||
|
*/
|
||||||
|
export function loadDeployPreview(
|
||||||
|
collection: Collection,
|
||||||
|
slug: string,
|
||||||
|
entry: Entry,
|
||||||
|
published: boolean,
|
||||||
|
opts?: { maxAttempts?: number; interval?: number },
|
||||||
|
) {
|
||||||
|
return async (dispatch: ThunkDispatch<State, undefined, AnyAction>, getState: () => State) => {
|
||||||
|
const state = getState();
|
||||||
|
const backend = currentBackend(state.config);
|
||||||
|
const collectionName = collection.get('name');
|
||||||
|
|
||||||
|
// Exit if currently fetching
|
||||||
|
const deployState = selectDeployPreview(state, collectionName, slug);
|
||||||
|
if (deployState && deployState.isFetching) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(deployPreviewLoading(collectionName, slug));
|
||||||
|
|
||||||
|
try {
|
||||||
|
/**
|
||||||
|
* `getDeploy` is for published entries, while `getDeployPreview` is for
|
||||||
|
* unpublished entries.
|
||||||
|
*/
|
||||||
|
const deploy = published
|
||||||
|
? backend.getDeploy(collection, slug, entry)
|
||||||
|
: await backend.getDeployPreview(collection, slug, entry, opts);
|
||||||
|
if (deploy) {
|
||||||
|
return dispatch(deployPreviewLoaded(collectionName, slug, deploy));
|
||||||
|
}
|
||||||
|
return dispatch(deployPreviewError(collectionName, slug));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
dispatch(
|
||||||
|
notifSend({
|
||||||
|
message: {
|
||||||
|
details: error.message,
|
||||||
|
key: 'ui.toast.onFailToLoadDeployPreview',
|
||||||
|
},
|
||||||
|
kind: 'danger',
|
||||||
|
dismissAfter: 8000,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
dispatch(deployPreviewError(collectionName, slug));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DeploysAction = ReturnType<
|
||||||
|
typeof deployPreviewLoading | typeof deployPreviewLoaded | typeof deployPreviewError
|
||||||
|
>;
|
@ -64,7 +64,7 @@ export class Editor extends React.Component {
|
|||||||
deleteUnpublishedEntry: PropTypes.func.isRequired,
|
deleteUnpublishedEntry: PropTypes.func.isRequired,
|
||||||
logoutUser: PropTypes.func.isRequired,
|
logoutUser: PropTypes.func.isRequired,
|
||||||
loadEntries: PropTypes.func.isRequired,
|
loadEntries: PropTypes.func.isRequired,
|
||||||
deployPreview: ImmutablePropTypes.map,
|
deployPreview: PropTypes.object,
|
||||||
loadDeployPreview: PropTypes.func.isRequired,
|
loadDeployPreview: PropTypes.func.isRequired,
|
||||||
currentStatus: PropTypes.string,
|
currentStatus: PropTypes.string,
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
|
@ -422,7 +422,7 @@ EditorInterface.propTypes = {
|
|||||||
isModification: PropTypes.bool,
|
isModification: PropTypes.bool,
|
||||||
currentStatus: PropTypes.string,
|
currentStatus: PropTypes.string,
|
||||||
onLogoutClick: PropTypes.func.isRequired,
|
onLogoutClick: PropTypes.func.isRequired,
|
||||||
deployPreview: ImmutablePropTypes.map,
|
deployPreview: PropTypes.object,
|
||||||
loadDeployPreview: PropTypes.func.isRequired,
|
loadDeployPreview: PropTypes.func.isRequired,
|
||||||
draftKey: PropTypes.string.isRequired,
|
draftKey: PropTypes.string.isRequired,
|
||||||
t: PropTypes.func.isRequired,
|
t: PropTypes.func.isRequired,
|
||||||
|
@ -4,7 +4,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||||||
import { css } from '@emotion/core';
|
import { css } from '@emotion/core';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { translate } from 'react-polyglot';
|
import { translate } from 'react-polyglot';
|
||||||
import { Map } from 'immutable';
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
Icon,
|
Icon,
|
||||||
@ -244,7 +243,7 @@ class EditorToolbar extends React.Component {
|
|||||||
isModification: PropTypes.bool,
|
isModification: PropTypes.bool,
|
||||||
currentStatus: PropTypes.string,
|
currentStatus: PropTypes.string,
|
||||||
onLogoutClick: PropTypes.func.isRequired,
|
onLogoutClick: PropTypes.func.isRequired,
|
||||||
deployPreview: ImmutablePropTypes.map,
|
deployPreview: PropTypes.object,
|
||||||
loadDeployPreview: PropTypes.func.isRequired,
|
loadDeployPreview: PropTypes.func.isRequired,
|
||||||
t: PropTypes.func.isRequired,
|
t: PropTypes.func.isRequired,
|
||||||
editorBackLink: PropTypes.string.isRequired,
|
editorBackLink: PropTypes.string.isRequired,
|
||||||
@ -276,15 +275,13 @@ class EditorToolbar extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderDeployPreviewControls = label => {
|
renderDeployPreviewControls = label => {
|
||||||
const { deployPreview = Map(), loadDeployPreview, t } = this.props;
|
const { deployPreview = {}, loadDeployPreview, t } = this.props;
|
||||||
const url = deployPreview.get('url');
|
const { url, status, isFetching } = deployPreview;
|
||||||
const status = deployPreview.get('status');
|
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFetching = deployPreview.get('isFetching');
|
|
||||||
const deployPreviewReady = status === 'SUCCESS' && !isFetching;
|
const deployPreviewReady = status === 'SUCCESS' && !isFetching;
|
||||||
return (
|
return (
|
||||||
<PreviewButtonContainer>
|
<PreviewButtonContainer>
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
import { Map, fromJS } from 'immutable';
|
|
||||||
import {
|
|
||||||
DEPLOY_PREVIEW_REQUEST,
|
|
||||||
DEPLOY_PREVIEW_SUCCESS,
|
|
||||||
DEPLOY_PREVIEW_FAILURE,
|
|
||||||
} from 'Actions/deploys';
|
|
||||||
|
|
||||||
function deploys(state = Map({ deploys: Map() }), action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case DEPLOY_PREVIEW_REQUEST: {
|
|
||||||
const { collection, slug } = action.payload;
|
|
||||||
return state.setIn(['deploys', `${collection}.${slug}`, 'isFetching'], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEPLOY_PREVIEW_SUCCESS: {
|
|
||||||
const { collection, slug, url, status } = action.payload;
|
|
||||||
return state.setIn(
|
|
||||||
['deploys', `${collection}.${slug}`],
|
|
||||||
fromJS({
|
|
||||||
isFetching: false,
|
|
||||||
url,
|
|
||||||
status,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEPLOY_PREVIEW_FAILURE: {
|
|
||||||
const { collection, slug } = action.payload;
|
|
||||||
return state.setIn(
|
|
||||||
['deploys', `${collection}.${slug}`],
|
|
||||||
fromJS({
|
|
||||||
isFetching: false,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectDeployPreview(state, collection, slug) {
|
|
||||||
return state.getIn(['deploys', `${collection}.${slug}`]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default deploys;
|
|
50
packages/netlify-cms-core/src/reducers/deploys.ts
Normal file
50
packages/netlify-cms-core/src/reducers/deploys.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { produce } from 'immer';
|
||||||
|
import {
|
||||||
|
DEPLOY_PREVIEW_REQUEST,
|
||||||
|
DEPLOY_PREVIEW_SUCCESS,
|
||||||
|
DEPLOY_PREVIEW_FAILURE,
|
||||||
|
DeploysAction,
|
||||||
|
} from '../actions/deploys';
|
||||||
|
|
||||||
|
export type Deploys = {
|
||||||
|
[key: string]: {
|
||||||
|
isFetching: boolean;
|
||||||
|
url?: string;
|
||||||
|
status?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultState: Deploys = {};
|
||||||
|
|
||||||
|
const deploys = produce((state: Deploys, action: DeploysAction) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case DEPLOY_PREVIEW_REQUEST: {
|
||||||
|
const { collection, slug } = action.payload;
|
||||||
|
const key = `${collection}.${slug}`;
|
||||||
|
state[key] = state[key] || {};
|
||||||
|
state[key].isFetching = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEPLOY_PREVIEW_SUCCESS: {
|
||||||
|
const { collection, slug, url, status } = action.payload;
|
||||||
|
const key = `${collection}.${slug}`;
|
||||||
|
state[key].isFetching = false;
|
||||||
|
state[key].url = url;
|
||||||
|
state[key].status = status;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEPLOY_PREVIEW_FAILURE: {
|
||||||
|
const { collection, slug } = action.payload;
|
||||||
|
state[`${collection}.${slug}`].isFetching = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, defaultState);
|
||||||
|
|
||||||
|
export function selectDeployPreview(state: Deploys, collection: string, slug: string) {
|
||||||
|
return state[`${collection}.${slug}`];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default deploys;
|
@ -6,6 +6,7 @@ import { MediaFile as BackendMediaFile } from '../backend';
|
|||||||
import { Auth } from '../reducers/auth';
|
import { Auth } from '../reducers/auth';
|
||||||
import { Status } from '../reducers/status';
|
import { Status } from '../reducers/status';
|
||||||
import { Medias } from '../reducers/medias';
|
import { Medias } from '../reducers/medias';
|
||||||
|
import { Deploys } from '../reducers/deploys';
|
||||||
|
|
||||||
export type CmsBackendType =
|
export type CmsBackendType =
|
||||||
| 'azure'
|
| 'azure'
|
||||||
@ -510,8 +511,6 @@ export type Entries = StaticallyTypedRecord<{
|
|||||||
viewStyle: string;
|
viewStyle: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type Deploys = StaticallyTypedRecord<{}>;
|
|
||||||
|
|
||||||
export type EditorialWorkflow = StaticallyTypedRecord<{
|
export type EditorialWorkflow = StaticallyTypedRecord<{
|
||||||
pages: Pages & PagesObject;
|
pages: Pages & PagesObject;
|
||||||
entities: Entities & EntitiesObject;
|
entities: Entities & EntitiesObject;
|
||||||
|
Reference in New Issue
Block a user