Compare commits

..

35 Commits
4 ... 5.1.1

Author SHA1 Message Date
github-actions
3ac1f1bf9d Merge branch '4' into 5.1 2024-02-11 11:34:01 +00:00
Guy Sartorelli
84edeab427
Merge pull request #217 from creative-commoners/pulls/5.1/docblock
MNT Update @methods on class docblocks
2023-12-15 12:45:21 +13:00
Steve Boyd
d57cf056cb MNT Update @methods on class docblocks 2023-12-14 15:10:51 +13:00
Guy Sartorelli
d401365c23
Merge pull request #215 from creative-commoners/pulls/5.1/remove-todo
MNT Remove TODO comments
2023-10-30 12:20:08 +13:00
Sabina Talipova
c37f61861f MNT Remove TODO comments 2023-10-27 10:44:13 +13:00
github-actions
a7e77a66be Merge branch '5.0' into 5 2023-08-29 22:26:00 +00:00
Guy Sartorelli
5da7a119e4
Merge pull request #211 from creative-commoners/pulls/5.0/module-standardiser-1693278564
MNT Run module-standardiser
2023-08-29 17:08:09 +12:00
Steve Boyd
e0cef401b9 MNT Run module-standardiser 2023-08-29 15:09:24 +12:00
Guy Sartorelli
bded3af5ce
Merge branch '5.0' into 5 2023-08-29 10:27:53 +12:00
github-actions
51c69c6c0f Merge branch '4' into 5.0 2023-08-27 11:32:18 +00:00
github-actions[bot]
fd1fd08db0
DEP Update JS dependencies (#210)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-08-24 11:47:48 +12:00
github-actions
0dfe8a6c26 Merge branch '5.0' into 5 2023-08-20 11:32:15 +00:00
Guy Sartorelli
d96254e18e
Merge pull request #206 from creative-commoners/pulls/5/module-standardiser-1691550008
MNT Run module-standardiser
2023-08-15 12:09:10 +12:00
Steve Boyd
3f5079f5b6 MNT Run module-standardiser 2023-08-14 15:44:14 +12:00
Sabina Talipova
a571e5d8f8
DEP Update eslint module (#205) 2023-07-12 11:04:52 +12:00
Michal Kleiner
5c79718c0a Merge branch '4' into 5.0 2023-06-16 12:09:37 +12:00
Michal Kleiner
3d879d2d27 Merge branch '5.0' into 5 2023-06-16 11:20:21 +12:00
Michal Kleiner
ae8d36c79f Merge branch '4' into 5.0 2023-06-16 11:18:17 +12:00
Guy Sartorelli
e7671b3994
Merge pull request #198 from creative-commoners/pulls/5/tx-1686703299
ENH Update translations
2023-06-14 15:17:36 +12:00
Steve Boyd
91fa889d8d ENH Update translations 2023-06-14 12:41:39 +12:00
Steve Boyd
95d33141fd Merge branch '5.0' into 5 2023-05-04 13:28:02 +12:00
Guy Sartorelli
5c7a4254f4
Merge branch '4' into 5.0 2023-04-27 14:42:17 +12:00
Sabina Talipova
882da53ef3
Merge pull request #196 from creative-commoners/pulls/5.0/cms5-readme
DOC Update README.md for CMS 5
2023-04-21 14:38:42 +12:00
Guy Sartorelli
7a7e930d40
DOC Update README.md for CMS 5 2023-04-21 14:25:15 +12:00
Maxime Rainville
7955f8dcc4
Merge pull request #194 from creative-commoners/pulls/5.0/devjs
MNT Update dev JS
2023-04-03 15:32:20 +12:00
Steve Boyd
8e3dd58f78 MNT Update dev JS 2023-04-03 14:31:29 +12:00
Steve Boyd
5b93e37dee Merge branch '5.0' into 5 2023-03-30 13:26:59 +13:00
Steve Boyd
0ac70f6054 Merge branch '4' into 5.0 2023-03-30 13:26:50 +13:00
Steve Boyd
3ca281a4ed Merge branch '5.0' into 5 2023-03-08 12:18:55 +13:00
Steve Boyd
8433b007e5 Merge branch '4' into 5.0 2023-03-08 12:18:39 +13:00
Steve Boyd
376474f699 Merge branch '4' into 5 2023-02-03 10:21:00 +13:00
Guy Sartorelli
dc66fe86c9
DEP Upgrade frontend build stack (#182) 2023-01-30 14:00:46 +13:00
Maxime Rainville
978ffec4f9
Merge pull request #181 from creative-commoners/pulls/5/remove-legacy-upgrader
MNT Remove legacy upgrader config
2023-01-23 10:35:54 +13:00
Steve Boyd
6ca6bff7e1 MNT Remove legacy upgrader config 2023-01-20 17:11:08 +13:00
Sabina Talipova
f4b409e0d3
DEP PHP Support in CMS5 (#178) 2023-01-10 09:43:41 +13:00
29 changed files with 5554 additions and 3657 deletions

View File

@ -1,7 +0,0 @@
{
"extends": "airbnb",
"root": true,
"rules": {
"init-declarations": 1
}
}

1
.eslintrc.js Normal file
View File

@ -0,0 +1 @@
module.exports = require('@silverstripe/eslint-config/.eslintrc');

View File

@ -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
View 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

View File

@ -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:

2
.nvmrc
View File

@ -1 +1 @@
10 18

View File

@ -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

View File

@ -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:

View File

@ -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`.

View File

@ -1,6 +0,0 @@
---
Name: contentreviewlegacy
---
SilverStripe\ORM\DatabaseAdmin:
classname_value_remapping:
ContentReviewLog: SilverStripe\ContentReview\Models\ContentReviewLog

6
babel.config.json Normal file
View File

@ -0,0 +1,6 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}

View File

@ -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)}();

View File

@ -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}

View File

@ -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) {

View File

@ -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) {

View File

@ -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';

View File

@ -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;

View File

@ -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.11", "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"

View File

@ -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)'

View File

@ -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"
]
} }

View File

@ -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

View File

@ -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
{ {

View File

@ -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
{ {
/** /**

View File

@ -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);

View File

@ -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
{ {
/** /**

View File

@ -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'",

View File

@ -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();
}
} }

View File

@ -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;

8934
yarn.lock

File diff suppressed because it is too large Load Diff