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,
|
||||
logoutUser: PropTypes.func.isRequired,
|
||||
loadEntries: PropTypes.func.isRequired,
|
||||
deployPreview: ImmutablePropTypes.map,
|
||||
deployPreview: PropTypes.object,
|
||||
loadDeployPreview: PropTypes.func.isRequired,
|
||||
currentStatus: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
|
@ -422,7 +422,7 @@ EditorInterface.propTypes = {
|
||||
isModification: PropTypes.bool,
|
||||
currentStatus: PropTypes.string,
|
||||
onLogoutClick: PropTypes.func.isRequired,
|
||||
deployPreview: ImmutablePropTypes.map,
|
||||
deployPreview: PropTypes.object,
|
||||
loadDeployPreview: PropTypes.func.isRequired,
|
||||
draftKey: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
|
@ -4,7 +4,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { css } from '@emotion/core';
|
||||
import styled from '@emotion/styled';
|
||||
import { translate } from 'react-polyglot';
|
||||
import { Map } from 'immutable';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
Icon,
|
||||
@ -244,7 +243,7 @@ class EditorToolbar extends React.Component {
|
||||
isModification: PropTypes.bool,
|
||||
currentStatus: PropTypes.string,
|
||||
onLogoutClick: PropTypes.func.isRequired,
|
||||
deployPreview: ImmutablePropTypes.map,
|
||||
deployPreview: PropTypes.object,
|
||||
loadDeployPreview: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
editorBackLink: PropTypes.string.isRequired,
|
||||
@ -276,15 +275,13 @@ class EditorToolbar extends React.Component {
|
||||
};
|
||||
|
||||
renderDeployPreviewControls = label => {
|
||||
const { deployPreview = Map(), loadDeployPreview, t } = this.props;
|
||||
const url = deployPreview.get('url');
|
||||
const status = deployPreview.get('status');
|
||||
const { deployPreview = {}, loadDeployPreview, t } = this.props;
|
||||
const { url, status, isFetching } = deployPreview;
|
||||
|
||||
if (!status) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isFetching = deployPreview.get('isFetching');
|
||||
const deployPreviewReady = status === 'SUCCESS' && !isFetching;
|
||||
return (
|
||||
<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 { Status } from '../reducers/status';
|
||||
import { Medias } from '../reducers/medias';
|
||||
import { Deploys } from '../reducers/deploys';
|
||||
|
||||
export type CmsBackendType =
|
||||
| 'azure'
|
||||
@ -510,8 +511,6 @@ export type Entries = StaticallyTypedRecord<{
|
||||
viewStyle: string;
|
||||
}>;
|
||||
|
||||
export type Deploys = StaticallyTypedRecord<{}>;
|
||||
|
||||
export type EditorialWorkflow = StaticallyTypedRecord<{
|
||||
pages: Pages & PagesObject;
|
||||
entities: Entities & EntitiesObject;
|
||||
|
Reference in New Issue
Block a user