Skip to content

Commit

Permalink
Provide planning details widget from the extension (#2078)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaskikutis authored Sep 16, 2024
1 parent a480add commit 1abfedf
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 136 deletions.
3 changes: 3 additions & 0 deletions TAGS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# TAG: AUTHORING-ANGULAR

AUTHORING-ANGULAR tag is meant to mark code that has to be removed together with angular based authoring component when time comes.
35 changes: 19 additions & 16 deletions client/components/PlanningDetailsWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React from 'react';
import {Provider} from 'react-redux';
import {connectServices} from 'superdesk-core/scripts/core/helpers/ReactRenderAsync';
import ng from 'superdesk-core/scripts/core/services/ng';
import {PlanningPreviewContent} from './Planning/PlanningPreviewContent';
import {modifyForClient} from '../utils/planning';
import {WORKSPACE} from '../constants';
import {fetchAgendas} from '../actions';

interface IProps {
api: any;
sdPlanningStore: any;
item: {
assignment_id: string;
};
Expand All @@ -19,7 +17,9 @@ interface IState {
planning: any;
}

export function getItemPlanningInfo(item: IProps['item'], api: IProps['api']) {
export function getItemPlanningInfo(item: {assignment_id: string}) {
const api = ng.get('api');

if (item.assignment_id != null) {
return api.find('assignments', item.assignment_id)
.then((assignment) => api.find('planning', assignment.planning_item))
Expand All @@ -30,17 +30,25 @@ export function getItemPlanningInfo(item: IProps['item'], api: IProps['api']) {
}

class PlanningDetailsWidget extends React.Component<IProps, IState> {
static defaultProps: Partial<IProps>;
readonly state = {store: null, planning: null};
private sdPlanningStore: any;

constructor(props: IProps) {
super(props);

this.sdPlanningStore = ng.get('sdPlanningStore');
}

componentDidMount() {
const {item, api, sdPlanningStore} = this.props;
const {item} = this.props;

// Allow the Planning item and store to be loaded concurrently
getItemPlanningInfo(item, api).then((planning) => {
getItemPlanningInfo(item).then((planning) => {
this.setState({planning});
});

sdPlanningStore.initWorkspace(WORKSPACE.AUTHORING_WIDGET, (store) => {
this.sdPlanningStore.initWorkspace(WORKSPACE.AUTHORING_WIDGET, (store) => {
// Fetch the agendas before saving the store to the state
store.dispatch(fetchAgendas()).then(() => {
this.setState({store});
Expand All @@ -55,16 +63,11 @@ class PlanningDetailsWidget extends React.Component<IProps, IState> {
}

return (
<div className="widget sd-padding-all--2">
<Provider store={this.state.store}>
<PlanningPreviewContent item={this.state.planning} />
</Provider>
</div>
<Provider store={this.state.store}>
<PlanningPreviewContent item={this.state.planning} noPadding />
</Provider>
);
}
}

export default connectServices<IProps>(
PlanningDetailsWidget,
['api', 'sdPlanningStore'],
);
export default PlanningDetailsWidget;
12 changes: 11 additions & 1 deletion client/extension_bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {getVocabularyItemFieldTranslated} from './utils/vocabularies';
import {getUserInterfaceLanguageFromCV} from './utils/users';

import {registerEditorField} from './components/fields/resources/registerEditorFields';
import {IAssignmentItem, IEditorFieldProps, IPlanningAppState} from 'interfaces';
import {IAssignmentItem, IEditorFieldProps, IPlanningAppState, IPlanningItem} from 'interfaces';

import PlanningDetailsWidget, {getItemPlanningInfo} from './components/PlanningDetailsWidget';

// KEEP IN SYNC WITH client/planning-extension/src/extension_bridge.ts
interface IExtensionBridge {
Expand All @@ -29,6 +31,9 @@ interface IExtensionBridge {
StateComponent: React.ComponentType<{assignment: IAssignmentItem}>;
};
};
planning: {
getItemPlanningInfo(item: {assignment_id?: string}): Promise<IPlanningItem>;
},
ui: {
utils: {
getUserInterfaceLanguageFromCV(): string;
Expand All @@ -45,6 +50,7 @@ interface IExtensionBridge {

components: {
EditorFieldVocabulary: React.ComponentType<IEditorFieldVocabularyProps>;
PlanningDetailsWidget: React.ComponentType<{item: {assignment_id: string}}>;
};
};
fields: {
Expand Down Expand Up @@ -75,13 +81,17 @@ export const extensionBridge: IExtensionBridge = {
StateComponent,
},
},
planning: {
getItemPlanningInfo,
},
ui: {
utils: {
getUserInterfaceLanguageFromCV,
getVocabularyItemFieldTranslated,
},
components: {
EditorFieldVocabulary,
PlanningDetailsWidget,
},
},
fields: {
Expand Down
20 changes: 0 additions & 20 deletions client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import ng from 'superdesk-core/scripts/core/services/ng';
import * as actions from './actions';
import {PublishQueuePanel} from './apps';
import {gettext} from './utils';
import {reactToAngular1} from 'superdesk-ui-framework';
import PlanningDetailsWidget, {getItemPlanningInfo} from './components/PlanningDetailsWidget';

import {getSuperdeskApiImplementation} from 'superdesk-core/scripts/core/get-superdesk-api-implementation';
import {superdeskApi} from './superdeskApi';
Expand Down Expand Up @@ -51,7 +49,6 @@ export default angular.module('superdesk-planning', [])
controller: ctrl.LocationsController,
})
)
.component('sdPlanningDetailsWidget', reactToAngular1(PlanningDetailsWidget, ['item']))
.service('sdPlanningStore', svc.PlanningStoreService)
.service('assignments', svc.AssignmentsService)
.config(['workspaceMenuProvider', (workspaceMenuProvider) => {
Expand All @@ -76,24 +73,7 @@ export default angular.module('superdesk-planning', [])
shortcut: 'ctrl+alt+p',
});
}])
.config(['authoringWidgetsProvider', (authoringWidgetsProvider) => {
authoringWidgetsProvider.widget('planning-details', {
label: gettext('Planning Details'),
icon: 'tasks',
side: 'right',
order: 80,
template: 'planning-details-widget.html',
display: {
authoring: true,
},
configurable: false,
badgeAsync: ['item', 'api', (item, api) =>
getItemPlanningInfo(item, api).then((planning) => planning.coverages.length)],
isWidgetVisible: (item) => [() => item.assignment_id != null],
});
}])
.run(['$templateCache', ($templateCache) => {
$templateCache.put('planning-details-widget.html', require('./views/planning-details-widget.html'));
$templateCache.put('locations.html', require('./views/locations.html'));
}])
.run([
Expand Down
25 changes: 25 additions & 0 deletions client/planning-extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import {IPlanningExtensionConfigurationOptions} from './extension_configuration_
import {AutopostIngestRuleEditor} from './ingest_rule_autopost/AutopostIngestRuleEditor';
import {AutopostIngestRulePreview} from './ingest_rule_autopost/AutopostIngestRulePreview';
import {extensionBridge} from './extension_bridge';
import {
PlanningDetailsWidget,
PLANNING_DETAILS_WIDGET_ID,
PLANNING_DETAILS_WIDGET_LABEL,
} from './planning-details-widget';

function onSpike(superdesk: ISuperdesk, item: IArticle) {
const {gettext} = superdesk.localization;
Expand Down Expand Up @@ -109,6 +114,8 @@ const extension: IExtension = {
&& extensionConfig?.assignmentsTopBarWidget === true;
const {gettext} = superdesk.localization;

const {getItemPlanningInfo} = extensionBridge.planning;

const result: IExtensionActivationResult = {
contributions: {
entities: {
Expand Down Expand Up @@ -158,6 +165,24 @@ const extension: IExtension = {
notifications: {
'email:notification:assignments': {name: superdesk.localization.gettext('Assignment')}
},
authoringSideWidgets: [
{
_id: PLANNING_DETAILS_WIDGET_ID,
label: PLANNING_DETAILS_WIDGET_LABEL,
order: 12,
icon: 'tasks',
component: PlanningDetailsWidget,
isAllowed: (item) => item.assignment_id != null,
getBadge: (item) => { // KEEP IN SYNC WITH client/index.ts
if (item.assignment_id == null) {
return Promise.resolve(null);
}

return getItemPlanningInfo({assignment_id: item.assignment_id})
.then((planning) => planning.coverages.length.toString());
},
},
],
globalMenuHorizontal: displayTopbarWidget ? [AssignmentsList] : [],
},
};
Expand Down
6 changes: 5 additions & 1 deletion client/planning-extension/src/extension_bridge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import {IVocabularyItem} from 'superdesk-api';
import {IAssignmentItem, IEditorFieldProps, IPlanningAppState} from '../../interfaces';
import {IAssignmentItem, IEditorFieldProps, IPlanningAppState, IPlanningItem} from '../../interfaces';

interface IEditorFieldVocabularyProps extends IEditorFieldProps {
options: Array<any>;
Expand All @@ -27,6 +27,9 @@ interface IExtensionBridge {
StateComponent: React.ComponentType<{assignment: IAssignmentItem}>;
};
};
planning: {
getItemPlanningInfo(item: {assignment_id?: string}): Promise<IPlanningItem>;
},
ui: {
utils: {
getUserInterfaceLanguageFromCV(): string;
Expand All @@ -42,6 +45,7 @@ interface IExtensionBridge {
};
components: {
EditorFieldVocabulary: React.ComponentType<IEditorFieldVocabularyProps>;
PlanningDetailsWidget: React.ComponentType<{item: {assignment_id: string}}>;
};
};
fields: {
Expand Down
35 changes: 35 additions & 0 deletions client/planning-extension/src/planning-details-widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from 'react';
import {IArticleSideWidgetComponentType} from 'superdesk-api';
import {superdesk} from './superdesk';
import {extensionBridge} from './extension_bridge';

const {AuthoringWidgetLayout, AuthoringWidgetHeading} = superdesk.components;
const {gettext} = superdesk.localization;

export const PLANNING_DETAILS_WIDGET_ID = 'planning_details';
export const PLANNING_DETAILS_WIDGET_LABEL = gettext('Planning Details');

export class PlanningDetailsWidget extends React.PureComponent<IArticleSideWidgetComponentType> {
render() {
const PlanningDetailsBody = extensionBridge.ui.components.PlanningDetailsWidget;

if (this.props.article.assignment_id == null) {
return null;
}

return (
<AuthoringWidgetLayout
header={(
<AuthoringWidgetHeading
widgetId={PLANNING_DETAILS_WIDGET_ID}
widgetName={PLANNING_DETAILS_WIDGET_LABEL}
editMode={false}
/>
)}
body={(
<PlanningDetailsBody item={{assignment_id: this.props.article.assignment_id}} />
)}
/>
);
}
}
1 change: 0 additions & 1 deletion client/views/planning-details-widget.html

This file was deleted.

Loading

0 comments on commit 1abfedf

Please sign in to comment.