Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fulfil assignment #1848

Merged
merged 32 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
998cff9
adjust API
tomaskikutis Apr 20, 2023
209db09
update gettext usage
tomaskikutis Apr 20, 2023
def1a61
Fix event template (#1812)
thecalcc Jun 14, 2023
629c2e8
Fix show modal (#1814)
thecalcc Jun 14, 2023
46387f7
UIF version update (#1818)
thecalcc Jun 28, 2023
a9fe557
[email protected]
tomaskikutis Jul 27, 2023
63b3795
Fulfil assignment
thecalcc Aug 31, 2023
3b4db41
Sync extension bridge
thecalcc Aug 31, 2023
d309048
Fix lint
thecalcc Sep 14, 2023
6ee85a5
Merge remote-tracking branch 'origin/develop' into authoring-react-po…
petrjasek Oct 31, 2023
400ef62
fix lint
petrjasek Oct 31, 2023
9a8ec9e
fix e2e client build
petrjasek Oct 31, 2023
25ff5e5
Fix ng import
thecalcc Nov 6, 2023
8c7e9ad
Merge branch 'authoring-react-post-broadcasting' into fulfil-assignment
thecalcc Nov 6, 2023
7cc6b74
Fix CI
thecalcc Nov 6, 2023
e768699
Merge branch 'develop' into fulfil-assignment
thecalcc Aug 30, 2024
1bdb1bd
Fix lint
thecalcc Aug 30, 2024
cd6150c
Update client-core
thecalcc Sep 11, 2024
1804301
Update e2e client-core
thecalcc Sep 12, 2024
2bb3a63
Update artifact version
thecalcc Sep 12, 2024
ecc568e
Fix type
thecalcc Sep 12, 2024
e7e5715
Merge branch 'develop' into fulfil-assignment
thecalcc Sep 12, 2024
adaa48b
Merge branch 'develop' into fulfil-assignment
thecalcc Sep 16, 2024
dfc8cfb
Fix lint
thecalcc Sep 16, 2024
93da8b6
Merge branch 'develop' into fulfil-assignment
thecalcc Sep 18, 2024
950608f
Small changes
thecalcc Sep 18, 2024
ce435ba
Fix import
thecalcc Sep 18, 2024
7e4b490
Code cleanup
thecalcc Sep 19, 2024
59b038e
Get latest article, fix conditions, fix initialization of action
thecalcc Sep 26, 2024
3193af5
Fix lint
thecalcc Sep 27, 2024
1dca13f
Update client-core
thecalcc Sep 30, 2024
652b26a
Add notification
thecalcc Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 44 additions & 49 deletions client/components/Events/ManageEventTemplatesModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/* eslint-disable react/no-multi-comp */

import {IFormGroup, IBaseRestApiResponse, IGenericListPageComponent} from 'superdesk-api';
import {superdeskApi} from '../../superdeskApi';

import React from 'react';
import PropTypes from 'prop-types';
import {IFormGroup, IBaseRestApiResponse, IPropsGenericFormItemComponent, IFormField} from 'superdesk-api';
import {superdeskApi} from '../../superdeskApi';
import {Modal} from '../index';
import {planningEventTemplateEvents} from '../../actions/events/notifications';

Expand All @@ -16,67 +14,68 @@ interface IEventTemplate extends IBaseRestApiResponse {
template_name: string;
}

const getItemComponent = (nameField: IFormField) =>
class ItemComponent extends React.PureComponent<IPropsGenericFormItemComponent<any>> {
render(): React.ReactNode {
const {item, page} = this.props;

const {ListItem, ListItemColumn} = superdeskApi.components;
const {getFormFieldPreviewComponent} = superdeskApi.forms;

return (
<ListItem>
<ListItemColumn ellipsisAndGrow noBorder>
{getFormFieldPreviewComponent(item, nameField)}
</ListItemColumn>
<ListItemColumn noBorder>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<button onClick={() => page.startEditing(item._id)}>
<i className="icon-pencil" />
</button>
<button onClick={() => page.deleteItem(item)}>
<i className="icon-trash" />
</button>
</div>
</ListItemColumn>
</ListItem>
);
}
};

export class ManageEventTemplatesModal extends React.PureComponent<IProps> {
static propTypes: any;

render() {
const {handleHide} = this.props;

const {getGenericHttpEntityListPageComponent, ListItemColumn, ListItem} = superdeskApi.components;
const {getFormFieldPreviewComponent, FormFieldType} = superdeskApi.forms;

const {gettext} = superdeskApi.localization;
const {getGenericHttpEntityListPageComponent} = superdeskApi.components;
const {FormFieldType} = superdeskApi.forms;

const nameField = {
const nameField: IFormField = {
label: gettext('Template name'),
type: FormFieldType.textSingleLine,
type: FormFieldType.plainText,
field: 'template_name',
required: true,
};

const formConfig: IFormGroup = {
direction: 'vertical',
type: 'inline',
form: [
nameField,
],
form: [nameField],
};

const EventTemplatesComponent = getGenericHttpEntityListPageComponent<IEventTemplate>(
const EventTemplatesComponent = getGenericHttpEntityListPageComponent<IEventTemplate, unknown>(
'events_template',
formConfig
);

const renderRow = (
key: string,
item: IEventTemplate,
page: IGenericListPageComponent<IEventTemplate>
) => (
<ListItem
key={key}
>
<ListItemColumn ellipsisAndGrow noBorder>
{getFormFieldPreviewComponent(item, nameField)}
</ListItemColumn>
<ListItemColumn noBorder>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<button onClick={() => page.startEditing(item._id)}>
<i className="icon-pencil" />
</button>
<button onClick={() => page.deleteItem(item)}>
<i className="icon-trash" />
</button>
</div>
</ListItemColumn>
</ListItem>
);

return (
<Modal xLarge={true} show={true} onHide={handleHide}>
<Modal.Header>
Expand All @@ -87,8 +86,8 @@ export class ManageEventTemplatesModal extends React.PureComponent<IProps> {
</Modal.Header>
<Modal.Body noPadding={true}>
<EventTemplatesComponent
renderRow={renderRow}
formConfig={formConfig}
ItemComponent={getItemComponent(nameField)}
getFormConfig={() => formConfig}
defaultSortOption={{field: nameField.field, direction: 'ascending'}}
fieldForSearch={nameField}
refreshOnEvents={Object.keys(planningEventTemplateEvents)}
Expand All @@ -104,7 +103,3 @@ export class ManageEventTemplatesModal extends React.PureComponent<IProps> {
);
}
}

ManageEventTemplatesModal.propTypes = {
handleHide: PropTypes.func,
};
5 changes: 4 additions & 1 deletion client/extension_bridge.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {IAssignmentItem} from 'interfaces';
import React from 'react';

import {IVocabularyItem} from 'superdesk-api';
import {IArticle, IVocabularyItem} from 'superdesk-api';

import {getAssignmentTypeInfo} from './utils/assignments';
import {SluglineComponent} from './components/Assignments/AssignmentItem/fields/Slugline';
Expand All @@ -11,11 +11,13 @@ import {EditorFieldVocabulary, IEditorFieldVocabularyProps} from './components/f

import {getVocabularyItemFieldTranslated} from './utils/vocabularies';
import {getUserInterfaceLanguageFromCV} from './utils/users';
import {isContentLinkToCoverageAllowed} from 'utils/archive';

// KEEP IN SYNC WITH client/planning-extension/src/extension_bridge.ts
interface IExtensionBridge {
assignments: {
utils: {
isContentLinkToCoverageAllowed(item: IArticle): boolean;
getAssignmentTypeInfo(
assignment: IAssignmentItem,
contentTypes: Array<IVocabularyItem>,
Expand Down Expand Up @@ -57,6 +59,7 @@ export const extensionBridge: IExtensionBridge = {
assignments: {
utils: {
getAssignmentTypeInfo,
isContentLinkToCoverageAllowed,
},
components: {
SluglineComponent,
Expand Down
67 changes: 43 additions & 24 deletions client/planning-extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {AssignmentsList} from './assignments-overview';
import {IPlanningExtensionConfigurationOptions} from './extension_configuration_options';
import {AutopostIngestRuleEditor} from './ingest_rule_autopost/AutopostIngestRuleEditor';
import {AutopostIngestRulePreview} from './ingest_rule_autopost/AutopostIngestRulePreview';
import ng from 'superdesk-core/scripts/core/services/ng';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extensions must not import anything neither from core nor planning. Instead either use superdesk api or planning api via bridge.

import {extensionBridge} from './extension_bridge';
const {isContentLinkToCoverageAllowed} = extensionBridge.assignments.utils;

function onSpike(superdesk: ISuperdesk, item: IArticle) {
const {gettext} = superdesk.localization;
Expand Down Expand Up @@ -105,35 +108,51 @@ const extension: IExtension = {
activate: (superdesk: ISuperdesk) => {
const extensionConfig: IPlanningExtensionConfigurationOptions = superdesk.getExtensionConfig();

return superdesk.privileges.getOwnPrivileges().then((privileges) => {
const displayTopbarWidget = privileges['planning_assignments_view'] === 1
&& extensionConfig?.assignmentsTopBarWidget === true;

const result: IExtensionActivationResult = {
contributions: {
entities: {
article: {
onSpike: (item: IArticle) => onSpike(superdesk, item),
onSpikeMultiple: (items: Array<IArticle>) => onSpikeMultiple(superdesk, items),
onPublish: (item: IArticle) => onPublishArticle(superdesk, item),
onRewriteAfter: (item: IArticle) => onArticleRewriteAfter(superdesk, item),
onSendBefore: (items: Array<IArticle>, desk: IDesk) => onSendBefore(superdesk, items, desk),
},
ingest: {
ruleHandlers: {
planning_publish: {
editor: AutopostIngestRuleEditor,
preview: AutopostIngestRulePreview,
},
const displayTopbarWidget = superdesk.privileges.hasPrivilege('planning_assignments_view')
&& extensionConfig?.assignmentsTopBarWidget === true;

const result: IExtensionActivationResult = {
contributions: {
entities: {
article: {
getActions: (item) => [{
label: superdesk.localization.gettext('Fulfil assignment'),
groupId: 'planning-actions',
icon: 'calendar-list',
onTrigger: () => {
if (
!item.assignment_id &&
isContentLinkToCoverageAllowed(item) &&
!ng.get('archiveService').isPersonal(item) &&
ng.get('privileges').hasUserPrivileges({archive: 1}) &&
!superdesk.entities.article.isLockedInOtherSession(item) &&
!['killed', 'recalled', 'unpublished', 'spiked', 'correction'].includes(item.state)
) {
const event = new CustomEvent("planning:fulfilassignment", {detail: item});
window.dispatchEvent(event);
}
},
}],
onSpike: (item: IArticle) => onSpike(superdesk, item),
onSpikeMultiple: (items: Array<IArticle>) => onSpikeMultiple(superdesk, items),
onPublish: (item: IArticle) => onPublishArticle(superdesk, item),
onRewriteAfter: (item: IArticle) => onArticleRewriteAfter(superdesk, item),
onSendBefore: (items: Array<IArticle>, desk: IDesk) => onSendBefore(superdesk, items, desk),
},
ingest: {
ruleHandlers: {
planning_publish: {
editor: AutopostIngestRuleEditor,
preview: AutopostIngestRulePreview,
},
},
},
globalMenuHorizontal: displayTopbarWidget ? [AssignmentsList] : [],
},
};
globalMenuHorizontal: displayTopbarWidget ? [AssignmentsList] : [],
},
};

return result;
});
return Promise.resolve(result);
},
};

Expand Down
2 changes: 2 additions & 0 deletions client/planning-extension/src/extension_bridge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import {IVocabularyItem} from 'superdesk-api';
import {IAssignmentItem, IEditorFieldProps} from '../../interfaces';
import {IArticle} from 'superdesk-api';

// KEEP IN SYNC WITH client/extension_bridge.ts
interface IEditorFieldVocabularyProps extends IEditorFieldProps {
Expand All @@ -16,6 +17,7 @@ interface IEditorFieldVocabularyProps extends IEditorFieldProps {
interface IExtensionBridge {
assignments: {
utils: {
isContentLinkToCoverageAllowed(item: IArticle): boolean;
getAssignmentTypeInfo(
assignment: IAssignmentItem,
contentTypes: Array<IVocabularyItem>,
Expand Down
2 changes: 1 addition & 1 deletion client/utils/gettext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as utils from 'core/utils';
* @param {Object} params
* @return {String}
*/
export const gettext = (text, params = null) => utils.gettext(text, params);
export const gettext = (text, params = {}) => utils.gettext(text, params);

export function gettextCatalog(text, params = null) {
if (!text) {
Expand Down
6 changes: 3 additions & 3 deletions client/utils/ui.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import {Provider} from 'react-redux';
import $ from 'jquery';

import {planningApi, superdeskApi} from '../superdeskApi';
import {planningApi} from '../superdeskApi';
import {showModal} from '@superdesk/common';

const scrollListItemIfNeeded = (selectedIndex, listRefElement) => {
if (listRefElement.children.length > 0) {
Expand All @@ -29,7 +29,7 @@ export function showModalConnectedToStore<T = any>(
Component: React.ComponentType<{closeModal(): void} & any>,
props?: T,
): Promise<void> {
return superdeskApi.ui.showModal(
return showModal(
({closeModal}) => (
<Provider store={planningApi.redux.store}>
<Component
Expand Down
31 changes: 30 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import planningModule from './client';
import * as ctrl from './client/controllers';
import {gettext} from './client/utils/gettext';
import {isContentLinkToCoverageAllowed} from './client/utils/archive';

import ng from 'superdesk-core/scripts/core/services/ng';

configurePlanning.$inject = ['superdeskProvider'];
function configurePlanning(superdesk) {
Expand Down Expand Up @@ -134,5 +134,34 @@ function configurePlanning(superdesk) {
});
}

window.addEventListener('planning:fulfilassignment', (event: CustomEvent) => {
const element = window.$(document.createElement('div'));
const localScope = ng.get('$rootScope').$new(true);
const handleDestroy = () => {
localScope.$broadcast('$destroy');
element[0].remove();
};

localScope.resolve = handleDestroy;
localScope.reject = handleDestroy;
localScope.locals = {data: {item: event.detail}};

new ctrl.FulFilAssignmentController(
element,
localScope,
ng.get('sdPlanningStore'),
ng.get('notify'),
ng.get('gettext'),
ng.get('lock'),
ng.get('session'),
ng.get('userList'),
ng.get('api'),
ng.get('$timeout'),
ng.get('superdeskFlags'),
ng.get('desks')
);
});


export default planningModule
.config(configurePlanning);
Loading