diff --git a/.changeset/shy-ravens-turn.md b/.changeset/shy-ravens-turn.md new file mode 100644 index 00000000..bbbbf8ce --- /dev/null +++ b/.changeset/shy-ravens-turn.md @@ -0,0 +1,5 @@ +--- +"frontend-reglementaire-bijlage": minor +--- + +Add functionality to unpublish templates diff --git a/app/components/app-chrome.hbs b/app/components/app-chrome.hbs index 8b8667e2..2dc08081 100644 --- a/app/components/app-chrome.hbs +++ b/app/components/app-chrome.hbs @@ -42,12 +42,6 @@ {{/if}} - {{#if @isPublished}} - - {{t "utility.available"}} - - {{/if}} - {{yield to="leadingButtons"}} {{#if @save}} {{t "utility.save"}} diff --git a/app/components/app-chrome.js b/app/components/app-chrome.js index a3aefb6d..552c523f 100644 --- a/app/components/app-chrome.js +++ b/app/components/app-chrome.js @@ -17,7 +17,6 @@ import SnippetVersionModel from '../models/snippet-version'; * @property {boolean|undefined} readonly * @property {string|undefined} templateTypeId * @property {boolean|undefined} dirty - * @property {boolean|undefined} isPublished * @property {PublishSaveAction|undefined} save * @property {PublishSaveAction|undefined} publish */ diff --git a/app/components/confirm-modal.hbs b/app/components/confirm-modal.hbs new file mode 100644 index 00000000..88e08854 --- /dev/null +++ b/app/components/confirm-modal.hbs @@ -0,0 +1,26 @@ + + {{#if @message}} + +

{{@message}}

+
+ {{/if}} + + + + {{or @confirmMessage (t 'utility.confirm')}} + + + {{t 'utility.cancel'}} + + + +
\ No newline at end of file diff --git a/app/components/confirm-modal.js b/app/components/confirm-modal.js new file mode 100644 index 00000000..7d238d34 --- /dev/null +++ b/app/components/confirm-modal.js @@ -0,0 +1,31 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; + +/** + * A generic 'confirmation' modal to avoid copy-pasting boilerplate and to keep a consistent style. + * @title the title to give for the modal + * @message (optional) the message to show in the modal + * @confirmMessage (optional) the text to show in the confirm button + * @isAlert (optional) should the confirmation button be styled as an 'alert' + * @modalOpen boolean flag setting the open state of the modal + * @closeModal callback to trigger closing of the modal + * @onConfirm (optional) hook when confirmation is clicked + * @onCancel (optional) hook when cancellation is clicked or modal is closed + */ +export default class ConfirmModelComponent extends Component { + @action + onConfirm() { + if (this.args.onConfirm) { + this.args.onConfirm(); + } + this.args.closeModal(); + } + + @action + onCancel() { + if (this.args.onCancel) { + this.args.onCancel(); + } + this.args.closeModal(); + } +} diff --git a/app/components/confirm-route-leave.hbs b/app/components/confirm-route-leave.hbs index cb73c769..6b9723cc 100644 --- a/app/components/confirm-route-leave.hbs +++ b/app/components/confirm-route-leave.hbs @@ -1,19 +1,10 @@ - - -

- {{or @message (t 'utility.confirm-leave-without-saving')}} -

-
- - - {{or @confirmMessage (t 'utility.discard-changes')}} - - - {{t 'utility.cancel'}} - - -
\ No newline at end of file + @closeModal={{this.onCancel}} + @onConfirm={{this.onConfirm}} + @onCancel={{this.onCancel}} +/> \ No newline at end of file diff --git a/app/controllers/template-management/edit.js b/app/controllers/template-management/edit.js index c72c953a..0af92c11 100644 --- a/app/controllers/template-management/edit.js +++ b/app/controllers/template-management/edit.js @@ -3,9 +3,9 @@ import { action } from '@ember/object'; import { task } from 'ember-concurrency'; import { service } from '@ember/service'; import { tracked } from 'tracked-built-ins'; -import { trackedFunction } from 'reactiveweb/function'; -import { Schema } from '@lblod/ember-rdfa-editor'; import { v4 as uuid } from 'uuid'; +import isAfter from 'date-fns/isAfter'; +import { Schema } from '@lblod/ember-rdfa-editor'; import { em, strikethrough, @@ -143,6 +143,8 @@ export default class TemplateManagementEditController extends Controller { @service currentSession; @tracked citationPlugin = citationPlugin(this.config.citation); @tracked assignedSnippetListsIds = []; + @tracked isConfirmUnpublishOpen = false; + AttributeEditor = AttributeEditor; RdfaEditor = RdfaEditor; DebugInfo = DebugInfo; @@ -150,6 +152,7 @@ export default class TemplateManagementEditController extends Controller { SnippetInsert = SnippetInsertRdfaComponent; StructureInsert = StructureInsert; StructureControl = StructureControl; + schema = new Schema({ nodes: { doc: docWithConfig({ @@ -445,17 +448,6 @@ export default class TemplateManagementEditController extends Controller { } } - isPublished = trackedFunction(this, async () => { - const publishedTemplate = await this.store.query('template-version', { - filter: { - 'derived-from': { - id: this.editorDocument.id, - }, - }, - })[0]; - return Boolean(publishedTemplate); - }); - get dirty() { // Since we clear the undo history when saving, this works. If we want to maintain undo history // on save, we would need to add functionality to the editor to track what is the 'saved' state @@ -521,4 +513,34 @@ export default class TemplateManagementEditController extends Controller { ); this.assignedSnippetListsIds = snippetIds; } + + get isPublished() { + const version = this.model.templateVersion; + return ( + version && + (!this.unpublishDate || isAfter(this.unpublishDate, Date.now())) + ); + } + get unpublishDate() { + const validThrough = this.model.templateVersion?.validThrough; + return ( + validThrough && + (validThrough instanceof Date ? validThrough : new Date(validThrough)) + ); + } + + @action + openConfirmUnpublish() { + this.isConfirmUnpublishOpen = true; + } + + @action + closeConfirmUnpublish() { + this.isConfirmUnpublishOpen = false; + } + + unpublishTemplate = task(async () => { + this.model.templateVersion.validThrough = new Date(); + await this.model.templateVersion.save(); + }); } diff --git a/app/controllers/template-management/index.js b/app/controllers/template-management/index.js index 053d5652..bf3ce42e 100644 --- a/app/controllers/template-management/index.js +++ b/app/controllers/template-management/index.js @@ -3,9 +3,11 @@ import { task } from 'ember-concurrency'; import { service } from '@ember/service'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking'; +import { localCopy } from 'tracked-toolbox'; +import isAfter from 'date-fns/isAfter'; import { isBlank } from '../../utils/strings'; import { getTemplateType, getTemplateTypes } from '../../utils/template-type'; -import { localCopy } from 'tracked-toolbox'; + export default class TemplateManagementIndexController extends Controller { @service store; @service session; @@ -85,7 +87,13 @@ export default class TemplateManagementIndexController extends Controller { // params you add const templateVersion = await publishedTemplate.currentVersion; // end of shenanigans - return templateVersion.created; + let validThrough = + templateVersion.validThrough && new Date(templateVersion.validThrough); + if (validThrough && isAfter(validThrough, Date.now())) { + // Only display as unpublished when it actually is + validThrough = undefined; + } + return { created: templateVersion.created, validThrough }; } else { return; } @@ -141,10 +149,14 @@ export default class TemplateManagementIndexController extends Controller { this.documentContainer = documentContainer; } + @action + closeRemoveTemplateModal() { + this.removeTemplateModalIsOpen = false; + } + @action cancelRemoveTemplate() { this.editorDocument = undefined; - this.removeTemplateModalIsOpen = false; } submitRemoveTemplate = task(async () => { @@ -170,7 +182,6 @@ export default class TemplateManagementIndexController extends Controller { } } - this.removeTemplateModalIsOpen = false; await this.documentContainer.deleteRecord(); await this.documentContainer.save(); this.refresh(); diff --git a/app/controllers/template-management/publish.js b/app/controllers/template-management/publish.js index cac571bb..bfee5ec8 100644 --- a/app/controllers/template-management/publish.js +++ b/app/controllers/template-management/publish.js @@ -14,13 +14,11 @@ export default class TemplateManagementPublishController extends Controller { @service intl; @tracked currentVersion; - - constructor() { - super(...arguments); - } + @tracked currentVersionValidThrough; fetchPreview = task(async () => { this.currentVersion = ''; + this.currentVersionValidThrough = undefined; const currentPublishedTemplate = ( await this.store.query('template', { filter: { @@ -34,6 +32,9 @@ export default class TemplateManagementPublishController extends Controller { if (currentPublishedTemplate) { const publishedVersion = await currentPublishedTemplate.currentVersion; const response = await fetch(publishedVersion.downloadLink); + this.currentVersionValidThrough = + publishedVersion.validThrough && + new Date(publishedVersion.validThrough); this.currentVersion = await response.text(); } }); diff --git a/app/routes/.gitkeep b/app/routes/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/routes/template-management/edit.js b/app/routes/template-management/edit.js index e2ce77c5..c1714dc8 100644 --- a/app/routes/template-management/edit.js +++ b/app/routes/template-management/edit.js @@ -18,10 +18,23 @@ export default class TemplateManagementEditRoute extends Route { reload: true, }, ); + const templateVersion = await this.store + .query('template', { + filter: { + 'derived-from': { + id: documentContainer.id, + }, + }, + // See template-management/index.js for details of this hack + avoid_cache: new Date().toISOString(), + include: 'current-version', + }) + .then((templates) => templates[0]?.currentVersion); return hash({ documentContainer, editorDocument: documentContainer.currentVersion, templateTypeId: documentContainer.templateTypeId, + templateVersion, }); } diff --git a/app/templates/template-management/edit.hbs b/app/templates/template-management/edit.hbs index 0fe50261..45fa174b 100644 --- a/app/templates/template-management/edit.hbs +++ b/app/templates/template-management/edit.hbs @@ -18,10 +18,25 @@ action=(perform this.publish) isRunning=this.save.isRunning }} - @isPublished={{this.isPublished.value}} > <:leadingButtons> - + + {{#if this.isPublished}} + {{#if this.model.templateVersion.validThrough}} + {{t "template-management.available-until" date=(human-friendly-date this.unpublishDate)}} + {{else}} + {{t "template-management.available"}} + {{/if}} + {{else}} + {{t "template-management.not-published"}} + {{/if}} + {{#if this.activeNode}} {{/if}} - \ No newline at end of file + + \ No newline at end of file diff --git a/app/templates/template-management/index.hbs b/app/templates/template-management/index.hbs index 64874903..19e74a07 100644 --- a/app/templates/template-management/index.hbs +++ b/app/templates/template-management/index.hbs @@ -76,7 +76,12 @@ as |lastPublicationDate| }} {{#if lastPublicationDate}} - {{detailed-date lastPublicationDate}} + {{#if lastPublicationDate.validThrough}} + {{detailed-date + lastPublicationDate.created}} + {{else}} + {{detailed-date lastPublicationDate.created}} + {{/if}} {{else}} {{t "template-management.not-found"}} {{/if}} @@ -149,23 +154,11 @@ - - - - - {{t "template-management.remove-modal.remove"}} - - - {{t "template-management.remove-modal.cancel"}} - - - - \ No newline at end of file + @closeModal={{this.closeRemoveTemplateModal}} + @onConfirm={{perform this.submitRemoveTemplate}} + @onCancel={{this.cancelRemoveTemplate}} +/> \ No newline at end of file diff --git a/app/templates/template-management/publish.hbs b/app/templates/template-management/publish.hbs index 1a2f26e6..6d7e6156 100644 --- a/app/templates/template-management/publish.hbs +++ b/app/templates/template-management/publish.hbs @@ -40,7 +40,11 @@ - {{t 'publish-page.publishedversion'}} + {{#if this.currentVersionValidThrough}} + {{t 'publish-page.published-until' date=(detailed-date this.currentVersionValidThrough)}} + {{else}} + {{t 'publish-page.publishedversion'}} + {{/if}} diff --git a/translations/en-us.yaml b/translations/en-us.yaml index e30b518c..bd456a4f 100644 --- a/translations/en-us.yaml +++ b/translations/en-us.yaml @@ -51,7 +51,6 @@ utility: remove-concept: Remove concept export-to-html: "Export to HTML" to-recycle-bin: "Move to recycle bin" - available: Available confirmation: title: Confirm body: Are you sure? @@ -90,6 +89,9 @@ template-management: updated-on: Updated On not-found: N/A publish-date: Published on + not-published: Not published + available: Available + available-until: Available until {date} template-type: label: Template type decision: Decision @@ -111,6 +113,8 @@ template-edit: saving: Saving document-title-placeholder: Enter document title insert-title: Insert document title + unpublish: Unpublish + unpublish-confirm: Are you sure you want to unpublish this template? auth: acmidm: Log in with acm/idm login: Log in @@ -123,6 +127,7 @@ publish-page: back: Back to document template latestversion: Latest version publishedversion: Published version + published-until: Version published up until {date} publish: Publish notification-title: Success notification-content: Template successfully published diff --git a/translations/nl-BE.yaml b/translations/nl-BE.yaml index 64bc96e2..433fb1df 100644 --- a/translations/nl-BE.yaml +++ b/translations/nl-BE.yaml @@ -51,7 +51,6 @@ utility: remove-concept: Verwijder concept export-to-html: "Exporteer als HTML" to-recycle-bin: "Naar prullenmand" - available: Beschikbaar confirmation: title: Bevestigen body: Ben je zeker? @@ -90,6 +89,9 @@ template-management: updated-on: Bijgewerkt op not-found: n.v.t. publish-date: Beschikbaar gemaakt op + not-published: Niet uitgegeven + available: Beschikbaar + available-until: Beschikbaar tot {date} template-type: label: Sjabloontype decision: Besluit @@ -111,6 +113,8 @@ template-edit: saving: Bezig met opslaan document-title-placeholder: Geef document-titel op insert-title: Document-titel invoegen + unpublish: Uitgave ongedaan maken + unpublish-confirm: Weet je zeker dat je het uitgeven van deze sjabloon ongedaan wilt maken? auth: acmidm: Log in met acm/idm login: Meld u aan @@ -123,6 +127,7 @@ publish-page: back: Terug naar sjabloon latestversion: Laatste versie publishedversion: Publieke versie + published-until: Versie publiek tot {date} publish: Maak beschikbaar notification-title: Geslaagd notification-content: Sjabloon beschikbaar gemaakt