@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
257 lines (255 loc) • 9.55 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import RepoGridUI from './RepoGridUI';
import React, { useState } from 'react';
import PullDialog from '../PullDialog';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import PushDialog from '../PushDialog';
import { deleteRemote as deleteRemoteService } from '../../../services/repositories';
import { showSystemNotification } from '../../../state/actions/system';
import { showErrorDialog } from '../../../state/reducers/dialogs/error';
import { useDispatch } from 'react-redux';
import { useActiveSiteId } from '../../../hooks/useActiveSiteId';
import { useEnhancedDialogState } from '../../../hooks/useEnhancedDialogState';
import SnackbarContent, { snackbarContentClasses } from '@mui/material/SnackbarContent';
import InputBase from '@mui/material/InputBase';
import Button from '@mui/material/Button';
import Snackbar from '@mui/material/Snackbar';
import { useSnackbar } from 'notistack';
import { copyToClipboard } from '../../../utils/system';
import PublishCommitDialog from '../PublishCommitDialog/PublishCommitDialog';
import useSpreadState from '../../../hooks/useSpreadState';
import RepoGridSkeleton from './RepoGridSkeleton';
const messages = defineMessages({
mergeStrategyNone: {
id: 'repositories.mergeStrategyNone',
defaultMessage: 'None'
},
mergeStrategyOurs: {
id: 'repositories.mergeStrategyOurs',
defaultMessage: 'Accept Ours'
},
mergeStrategyTheirs: {
id: 'repositories.mergeStrategyTheirs',
defaultMessage: 'Accept Theirs'
},
remoteDeleteSuccessMessage: {
id: 'repositories.remoteDeleteSuccessMessage',
defaultMessage: 'Remote repository deleted successfully.'
},
pullSuccessMessage: {
id: 'repositories.pullSuccessMessage',
defaultMessage: 'Successfully pulled {numberOfCommits} commits. Would you like to publish this now?'
},
pullSuccessNoChangesMessage: {
id: 'repositories.pullSuccessNoChangesMessage',
defaultMessage: 'Pull successful: already up to date.'
},
pushSuccessMessage: {
id: 'repositories.pushSuccessMessage',
defaultMessage: 'Successfully pushed.'
}
});
export function RepoGrid(props) {
const { repositories, disableActions, onPullSuccess: onPullSuccessProp, onPullError, fetchRepositories } = props;
const [repositoriesPushDialogBranches, setRepositoriesPushDialogBranches] = useState([]);
const [pullRemoteName, setPullRemoteName] = useState(null);
const [pushRemoteName, setPushRemoteName] = useState(null);
const { formatMessage } = useIntl();
const mergeStrategies = [
{
key: 'none',
value: formatMessage(messages.mergeStrategyNone)
},
{
key: 'ours',
value: formatMessage(messages.mergeStrategyOurs)
},
{
key: 'theirs',
value: formatMessage(messages.mergeStrategyTheirs)
}
];
const siteId = useActiveSiteId();
const dispatch = useDispatch();
const pushToRemoteDialogState = useEnhancedDialogState();
const pullFromRemoteDialogState = useEnhancedDialogState();
const { enqueueSnackbar } = useSnackbar();
const publishCommitDialogState = useEnhancedDialogState();
const [postPullState, setPostPullState] = useSpreadState({
openPostPullSnack: false,
mergeCommitId: '',
commitsMerged: 0
});
const onClickPull = (remoteName, branches) => {
setPullRemoteName(remoteName);
pullFromRemoteDialogState.onOpen();
};
const onClickPush = (remoteName, branches) => {
setRepositoriesPushDialogBranches(branches);
setPushRemoteName(remoteName);
pushToRemoteDialogState.onOpen();
};
const onPullSuccess = (result) => {
onPullSuccessProp(result);
pullFromRemoteDialogState.onClose();
if (result.mergeCommitId) {
setPostPullState({ openPostPullSnack: true, ...result });
} else {
dispatch(
showSystemNotification({
message: formatMessage(messages.pullSuccessNoChangesMessage)
})
);
}
};
const onPushSuccess = () => {
pushToRemoteDialogState.onResetState();
dispatch(
showSystemNotification({
message: formatMessage(messages.pushSuccessMessage)
})
);
};
const onPushError = (response) => {
pushToRemoteDialogState.onClose();
dispatch(showErrorDialog({ error: response }));
};
const deleteRemote = (remoteName) => {
deleteRemoteService(siteId, remoteName).subscribe(
() => {
fetchRepositories();
dispatch(
showSystemNotification({
message: formatMessage(messages.remoteDeleteSuccessMessage)
})
);
},
({ response }) => {
dispatch(showErrorDialog({ error: response }));
}
);
};
const onClosePostPullSnack = () => setPostPullState({ openPostPullSnack: false });
return React.createElement(
React.Fragment,
null,
repositories
? React.createElement(RepoGridUI, {
repositories: repositories,
disableActions: disableActions,
onPullClick: onClickPull,
onPushClick: onClickPush,
onDeleteRemote: deleteRemote
})
: React.createElement(RepoGridSkeleton, null),
React.createElement(
Snackbar,
{
autoHideDuration: 10000,
onClose: onClosePostPullSnack,
open: postPullState.openPostPullSnack,
sx: { maxWidth: '500px' }
},
React.createElement(SnackbarContent, {
sx: { [`.${snackbarContentClasses.message}`]: { width: '100%' } },
message: React.createElement(
React.Fragment,
null,
formatMessage(messages.pullSuccessMessage, { numberOfCommits: postPullState.commitsMerged }),
React.createElement(InputBase, {
sx: { display: 'block', mt: 1, borderRadius: 1, pr: 0.5, pl: 0.5 },
autoFocus: true,
value: postPullState.mergeCommitId,
readOnly: true,
onClick: (e) => {
e.target.select();
copyToClipboard(postPullState.mergeCommitId).then(function () {
enqueueSnackbar('Copied');
});
}
})
),
action: React.createElement(
React.Fragment,
null,
React.createElement(
Button,
{
size: 'small',
onClick: () => {
publishCommitDialogState.onOpen();
setPostPullState({ openPostPullSnack: false });
}
},
React.createElement(FormattedMessage, { id: 'words.yes', defaultMessage: 'Yes' })
),
React.createElement(
Button,
{ size: 'small', onClick: onClosePostPullSnack },
React.createElement(FormattedMessage, { id: 'words.no', defaultMessage: 'No' })
)
)
})
),
React.createElement(PullDialog, {
open: pullFromRemoteDialogState.open,
onClose: pullFromRemoteDialogState.onClose,
remoteName: pullRemoteName,
mergeStrategies: mergeStrategies,
onPullSuccess: onPullSuccess,
onPullError: onPullError,
isMinimized: pullFromRemoteDialogState.isMinimized,
isSubmitting: pullFromRemoteDialogState.isSubmitting,
hasPendingChanges: pullFromRemoteDialogState.hasPendingChanges
}),
React.createElement(PushDialog, {
open: pushToRemoteDialogState.open,
branches: repositoriesPushDialogBranches,
remoteName: pushRemoteName,
onClose: pushToRemoteDialogState.onClose,
onPushSuccess: onPushSuccess,
onPushError: onPushError,
isMinimized: pushToRemoteDialogState.isMinimized,
isSubmitting: pushToRemoteDialogState.isSubmitting,
hasPendingChanges: pushToRemoteDialogState.hasPendingChanges,
onSubmittingChange: pushToRemoteDialogState.onSubmittingChange
}),
React.createElement(PublishCommitDialog, {
commitId: postPullState.mergeCommitId,
open: publishCommitDialogState.open,
hasPendingChanges: publishCommitDialogState.hasPendingChanges,
onSubmittingAndOrPendingChange: publishCommitDialogState.onSubmittingAndOrPendingChange,
onClose: publishCommitDialogState.onClose
})
);
}
export default RepoGrid;