Skip to content

Commit

Permalink
Toolbar export action modal (#4157)
Browse files Browse the repository at this point in the history
  • Loading branch information
thecalcc authored Dec 20, 2022
1 parent 6380a4a commit 489d54e
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 1 deletion.
36 changes: 35 additions & 1 deletion scripts/apps/authoring-react/authoring-integration-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {dispatchInternalEvent} from 'core/internal-events';
import {IArticleActionInteractive} from 'core/interactive-article-actions-panel/interfaces';
import {ARTICLE_RELATED_RESOURCE_NAMES} from 'core/constants';
import {IProps} from './authoring-angular-integration';
import {showModal} from '@superdesk/common';
import ExportModal from './toolbar/export-modal';

function getAuthoringActionsFromExtensions(
item: IArticle,
Expand Down Expand Up @@ -103,6 +105,30 @@ function getPublishToolbarWidget(
return publishWidgetButton;
}

const getExportModal = (
getLatestItem: () => IArticle,
handleUnsavedChanges: () => Promise<IArticle>,
hasUnsavedChanges: () => boolean,
): IAuthoringAction => ({
label: gettext('Export'),
onTrigger: () => {
const openModal = (article: IArticle) => showModal(({closeModal}) => {
return (
<ExportModal
closeModal={closeModal}
article={article}
/>
);
});

if (hasUnsavedChanges()) {
handleUnsavedChanges().then((article) => openModal(article));
} else {
openModal(getLatestItem());
}
},
});

interface IPropsWrapper extends IProps {
onClose?(): void;
getInlineToolbarActions?(options: IExposedFromAuthoring<IArticle>): {
Expand Down Expand Up @@ -228,14 +254,22 @@ export class AuthoringIntegrationWrapper extends React.PureComponent<IPropsWrapp
onEditingEnd={(article) => {
dispatchCustomEvent('articleEditEnd', article);
}}
getActions={({item, contentProfile, fieldsData}) => {
getActions={({
item,
contentProfile,
fieldsData,
getLatestItem,
handleUnsavedChanges,
hasUnsavedChanges,
}) => {
return Promise.all([
getAuthoringActionsFromExtensions(item, contentProfile, fieldsData),
getArticleActionsFromExtensions(item),
]).then((res) => {
const [authoringActionsFromExtensions, articleActionsFromExtensions] = res;

return [
getExportModal(getLatestItem, handleUnsavedChanges, hasUnsavedChanges),
...authoringActionsFromExtensions,
...articleActionsFromExtensions,
];
Expand Down
126 changes: 126 additions & 0 deletions scripts/apps/authoring-react/toolbar/export-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {httpRequestJsonLocal} from 'core/helpers/network';
import {Spacer} from 'core/ui/components/Spacer';
import {gettext} from 'core/utils';
import React from 'react';
import {IArticle, IArticleFormatter, IRestApiResponse} from 'superdesk-api';
import {Modal, Select, Switch, Option, Button} from 'superdesk-ui-framework/react';

interface IProps {
closeModal(): void;
article: IArticle;
}

interface IStateLoading {
initialized: false;
}

interface IStateLoaded {
initialized: true;
validate: boolean;
selectedFormatter: string | null;
availableFormatters: Array<any> | null;
}

type IState = IStateLoaded | IStateLoading;

export default class ExportModal extends React.PureComponent<IProps, IState> {
constructor(props: IProps) {
super(props);

this.state = {
initialized: false,
};

this.exportArticle = this.exportArticle.bind(this);
}

componentDidMount(): void {
httpRequestJsonLocal<IRestApiResponse<IArticleFormatter>>({
method: 'GET',
path: '/formatters',
urlParams: {
criteria: 'can_export',
},
}).then((result) => {
this.setState({
...this.state,
initialized: true,
availableFormatters: result._items,
});
});
}

private exportArticle() {
if (this.state.initialized) {
return httpRequestJsonLocal({
method: 'POST',
path: '/export',
payload: {
item_ids: [this.props.article._id],
validate: this.state.validate,
format_type: this.state.selectedFormatter,
},
}).then((response: any) => {
window.open(response.url);
this.props.closeModal();
});
}
}

render(): JSX.Element {
const state = this.state;

if (!state.initialized) {
return null;
}

return (
<Modal
size="medium"
onHide={this.props.closeModal}
visible
zIndex={1050}
headerTemplate={gettext('Export')}
>
<Spacer v gap="32">
<Select
value={state.selectedFormatter}
onChange={(value) => this.setState({...state, selectedFormatter: value})}
label={gettext('Formatters')}
>
<Option />
{
state.availableFormatters.map(({name}) => {
return (
<Option
key={name}
>
{name}
</Option>
);
})
}
</Select>
<Switch
label={{text: gettext('Validate'), side: 'left'}}
value={state.validate}
onChange={(value) => this.setState({...state, validate: value})}
/>
<Spacer h gap="8" justifyContent="end" noGrow>
<Button
onClick={() => this.exportArticle()}
type="primary"
text={gettext('Export')}
disabled={state.selectedFormatter?.length > 0}
/>
<Button
onClick={() => this.props.closeModal()}
type="default"
text={gettext('Cancel')}
/>
</Spacer>
</Spacer>
</Modal>
);
}
}
4 changes: 4 additions & 0 deletions scripts/core/superdesk-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,10 @@ declare module 'superdesk-api' {

export type IPropsLockInfo<T extends ILockInfo> = IPropsLockInfoReadOnly<T> | IPropsLockInfoCanUnlock<T>;

export interface IArticleFormatter extends IBaseRestApiResponse {
name: string;
}

export interface IArticle extends IBaseRestApiResponse {
_id: string;
_current_version: number;
Expand Down

0 comments on commit 489d54e

Please sign in to comment.