mirror of
https://github.com/silverstripe/silverstripe-contentreview
synced 2024-10-22 17:05:47 +02:00
Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3ac1f1bf9d | ||
|
84edeab427 | ||
|
d57cf056cb | ||
|
d401365c23 | ||
|
c37f61861f | ||
|
a7e77a66be | ||
|
5da7a119e4 | ||
|
e0cef401b9 | ||
|
bded3af5ce | ||
|
51c69c6c0f | ||
|
fd1fd08db0 | ||
|
0dfe8a6c26 | ||
|
d96254e18e | ||
|
3f5079f5b6 | ||
|
a571e5d8f8 | ||
|
5c79718c0a | ||
|
3d879d2d27 | ||
|
ae8d36c79f | ||
|
e7671b3994 | ||
|
91fa889d8d | ||
|
95d33141fd | ||
|
5c7a4254f4 | ||
|
882da53ef3 | ||
|
7a7e930d40 | ||
|
7955f8dcc4 | ||
|
8e3dd58f78 | ||
|
5b93e37dee | ||
|
0ac70f6054 | ||
|
3ca281a4ed | ||
|
8433b007e5 | ||
|
376474f699 | ||
|
dc66fe86c9 | ||
|
978ffec4f9 | ||
|
6ca6bff7e1 | ||
|
f4b409e0d3 |
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "airbnb",
|
|
||||||
"root": true,
|
|
||||||
"rules": {
|
|
||||||
"init-declarations": 1
|
|
||||||
}
|
|
||||||
}
|
|
1
.eslintrc.js
Normal file
1
.eslintrc.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('@silverstripe/eslint-config/.eslintrc');
|
6
.github/workflows/keepalive.yml
vendored
6
.github/workflows/keepalive.yml
vendored
@ -1,10 +1,10 @@
|
|||||||
name: Keepalive
|
name: Keepalive
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
# At 8:40 PM UTC, on day 9 of the month
|
||||||
# The 4th of every month at 10:50am UTC
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '50 10 4 * *'
|
- cron: '40 20 9 * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
keepalive:
|
keepalive:
|
||||||
|
17
.github/workflows/merge-up.yml
vendored
Normal file
17
.github/workflows/merge-up.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: Merge-up
|
||||||
|
|
||||||
|
on:
|
||||||
|
# At 11:30 AM UTC, only on Sunday
|
||||||
|
schedule:
|
||||||
|
- cron: '30 11 * * 0'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
merge-up:
|
||||||
|
name: Merge-up
|
||||||
|
# Only run cron on the silverstripe account
|
||||||
|
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Merge-up
|
||||||
|
uses: silverstripe/gha-merge-up@v1
|
2
.github/workflows/update-js.yml
vendored
2
.github/workflows/update-js.yml
vendored
@ -4,7 +4,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
# Run on a schedule of once per quarter
|
# Run on a schedule of once per quarter
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 1 */3 *'
|
- cron: '40 20 1 */3 *'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-js:
|
update-js:
|
||||||
|
18
.upgrade.yml
18
.upgrade.yml
@ -1,18 +0,0 @@
|
|||||||
mappings:
|
|
||||||
ContentReviewCompatability: SilverStripe\ContentReview\Compatibility\ContentReviewCompatability
|
|
||||||
ContentReviewCMSExtension: SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension
|
|
||||||
ContentReviewDefaultSettings: SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings
|
|
||||||
ContentReviewOwner: SilverStripe\ContentReview\Extensions\ContentReviewOwner
|
|
||||||
SiteTreeContentReview: SilverStripe\ContentReview\Extensions\SiteTreeContentReview
|
|
||||||
ContentReviewNotificationJob: SilverStripe\ContentReview\Jobs\ContentReviewNotificationJob
|
|
||||||
ContentReviewLog: SilverStripe\ContentReview\Models\ContentReviewLog
|
|
||||||
PagesDueForReviewReport: SilverStripe\ContentReview\Reports\PagesDueForReviewReport
|
|
||||||
PagesWithoutReviewScheduleReport: SilverStripe\ContentReview\Reports\PagesWithoutReviewScheduleReport
|
|
||||||
ContentReviewEmails: SilverStripe\ContentReview\Tasks\ContentReviewEmails
|
|
||||||
ContentReviewOwnerMigrationTask: SilverStripe\ContentReview\Tasks\ContentReviewOwnerMigrationTask
|
|
||||||
ContentReviewBaseTest: SilverStripe\ContentReview\Tests\ContentReviewBaseTest
|
|
||||||
ContentReviewCMSPageEditControllerTest: SilverStripe\ContentReview\Tests\ContentReviewCMSPageEditControllerTest
|
|
||||||
ContentReviewNotificationTest: SilverStripe\ContentReview\Tests\ContentReviewNotificationTest
|
|
||||||
ContentReviewReportTest: SilverStripe\ContentReview\Tests\ContentReviewReportTest
|
|
||||||
ContentReviewSettingsTest: SilverStripe\ContentReview\Tests\ContentReviewSettingsTest
|
|
||||||
SiteTreeContentReviewTest: SilverStripe\ContentReview\Tests\SiteTreeContentReviewTest
|
|
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2017, SilverStripe Limited
|
Copyright (c) 2017, Silverstripe Limited
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
10
README.md
10
README.md
@ -13,11 +13,11 @@ There are two types of roles with this module.
|
|||||||
* Website owner; (typically assigned to the Administrator group) ensures that a website is accurate and up-to-date, by delegating responsibility to content reviewers.
|
* Website owner; (typically assigned to the Administrator group) ensures that a website is accurate and up-to-date, by delegating responsibility to content reviewers.
|
||||||
* Content reviewer; responsible for keeping a website or part of a website accurate and up-to-date.
|
* Content reviewer; responsible for keeping a website or part of a website accurate and up-to-date.
|
||||||
|
|
||||||
## Requirements
|
## Installation
|
||||||
|
|
||||||
* Silverstripe ^4.0
|
```sh
|
||||||
|
composer require silverstripe/contentreview
|
||||||
**Note:** For Silverstripe 3.x, please use the [3.x release line](https://github.com/silverstripe/silverstripe-contentreview/tree/3).
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ There are two types of roles with this module.
|
|||||||
## Composer installation
|
## Composer installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ composer require silverstripe/contentreview
|
composer require silverstripe/contentreview
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll also need to run `dev/build`.
|
You'll also need to run `dev/build`.
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
Name: contentreviewlegacy
|
|
||||||
---
|
|
||||||
SilverStripe\ORM\DatabaseAdmin:
|
|
||||||
classname_value_remapping:
|
|
||||||
ContentReviewLog: SilverStripe\ContentReview\Models\ContentReviewLog
|
|
6
babel.config.json
Normal file
6
babel.config.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
"@babel/preset-env",
|
||||||
|
"@babel/preset-react"
|
||||||
|
]
|
||||||
|
}
|
2
client/dist/js/contentreview.js
vendored
2
client/dist/js/contentreview.js
vendored
@ -1 +1 @@
|
|||||||
!function(e){function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var t={};n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:o})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=4)}([function(e,n){e.exports=jQuery},function(e,n,t){"use strict";var o=t(8),i=t.n(o),r=t(0),s=t.n(r),c=t(6),a=t.n(c),u=t(7),d=t.n(u),l=t(5),f=(t.n(l),t.i(l.loadComponent)("FormBuilderModal"));s.a.entwine("ss",function(e){e(".cms-content-actions .content-review__button").entwine({onclick:function(n){n.preventDefault();var t=e("#content-review__dialog-wrapper");return t.length||(t=e('<div id="content-review__dialog-wrapper" />'),e("body").append(t)),t.open(),!1}}),e(".content-review-modal .content-review-modal__nav-link").entwine({onclick:function(n){n.preventDefault();var t=e(n.target);window.location=t.attr("href")}}),e("#content-review__dialog-wrapper").entwine({onunmatch:function(){this._clearModal()},open:function(){this._renderModal(!0)},close:function(){this._renderModal(!1)},_renderModal:function(n){var t=this,o=function(){return t.close()},r=function(){return t._handleSubmitModal.apply(t,arguments)},s=e("form.cms-edit-form :input[name=ID]").val(),c=window.ss.store,u=c.getState().config.sections.find(function(e){return"SilverStripe\\CMS\\Controllers\\CMSPageEditController"===e.name}),l=u.form.ReviewContentForm.schemaUrl+"/"+s,_=i.a._t("ContentReview.CONTENT_DUE_FOR_REVIEW","Content due for review");d.a.render(a.a.createElement(f,{title:_,isOpen:n,onSubmit:r,onClosed:o,schemaUrl:l,bodyClassName:"modal__dialog",className:"content-review-modal",responseClassBad:"modal__response modal__response--error",responseClassGood:"modal__response modal__response--good",identifier:"ContentReview.CONTENT_DUE_FOR_REVIEW"}),this[0])},_clearModal:function(){d.a.unmountComponentAtNode(this[0])},_handleSubmitModal:function(n,t,o){return e(".content-review__button-holder").remove(),o()}})})},function(e,n,t){"use strict";var o=t(0);t.n(o).a.entwine("ss",function(e){e(".cms-edit-form #Form_EditForm_ContentReviewType_Holder").entwine({onmatch:function(){var e=this;this.find(".optionset :input").bind("change",function(n){e.show_option(n.target.value)});var n=this.find("input[name=ContentReviewType]:checked").val();this.show_option(n),this._super()},onunmatch:function(){return this._super()},show_option:function(e){"Custom"===e?this._custom():"Inherit"===e?this._inherited():this._disabled()},_custom:function(){e(".review-settings").show(),e(".field.custom-setting").show()},_inherited:function(){e(".review-settings").show(),e(".field.custom-setting").hide()},_disabled:function(){e(".review-settings").hide()}})})},function(e,n,t){"use strict";var o=t(0);t.n(o).a.entwine("ss",function(e){function n(n){var t="ContentReviewOwnerID"+n,o=e("div.subsiteSpecificOwnerID"),i=0;for(i=0;i<o.length;i++)o[i].id===t?e(o[i]).show():e(o[i]).hide()}e("#Form_EditForm_SubsiteIDWithOwner").entwine({onmatch:function(){n(this.value)},change:function(){n(this.value)}})})},function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),t(1),t(2),t(3)},function(e,n){e.exports=Injector},function(e,n){e.exports=React},function(e,n){e.exports=ReactDom},function(e,n){e.exports=i18n}]);
|
!function(){"use strict";var e={30:function(e,t,n){var o=a(n(754)),i=a(n(311)),s=a(n(363)),r=n(691);function a(e){return e&&e.__esModule?e:{default:e}}const l=(0,n(648).loadComponent)("FormBuilderModal");i.default.entwine("ss",(e=>{e(".cms-content-actions .content-review__button").entwine({onclick(t){t.preventDefault();let n=e("#content-review__dialog-wrapper");return n.length||(n=e('<div id="content-review__dialog-wrapper" />'),e("body").append(n)),n.open(),!1}}),e(".content-review-modal .content-review-modal__nav-link").entwine({onclick:t=>{t.preventDefault();const n=e(t.target);window.location=n.attr("href")}}),e("#content-review__dialog-wrapper").entwine({ReactRoot:null,onunmatch(){this._clearModal()},open(){this._renderModal(!0)},close(){this._renderModal(!1)},_renderModal(t){var n=this;const i=e("form.cms-edit-form :input[name=ID]").val(),a=`${window.ss.store.getState().config.sections.find((e=>"SilverStripe\\CMS\\Controllers\\CMSPageEditController"===e.name)).form.ReviewContentForm.schemaUrl}/${i}`,d=o.default._t("ContentReview.CONTENT_DUE_FOR_REVIEW","Content due for review");let c=this.getReactRoot();c||(c=(0,r.createRoot)(this[0]),this.setReactRoot(c)),c.render(s.default.createElement(l,{title:d,isOpen:t,onSubmit:function(){return n._handleSubmitModal(...arguments)},onClosed:()=>this.close(),schemaUrl:a,bodyClassName:"modal__dialog",className:"content-review-modal",responseClassBad:"modal__response modal__response--error",responseClassGood:"modal__response modal__response--good",identifier:"ContentReview.CONTENT_DUE_FOR_REVIEW"}))},_clearModal(){const e=this.getReactRoot();e&&(e.unmount(),this.setReactRoot(null))},_handleSubmitModal(t,n,o){return e(".content-review__button-holder").remove(),o()}})}))},933:function(e,t,n){var o;((o=n(311))&&o.__esModule?o:{default:o}).default.entwine("ss",(e=>{e(".cms-edit-form #Form_EditForm_ContentReviewType_Holder").entwine({onmatch(){const e=this;this.find(".optionset :input").bind("change",(t=>{e.show_option(t.target.value)}));const t=this.find("input[name=ContentReviewType]:checked").val();this.show_option(t),this._super()},onunmatch(){return this._super()},show_option(e){"Custom"===e?this._custom():"Inherit"===e?this._inherited():this._disabled()},_custom(){e(".review-settings").show(),e(".field.custom-setting").show()},_inherited(){e(".review-settings").show(),e(".field.custom-setting").hide()},_disabled(){e(".review-settings").hide()}})}))},154:function(e,t,n){var o;((o=n(311))&&o.__esModule?o:{default:o}).default.entwine("ss",(e=>{function t(t){const n=`ContentReviewOwnerID${t}`,o=e("div.subsiteSpecificOwnerID");let i=0;for(i=0;i<o.length;i++)o[i].id===n?e(o[i]).show():e(o[i]).hide()}e("#Form_EditForm_SubsiteIDWithOwner").entwine({onmatch(){t(this.value)},change(){t(this.value)}})}))},648:function(e){e.exports=Injector},363:function(e){e.exports=React},691:function(e){e.exports=ReactDomClient},754:function(e){e.exports=i18n},311:function(e){e.exports=jQuery}},t={};function n(o){var i=t[o];if(void 0!==i)return i.exports;var s=t[o]={exports:{}};return e[o](s,s.exports,n),s.exports}n(30),n(933),n(154)}();
|
2
client/dist/styles/contentreview.css
vendored
2
client/dist/styles/contentreview.css
vendored
@ -1 +1 @@
|
|||||||
.content-review__button{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAYAAAD+MdrbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPlJREFUeNpi/P//PwM1AeOAGPg1h3EBiOae8j+BkFoWIi22pIoLgS5rAFIFQMwPFfoIxBNAGOjaDyQZCDTsApDSx2HXRSB2wGYoEx6X6ePxmT7U5QxEGYhLMTFqMLwMdJ0AkHpPZBwYAr19gZALDUhIdgLEeplsQBcDBUjQr4A3UoARQlbGBkYMI828TN/SBkeaFMSVjwl6GaqxEUmoEZ9hA1fAjkADL8dC6hTdxYOtTgG6DGedAnQtaXUK0DCCdQo2Q5nwuGyQ1ilA15FUpwC9PVqn0LJOAUYIWRkbGDHDpU7BkSYFceVjgl6GakSpU/AZNjRKbIAAAwDhCJTckjfR5wAAAABJRU5ErkJggg==) 50% no-repeat;background-position:0 0;display:inline-block;height:20px;margin:6px 4px 0 12px;padding:0;text-indent:-9999px;width:20px}.content-review__button:focus,.content-review__button:hover{background-position:0 -20px}
|
.content-review__button{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAYAAAD+MdrbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPlJREFUeNpi/P//PwM1AeOAGPg1h3EBiOae8j+BkFoWIi22pIoLgS5rAFIFQMwPFfoIxBNAGOjaDyQZCDTsApDSx2HXRSB2wGYoEx6X6ePxmT7U5QxEGYhLMTFqMLwMdJ0AkHpPZBwYAr19gZALDUhIdgLEeplsQBcDBUjQr4A3UoARQlbGBkYMI828TN/SBkeaFMSVjwl6GaqxEUmoEZ9hA1fAjkADL8dC6hTdxYOtTgG6DGedAnQtaXUK0DCCdQo2Q5nwuGyQ1ilA15FUpwC9PVqn0LJOAUYIWRkbGDHDpU7BkSYFceVjgl6GakSpU/AZNjRKbIAAAwDhCJTckjfR5wAAAABJRU5ErkJggg==) center center no-repeat;background-position:0 0;display:inline-block;height:20px;margin:6px 4px 0 12px;padding:0;text-indent:-9999px;width:20px}.content-review__button:hover,.content-review__button:focus{background-position:0 -20px}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import i18n from 'i18n';
|
import i18n from 'i18n';
|
||||||
import jQuery from 'jquery';
|
import jQuery from 'jquery';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { loadComponent } from 'lib/Injector';
|
import { loadComponent } from 'lib/Injector';
|
||||||
|
|
||||||
const FormBuilderModal = loadComponent('FormBuilderModal');
|
const FormBuilderModal = loadComponent('FormBuilderModal');
|
||||||
@ -12,7 +12,7 @@ const FormBuilderModal = loadComponent('FormBuilderModal');
|
|||||||
* silverstripe/admin for reference.
|
* silverstripe/admin for reference.
|
||||||
*/
|
*/
|
||||||
jQuery.entwine('ss', ($) => {
|
jQuery.entwine('ss', ($) => {
|
||||||
/**
|
/**
|
||||||
* Kick off a "content due for review" dialog from the CMS actions.
|
* Kick off a "content due for review" dialog from the CMS actions.
|
||||||
*/
|
*/
|
||||||
$('.cms-content-actions .content-review__button').entwine({
|
$('.cms-content-actions .content-review__button').entwine({
|
||||||
@ -42,10 +42,12 @@ jQuery.entwine('ss', ($) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses reactstrap in order to replicate the bootstrap styling and JavaScript behaviour.
|
* Uses reactstrap in order to replicate the bootstrap styling and JavaScript behaviour.
|
||||||
*/
|
*/
|
||||||
$('#content-review__dialog-wrapper').entwine({
|
$('#content-review__dialog-wrapper').entwine({
|
||||||
|
ReactRoot: null,
|
||||||
|
|
||||||
onunmatch() {
|
onunmatch() {
|
||||||
// solves errors given by ReactDOM "no matched root found" error.
|
// solves errors given by ReactDOM "no matched root found" error.
|
||||||
this._clearModal();
|
this._clearModal();
|
||||||
@ -70,7 +72,12 @@ jQuery.entwine('ss', ($) => {
|
|||||||
const modalSchemaUrl = `${sectionConfig.form.ReviewContentForm.schemaUrl}/${id}`;
|
const modalSchemaUrl = `${sectionConfig.form.ReviewContentForm.schemaUrl}/${id}`;
|
||||||
const title = i18n._t('ContentReview.CONTENT_DUE_FOR_REVIEW', 'Content due for review');
|
const title = i18n._t('ContentReview.CONTENT_DUE_FOR_REVIEW', 'Content due for review');
|
||||||
|
|
||||||
ReactDOM.render(
|
let root = this.getReactRoot();
|
||||||
|
if (!root) {
|
||||||
|
root = createRoot(this[0]);
|
||||||
|
this.setReactRoot(root);
|
||||||
|
}
|
||||||
|
root.render(
|
||||||
<FormBuilderModal
|
<FormBuilderModal
|
||||||
title={title}
|
title={title}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
@ -82,13 +89,16 @@ jQuery.entwine('ss', ($) => {
|
|||||||
responseClassBad="modal__response modal__response--error"
|
responseClassBad="modal__response modal__response--error"
|
||||||
responseClassGood="modal__response modal__response--good"
|
responseClassGood="modal__response modal__response--good"
|
||||||
identifier="ContentReview.CONTENT_DUE_FOR_REVIEW"
|
identifier="ContentReview.CONTENT_DUE_FOR_REVIEW"
|
||||||
/>,
|
/>
|
||||||
this[0]
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
_clearModal() {
|
_clearModal() {
|
||||||
ReactDOM.unmountComponentAtNode(this[0]);
|
const root = this.getReactRoot();
|
||||||
|
if (root) {
|
||||||
|
root.unmount();
|
||||||
|
this.setReactRoot(null);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleSubmitModal(data, action, submitFn) {
|
_handleSubmitModal(data, action, submitFn) {
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import jQuery from 'jquery';
|
import jQuery from 'jquery';
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Re-validate this with Subsites
|
|
||||||
*/
|
|
||||||
jQuery.entwine('ss', ($) => {
|
jQuery.entwine('ss', ($) => {
|
||||||
// Hide all owner dropdowns except the one for the current subsite
|
// Hide all owner dropdowns except the one for the current subsite
|
||||||
function showCorrectSubsiteIDDropdown(value) {
|
function showCorrectSubsiteIDDropdown(value) {
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import 'bundles/ContentReviewForm.js';
|
import 'bundles/ContentReviewForm';
|
||||||
import 'bundles/ContentReviewSettings.js';
|
import 'bundles/ContentReviewSettings';
|
||||||
import 'bundles/PagesDueForReview.js';
|
import 'bundles/PagesDueForReview';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// The bell button, shows up next to the major actions (save, publish, etc) when
|
// The bell button, shows up next to the major actions (save, publish, etc) when
|
||||||
// viewing a page in the CMS
|
// viewing a page in the CMS
|
||||||
.content-review__button {
|
.content-review__button {
|
||||||
background: url("images/icon-bell.png") center center no-repeat;
|
background: url('../images/icon-bell.png') center center no-repeat;
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
@ -23,17 +23,17 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.4 || ^8.0",
|
"php": "^8.1",
|
||||||
"silverstripe/vendor-plugin": "^1",
|
"silverstripe/vendor-plugin": "^2",
|
||||||
"silverstripe/framework": "^4.10",
|
"silverstripe/framework": "^5",
|
||||||
"silverstripe/cms": "^4.2",
|
"silverstripe/cms": "^5",
|
||||||
"silverstripe/reports": "^4.2",
|
"silverstripe/reports": "^5",
|
||||||
"silverstripe/siteconfig": "^4.2"
|
"silverstripe/siteconfig": "^5"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"silverstripe/recipe-testing": "^2",
|
"silverstripe/recipe-testing": "^3",
|
||||||
"squizlabs/php_codesniffer": "^3",
|
"squizlabs/php_codesniffer": "^3",
|
||||||
"symbiote/silverstripe-queuedjobs": "^4.9"
|
"symbiote/silverstripe-queuedjobs": "^5"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"symbiote/silverstripe-queuedjobs": "Automatically schedules content review emails to be sent, only requiring one crontask to be created"
|
"symbiote/silverstripe-queuedjobs": "Automatically schedules content review emails to be sent, only requiring one crontask to be created"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
en:
|
en:
|
||||||
SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension:
|
SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension:
|
||||||
ErrorItemPermissionDenied: 'It seems you don''t have the necessary permissions to review this content'
|
ErrorItemPermissionDenied: "It seems you don't have the necessary permissions to review this content"
|
||||||
SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings:
|
SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings:
|
||||||
ADDGROUP: 'Add groups'
|
ADDGROUP: 'Add groups'
|
||||||
ADDUSERS: 'Add users'
|
ADDUSERS: 'Add users'
|
||||||
@ -51,7 +51,7 @@ en:
|
|||||||
db_ReviewPeriodDays: 'Review period days'
|
db_ReviewPeriodDays: 'Review period days'
|
||||||
has_many_ReviewLogs: 'Review logs'
|
has_many_ReviewLogs: 'Review logs'
|
||||||
SilverStripe\ContentReview\Forms\ReviewContentHandler:
|
SilverStripe\ContentReview\Forms\ReviewContentHandler:
|
||||||
ErrorReviewPermissionDenied: 'It seems you don''t have the necessary permissions to submit a content review'
|
ErrorReviewPermissionDenied: "It seems you don't have the necessary permissions to submit a content review"
|
||||||
MarkAsReviewedAction: 'Mark as reviewed'
|
MarkAsReviewedAction: 'Mark as reviewed'
|
||||||
NoComments: '(no comments)'
|
NoComments: '(no comments)'
|
||||||
Placeholder: 'Add comments (optional)'
|
Placeholder: 'Add comments (optional)'
|
||||||
|
35
package.json
35
package.json
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "silverstripe-contentreview",
|
"name": "silverstripe-contentreview",
|
||||||
"version": "4.0.0",
|
|
||||||
"description": "Flags pages for periodical author review (incl. reporting)",
|
"description": "Flags pages for periodical author review (incl. reporting)",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn && NODE_ENV=production webpack -p --bail --progress",
|
"build": "yarn && yarn lint && rm -rf client/dist/* && NODE_ENV=production webpack --mode production --bail --progress",
|
||||||
|
"dev": "NODE_ENV=development webpack --progress",
|
||||||
"watch": "yarn && NODE_ENV=development webpack --watch --progress",
|
"watch": "yarn && NODE_ENV=development webpack --watch --progress",
|
||||||
"css": "WEBPACK_CHILD=css npm run build",
|
"css": "WEBPACK_CHILD=css npm run build",
|
||||||
"lint": "eslint client/src; sass-lint -v"
|
"lint": "eslint client/src; sass-lint -v"
|
||||||
@ -23,22 +23,25 @@
|
|||||||
"url": "https://github.com/silverstripe/silverstripe-contentreview/issues"
|
"url": "https://github.com/silverstripe/silverstripe-contentreview/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/silverstripe/silverstripe-contentreview#readme",
|
"homepage": "https://github.com/silverstripe/silverstripe-contentreview#readme",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.x"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jquery": "^3.4.0",
|
"react": "18.2.0",
|
||||||
"react": "15.3.1",
|
"react-dom": "18.2.0",
|
||||||
"react-dom": "15.3.1",
|
"react-redux": "^8.0.4",
|
||||||
"react-redux": "^4.4.1",
|
"redux": "^4.2.0"
|
||||||
"redux": "https://registry.npmjs.org/redux/-/redux-3.0.5.tgz"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@silverstripe/webpack-config": "^0.2.5",
|
"@silverstripe/eslint-config": "^1.1.0",
|
||||||
"babel-core": "^6.24.1",
|
"@silverstripe/webpack-config": "^2.0.0",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"webpack": "^5.74.0",
|
||||||
"babel-preset-es2016": "^6.24.1",
|
"webpack-cli": "^5.0.0"
|
||||||
"eslint": "^2.7.0",
|
|
||||||
"eslint-config-airbnb": "^6.2.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"resolutions": {
|
||||||
"node": "^10.x"
|
"colors": "1.4.0"
|
||||||
}
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"defaults"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,6 @@ class ContentReviewCMSExtension extends LeftAndMainExtension
|
|||||||
* Check if the current request has a X-Formschema-Request header set.
|
* Check if the current request has a X-Formschema-Request header set.
|
||||||
* Used by conditional logic that responds to validation results
|
* Used by conditional logic that responds to validation results
|
||||||
*
|
*
|
||||||
* @todo Remove duplication. See https://github.com/silverstripe/silverstripe-admin/issues/240
|
|
||||||
*
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function getSchemaRequested()
|
protected function getSchemaRequested()
|
||||||
@ -142,8 +140,6 @@ class ContentReviewCMSExtension extends LeftAndMainExtension
|
|||||||
/**
|
/**
|
||||||
* Generate schema for the given form based on the X-Formschema-Request header value
|
* Generate schema for the given form based on the X-Formschema-Request header value
|
||||||
*
|
*
|
||||||
* @todo Remove duplication. See https://github.com/silverstripe/silverstripe-admin/issues/240
|
|
||||||
*
|
|
||||||
* @param string $schemaID ID for this schema. Required.
|
* @param string $schemaID ID for this schema. Required.
|
||||||
* @param Form $form Required for 'state' or 'schema' response
|
* @param Form $form Required for 'state' or 'schema' response
|
||||||
* @param ValidationResult $errors Required for 'error' response
|
* @param ValidationResult $errors Required for 'error' response
|
||||||
|
@ -20,6 +20,8 @@ use SilverStripe\Security\Permission;
|
|||||||
* review setting.
|
* review setting.
|
||||||
*
|
*
|
||||||
* @property int $ReviewPeriodDays
|
* @property int $ReviewPeriodDays
|
||||||
|
* @method SilverStripe\ORM\ManyManyList<Group> ContentReviewGroups()
|
||||||
|
* @method SilverStripe\ORM\ManyManyList<Member> ContentReviewUsers()
|
||||||
*/
|
*/
|
||||||
class ContentReviewDefaultSettings extends DataExtension
|
class ContentReviewDefaultSettings extends DataExtension
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,9 @@ use SilverStripe\CMS\Model\SiteTree;
|
|||||||
use SilverStripe\Forms\FieldList;
|
use SilverStripe\Forms\FieldList;
|
||||||
use SilverStripe\ORM\DataExtension;
|
use SilverStripe\ORM\DataExtension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method SilverStripe\ORM\ManyManyList<SiteTree> SiteTreeContentReview()
|
||||||
|
*/
|
||||||
class ContentReviewOwner extends DataExtension
|
class ContentReviewOwner extends DataExtension
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -50,9 +50,9 @@ use Symbiote\QueuedJobs\Services\QueuedJobService;
|
|||||||
* @property string $LastEditedByName
|
* @property string $LastEditedByName
|
||||||
* @property string $OwnerNames
|
* @property string $OwnerNames
|
||||||
*
|
*
|
||||||
* @method DataList ReviewLogs()
|
* @method SilverStripe\ORM\ManyManyList<Group> ContentReviewGroups()
|
||||||
* @method DataList ContentReviewGroups()
|
* @method SilverStripe\ORM\ManyManyList<Member> ContentReviewUsers()
|
||||||
* @method DataList ContentReviewUsers()
|
* @method SilverStripe\ORM\HasManyList<ContentReviewLog> ReviewLogs()
|
||||||
*/
|
*/
|
||||||
class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
||||||
{
|
{
|
||||||
@ -142,7 +142,6 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
|||||||
$groupMembers = DataObject::get(Member::class)
|
$groupMembers = DataObject::get(Member::class)
|
||||||
->where("\"Group\".\"ID\" IN (" . implode(",", $groupIDs) . ")")
|
->where("\"Group\".\"ID\" IN (" . implode(",", $groupIDs) . ")")
|
||||||
->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"")
|
->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"")
|
||||||
/** @skipUpgrade */
|
|
||||||
->leftJoin('Group', "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\"");
|
->leftJoin('Group', "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\"");
|
||||||
|
|
||||||
$contentReviewOwners->merge($groupMembers);
|
$contentReviewOwners->merge($groupMembers);
|
||||||
|
@ -7,6 +7,10 @@ use SilverStripe\ORM\DataObject;
|
|||||||
use SilverStripe\Security\Member;
|
use SilverStripe\Security\Member;
|
||||||
use SilverStripe\Security\Security;
|
use SilverStripe\Security\Security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method Member Reviewer()
|
||||||
|
* @method SiteTree SiteTree()
|
||||||
|
*/
|
||||||
class ContentReviewLog extends DataObject
|
class ContentReviewLog extends DataObject
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -179,7 +179,6 @@ class PagesDueForReviewReport extends Report
|
|||||||
} else {
|
} else {
|
||||||
// Review date before
|
// Review date before
|
||||||
if (!empty($params['ReviewDateBefore'])) {
|
if (!empty($params['ReviewDateBefore'])) {
|
||||||
// TODO Get value from DateField->dataValue() once we have access to form elements here
|
|
||||||
$nextReviewUnixSec = strtotime(
|
$nextReviewUnixSec = strtotime(
|
||||||
' + 1 day',
|
' + 1 day',
|
||||||
strtotime($params['ReviewDateBefore'] ?? '')
|
strtotime($params['ReviewDateBefore'] ?? '')
|
||||||
@ -194,7 +193,6 @@ class PagesDueForReviewReport extends Report
|
|||||||
|
|
||||||
// Review date after
|
// Review date after
|
||||||
if (!empty($params['ReviewDateAfter'])) {
|
if (!empty($params['ReviewDateAfter'])) {
|
||||||
// TODO Get value from DateField->dataValue() once we have access to form elements here
|
|
||||||
$records = $records->where(
|
$records = $records->where(
|
||||||
sprintf(
|
sprintf(
|
||||||
"\"NextReviewDate\" >= '%s'",
|
"\"NextReviewDate\" >= '%s'",
|
||||||
|
@ -4,8 +4,6 @@ namespace SilverStripe\ContentReview\Tests;
|
|||||||
|
|
||||||
use SilverStripe\Dev\FunctionalTest;
|
use SilverStripe\Dev\FunctionalTest;
|
||||||
use SilverStripe\CMS\Model\SiteTree;
|
use SilverStripe\CMS\Model\SiteTree;
|
||||||
// @todo add translatable namespace
|
|
||||||
use Translatable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend this class when writing unit tests which are compatible with other modules.
|
* Extend this class when writing unit tests which are compatible with other modules.
|
||||||
@ -17,36 +15,4 @@ abstract class ContentReviewBaseTest extends FunctionalTest
|
|||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected $translatableEnabledBefore;
|
protected $translatableEnabledBefore;
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We set the locale for pages explicitly, because if we don't, then we get into a situation
|
|
||||||
* where the page takes on the tester's (your) locale, and any calls to simulate subsequent requests
|
|
||||||
* (e.g. $this->post()) do not seem to get passed the tester's locale,
|
|
||||||
* but instead fallback to the default locale.
|
|
||||||
*
|
|
||||||
* So we set the pages locale to be the default locale, which will then match any subsequent requests.
|
|
||||||
*
|
|
||||||
* If creating pages in your unit tests (rather than reading from the fixtures file), you must explicitly call
|
|
||||||
* self::compat() on the page, for the same reasons as above.
|
|
||||||
*/
|
|
||||||
if (class_exists(Translatable::class)) {
|
|
||||||
$this->translatableEnabledBefore = SiteTree::has_extension(Translatable::class);
|
|
||||||
SiteTree::remove_extension(Translatable::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
if (class_exists(Translatable::class)) {
|
|
||||||
if ($this->translatableEnabledBefore) {
|
|
||||||
SiteTree::add_extension(Translatable::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::tearDown();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,26 @@
|
|||||||
const Path = require('path');
|
const Path = require('path');
|
||||||
// Import the core config
|
const { JavascriptWebpackConfig, CssWebpackConfig } = require('@silverstripe/webpack-config');
|
||||||
const webpackConfig = require('@silverstripe/webpack-config');
|
|
||||||
const {
|
|
||||||
resolveJS,
|
|
||||||
externalJS,
|
|
||||||
moduleJS,
|
|
||||||
pluginJS,
|
|
||||||
moduleCSS,
|
|
||||||
pluginCSS,
|
|
||||||
} = webpackConfig;
|
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV;
|
const ENV = process.env.NODE_ENV;
|
||||||
const PATHS = {
|
const PATHS = {
|
||||||
MODULES: 'node_modules',
|
|
||||||
FILES_PATH: '../',
|
|
||||||
ROOT: Path.resolve(),
|
ROOT: Path.resolve(),
|
||||||
SRC: Path.resolve('client/src'),
|
SRC: Path.resolve('client/src'),
|
||||||
DIST: Path.resolve('client/dist'),
|
DIST: Path.resolve('client/dist'),
|
||||||
THIRDPARTY: Path.resolve('thirdparty'),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = [
|
const config = [
|
||||||
{
|
// Main JS bundle
|
||||||
name: 'js',
|
new JavascriptWebpackConfig('js', PATHS, 'silverstripe/contentreview')
|
||||||
entry: {
|
.setEntry({
|
||||||
contentreview: `${PATHS.SRC}/bundles/bundle.js`,
|
contentreview: `${PATHS.SRC}/bundles/bundle.js`,
|
||||||
},
|
})
|
||||||
output: {
|
.getConfig(),
|
||||||
path: PATHS.DIST,
|
// sass to css
|
||||||
filename: 'js/[name].js',
|
new CssWebpackConfig('css', PATHS)
|
||||||
},
|
.setEntry({
|
||||||
devtool: (ENV !== 'production') ? 'source-map' : '',
|
|
||||||
resolve: resolveJS(ENV, PATHS),
|
|
||||||
externals: externalJS(ENV, PATHS),
|
|
||||||
module: moduleJS(ENV, PATHS),
|
|
||||||
plugins: pluginJS(ENV, PATHS),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'css',
|
|
||||||
entry: {
|
|
||||||
contentreview: `${PATHS.SRC}/styles/bundle.scss`,
|
contentreview: `${PATHS.SRC}/styles/bundle.scss`,
|
||||||
},
|
})
|
||||||
output: {
|
.getConfig(),
|
||||||
path: PATHS.DIST,
|
|
||||||
filename: 'styles/[name].css'
|
|
||||||
},
|
|
||||||
devtool: (ENV !== 'production') ? 'source-map' : '',
|
|
||||||
module: moduleCSS(ENV, PATHS),
|
|
||||||
plugins: pluginCSS(ENV, PATHS),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
Loading…
Reference in New Issue
Block a user