├── .nvmrc ├── _config.php ├── lang ├── _manifest_exclude ├── fa_IR.yml ├── sl.yml ├── sv.yml ├── fi_FI.yml ├── pl.yml ├── sk.yml ├── en.yml ├── fi.yml ├── ru.yml ├── hr.yml ├── eo.yml ├── it.yml ├── de.yml └── nl.yml ├── codecov.yml ├── phpstan.neon.dist ├── .eslintrc.js ├── .stylelintrc.js ├── babel.config.json ├── templates └── SilverStripe │ └── Lumberjack │ └── Forms │ ├── GridFieldSiteTreeAddNewButton.ss │ └── GridFieldSiteTreeAddNewButton_holder.ss ├── code-of-conduct.md ├── .tx └── config ├── .github ├── ISSUE_TEMPLATE │ ├── 3_blank_issue.md │ ├── config.yml │ ├── 2_feature_request.yml │ └── 1_bug_report.yml ├── workflows │ ├── ci.yml │ ├── keepalive.yml │ ├── merge-up.yml │ ├── add-prs-to-project.yml │ ├── tag-patch-release.yml │ ├── update-js.yml │ └── dispatch-ci.yml └── PULL_REQUEST_TEMPLATE.md ├── _config └── lumberjack.yml ├── client ├── dist │ ├── js │ │ └── GridField.js │ └── styles │ │ └── lumberjack.css └── src │ ├── js │ └── GridField.js │ └── styles │ └── lumberjack.scss ├── phpcs.xml.dist ├── .editorconfig ├── changelog.md ├── phpunit.xml.dist ├── src ├── Forms │ ├── GridFieldSiteTreeViewButton.php │ ├── GridFieldSiteTreeEditButton.php │ ├── GridFieldConfig_Lumberjack.php │ ├── GridFieldSiteTreeState.php │ └── GridFieldSiteTreeAddNewButton.php └── Model │ └── Lumberjack.php ├── webpack.config.js ├── package.json ├── config.rb ├── composer.json ├── LICENSE ├── behat.yml └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /_config.php: -------------------------------------------------------------------------------- 1 | 2 | $FieldHolder 3 | <% end_loop %> -------------------------------------------------------------------------------- /templates/SilverStripe/Lumberjack/Forms/GridFieldSiteTreeAddNewButton_holder.ss: -------------------------------------------------------------------------------- 1 |
2 | $Field 3 |
4 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | When having discussions about this module in issues or pull request please adhere to the [SilverStripe Community Code of Conduct](https://docs.silverstripe.org/en/contributing/code_of_conduct). 2 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [o:silverstripe:p:silverstripe-lumberjack:r:master] 5 | file_filter = lang/.yml 6 | source_file = lang/en.yml 7 | source_lang = en 8 | type = YML 9 | 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_blank_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Blank issue 3 | about: Only for use by maintainers 4 | --- 5 | 6 | -------------------------------------------------------------------------------- /_config/lumberjack.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: lumberjack 3 | --- 4 | SilverStripe\Admin\LeftAndMain: 5 | extra_requirements_css: 6 | - silverstripe/lumberjack:client/dist/styles/lumberjack.css 7 | extra_requirements_javascript: 8 | - silverstripe/lumberjack:client/dist/js/GridField.js 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | ci: 10 | name: CI 11 | # Do not run if this is a pull-request from same repo i.e. not a fork repo 12 | if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository 13 | uses: silverstripe/gha-ci/.github/workflows/ci.yml@v2 14 | -------------------------------------------------------------------------------- /client/dist/js/GridField.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e={669:function(e){e.exports=jQuery}},t={};var r=function r(i){var d=t[i];if(void 0!==d)return d.exports;var n=t[i]={exports:{}};return e[i](n,n.exports,r),n.exports}(669);r.entwine("ss",e=>{e(".ss-gridfield .field .gridfield-dropdown").entwine({onchange(){const e=this.getGridField(),t=e.getState().GridFieldSiteTreeAddNewButton;t.recordType=this.val(),e.setState("GridFieldSiteTreeAddNewButton",t)}})})}(); -------------------------------------------------------------------------------- /phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeSniffer ruleset for SilverStripe coding conventions. 4 | 5 | src 6 | tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /client/src/js/GridField.js: -------------------------------------------------------------------------------- 1 | /* global jQuery */ 2 | (function ($) { 3 | // eslint-disable-next-line no-shadow 4 | $.entwine('ss', ($) => { 5 | $('.ss-gridfield .field .gridfield-dropdown').entwine({ 6 | 7 | onchange() { 8 | const gridField = this.getGridField(); 9 | const state = gridField.getState().GridFieldSiteTreeAddNewButton; 10 | 11 | state.recordType = this.val(); 12 | gridField.setState('GridFieldSiteTreeAddNewButton', state); 13 | } 14 | }); 15 | }); 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # For more information about the properties used in this file, 2 | # please see the EditorConfig documentation: 3 | # http://editorconfig.org 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = 4 9 | indent_style = space 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [{*.yml,*.js,*.scss,package.json,*.feature}] 14 | indent_size = 2 15 | indent_style = space 16 | 17 | # The indent size used in the package.json file cannot be changed: 18 | # https://github.com/npm/npm/pull/3180#issuecomment-16336516 19 | -------------------------------------------------------------------------------- /client/dist/styles/lumberjack.css: -------------------------------------------------------------------------------- 1 | .cms .ss-gridfield .gridfield-dropdown{margin:3px 8px 0 0;border-bottom:0}.cms .ss-gridfield .gridfield-dropdown .chzn-container,.cms .ss-gridfield .gridfield-dropdown .dropdown{min-width:195px}.cms .ss-gridfield .dropdown-action{font-size:12px;margin-top:.24em}.cms .gridfield-icon i{width:16px;height:16px;display:block;float:left;margin-right:6px}.cms .gridfield-icon.published i{color:#3fa142}.cms .modified{margin-left:5px;color:#7e7470;background-color:#fff0bc;padding:1px 3px;border:1px solid #c9b800;font-size:80%;border-radius:3px;text-transform:uppercase} 2 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | This project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [1.1.4] 8 | 9 | * Update translations. 10 | * If Translatable is active, set the Locale for new records 11 | 12 | ## [1.1.3] 13 | 14 | * Changelog added 15 | * Update translations 16 | * Update README.md 17 | * fixing composer require statement 18 | * filter hide_ancestor hidden page types from dropdown 19 | * BUG Fix creation of duplicate ParentID field on subtables of SiteTree 20 | * Add 3.2 and php 5.6 tests 21 | -------------------------------------------------------------------------------- /lang/fa_IR.yml: -------------------------------------------------------------------------------- 1 | fa_IR: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'افزودن {name} جدید' 4 | AddMultipleOptions: 'افزودن جدید' 5 | GridFieldSiteTreeState: 6 | Modified: 'اصلاح شده' 7 | StateTitle: وضیعت 8 | Lumberjack: 9 | TabTitle: 'صفحات زیرین' 10 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 11 | Add: 'افزودن {name} جدید' 12 | AddMultipleOptions: 'افزودن جدید' 13 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 14 | Modified: 'اصلاح شده' 15 | StateTitle: وضیعت 16 | SilverStripe\Lumberjack\Model\Lumberjack: 17 | TabTitle: 'صفحات زیرین' 18 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests/ 6 | 7 | 8 | 9 | 10 | 11 | src/ 12 | 13 | tests/ 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.github/workflows/keepalive.yml: -------------------------------------------------------------------------------- 1 | name: Keepalive 2 | 3 | on: 4 | # At 3:15 PM UTC, on day 16 of the month 5 | schedule: 6 | - cron: '15 15 16 * *' 7 | workflow_dispatch: 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | keepalive: 13 | name: Keepalive 14 | # Only run cron on the silverstripe account 15 | if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule') 16 | runs-on: ubuntu-latest 17 | permissions: 18 | actions: write 19 | steps: 20 | - name: Keepalive 21 | uses: silverstripe/gha-keepalive@v1 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Security Vulnerability 4 | url: https://docs.silverstripe.org/en/contributing/issues_and_bugs/#reporting-security-issues 5 | about: ⚠️ We do not use GitHub issues to track security vulnerability reports. Click "open" on the right to see how to report security vulnerabilities. 6 | - name: Support Question 7 | url: https://www.silverstripe.org/community/ 8 | about: We use GitHub issues only to discuss bugs and new features. For support questions, please use one of the support options available in our community channels. 9 | -------------------------------------------------------------------------------- /.github/workflows/merge-up.yml: -------------------------------------------------------------------------------- 1 | name: Merge-up 2 | 3 | on: 4 | # At 6:30 PM UTC, only on Saturday 5 | schedule: 6 | - cron: '30 18 * * 6' 7 | workflow_dispatch: 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | merge-up: 13 | name: Merge-up 14 | # Only run cron on the silverstripe account 15 | if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule') 16 | runs-on: ubuntu-latest 17 | permissions: 18 | contents: write 19 | actions: write 20 | steps: 21 | - name: Merge-up 22 | uses: silverstripe/gha-merge-up@v2 23 | -------------------------------------------------------------------------------- /src/Forms/GridFieldSiteTreeViewButton.php: -------------------------------------------------------------------------------- 1 | canView()) { 13 | return null; 14 | } 15 | 16 | $data = ArrayData::create([ 17 | 'Link' => $record->CMSEditLink(), 18 | ]); 19 | 20 | return $data->renderWith(GridFieldViewButton::class); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/add-prs-to-project.yml: -------------------------------------------------------------------------------- 1 | name: Add new PRs to github project 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - ready_for_review 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | addprtoproject: 13 | name: Add PR to GitHub Project 14 | # Only run on the silverstripe account 15 | if: github.repository_owner == 'silverstripe' 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Add PR to github project 19 | uses: silverstripe/gha-add-pr-to-project@v1 20 | with: 21 | app_id: ${{ vars.PROJECT_PERMISSIONS_APP_ID }} 22 | private_key: ${{ secrets.PROJECT_PERMISSIONS_APP_PRIVATE_KEY }} 23 | -------------------------------------------------------------------------------- /lang/sl.yml: -------------------------------------------------------------------------------- 1 | sl: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: "Dodaj '{name}'" 4 | AddMultipleOptions: Dodaj 5 | GridFieldSiteTreeState: 6 | Draft: ' Osnutek pripravljen {date}' 7 | Modified: Spremenjeno 8 | Published: ' Objavljeno {date}' 9 | StateTitle: Status 10 | Lumberjack: 11 | TabTitle: Podstrani 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: "Dodaj '{name}'" 14 | AddMultipleOptions: Dodaj 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Modified: Spremenjeno 17 | StateTitle: Status 18 | SilverStripe\Lumberjack\Model\Lumberjack: 19 | TabTitle: Podstrani 20 | -------------------------------------------------------------------------------- /lang/sv.yml: -------------------------------------------------------------------------------- 1 | sv: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Lägg till {name}' 4 | AddMultipleOptions: 'Lägg till' 5 | GridFieldSiteTreeState: 6 | Draft: ' Sparat som utkast {date}' 7 | Modified: Ändrad 8 | Published: ' Publicerad {date}' 9 | StateTitle: Status 10 | Lumberjack: 11 | TabTitle: Undersidor 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Lägg till {name}' 14 | AddMultipleOptions: 'Lägg till' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Modified: Ändrad 17 | StateTitle: Status 18 | SilverStripe\Lumberjack\Model\Lumberjack: 19 | TabTitle: Undersidor 20 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const Path = require('path'); 2 | const { JavascriptWebpackConfig, CssWebpackConfig } = require('@silverstripe/webpack-config'); 3 | 4 | const ENV = process.env.NODE_ENV; 5 | const PATHS = { 6 | ROOT: Path.resolve(), 7 | SRC: Path.resolve('client/src'), 8 | DIST: Path.resolve('client/dist'), 9 | }; 10 | 11 | const config = [ 12 | // Main JS bundle 13 | new JavascriptWebpackConfig('js', PATHS, 'silverstripe/lumberjack') 14 | .setEntry({ 15 | GridField: `${PATHS.SRC}/js/GridField.js` 16 | }) 17 | .getConfig(), 18 | // sass to css 19 | new CssWebpackConfig('css', PATHS) 20 | .setEntry({ 21 | lumberjack: `${PATHS.SRC}/styles/lumberjack.scss` 22 | }) 23 | .getConfig(), 24 | ]; 25 | 26 | module.exports = config; 27 | -------------------------------------------------------------------------------- /lang/fi_FI.yml: -------------------------------------------------------------------------------- 1 | fi_FI: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Lisää uusi {name}' 4 | AddMultipleOptions: 'Lisää uusi' 5 | GridFieldSiteTreeState: 6 | Draft: ' Tallennettiin vedoksena {date}' 7 | Modified: Muokattu 8 | Published: ' Julkaistu {date}' 9 | StateTitle: Tila 10 | Lumberjack: 11 | TabTitle: Alasivut 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Lisää uusi {name}' 14 | AddMultipleOptions: 'Lisää uusi' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Modified: Muokattu 17 | StateTitle: Tila 18 | SilverStripe\Lumberjack\Model\Lumberjack: 19 | TabTitle: Alasivut 20 | -------------------------------------------------------------------------------- /lang/pl.yml: -------------------------------------------------------------------------------- 1 | pl: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Dodaj nową {name}' 4 | AddMultipleOptions: 'Dodaj nową' 5 | GridFieldSiteTreeState: 6 | Draft: ' Zapisano jaki szkic {date}' 7 | Modified: Zmodyfikowano 8 | Published: ' Opublikowano {date}' 9 | StateTitle: Stan 10 | Lumberjack: 11 | TabTitle: Podstrony 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Dodaj nową {name}' 14 | AddMultipleOptions: 'Dodaj nową' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Modified: Zmodyfikowano 17 | StateTitle: Stan 18 | SilverStripe\Lumberjack\Model\Lumberjack: 19 | TabTitle: Podstrony 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "silverstripe-lumberjack", 3 | "engines": { 4 | "node": ">=18.x" 5 | }, 6 | "scripts": { 7 | "build": "yarn && yarn lint && rm -rf client/dist/* && NODE_ENV=production webpack --mode production --bail --progress", 8 | "dev": "NODE_ENV=development webpack --progress", 9 | "watch": "NODE_ENV=development webpack --watch --progress", 10 | "lint": "eslint client/src && stylelint client/src" 11 | }, 12 | "dependencies": {}, 13 | "devDependencies": { 14 | "@silverstripe/eslint-config": "^1.3.0", 15 | "@silverstripe/webpack-config": "^3", 16 | "webpack": "^5.94.0", 17 | "webpack-cli": "^5.0.0" 18 | }, 19 | "resolutions": { 20 | "colors": "1.4.0" 21 | }, 22 | "browserslist": [ 23 | "defaults" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /lang/sk.yml: -------------------------------------------------------------------------------- 1 | sk: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Pridať {name}' 4 | AddMultipleOptions: Pridať 5 | GridFieldSiteTreeState: 6 | Draft: ' Uložený ako koncept: {date}' 7 | Modified: zmenené 8 | Published: ' Publikovaný: {date}' 9 | StateTitle: Stav 10 | Lumberjack: 11 | TabTitle: Podstránky 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Pridať {name}' 14 | AddMultipleOptions: Pridať 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Uložené ako koncept dňa {date}' 17 | Modified: zmenené 18 | Published: 'Zverejnené dňa {date}' 19 | StateTitle: Stav 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: Podstránky 22 | -------------------------------------------------------------------------------- /lang/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Add new {name}' 4 | AddMultipleOptions: 'Add new' 5 | GridFieldSiteTreeState: 6 | Draft: ' Saved as Draft on {date}' 7 | Modified: Modified 8 | Published: ' Published on {date}' 9 | StateTitle: State 10 | Lumberjack: 11 | TabTitle: 'Child Pages' 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Add new {name}' 14 | AddMultipleOptions: 'Add new' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Saved as Draft on {date}' 17 | Modified: Modified 18 | Published: 'Published on {date}' 19 | StateTitle: State 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: 'Child Pages' 22 | -------------------------------------------------------------------------------- /lang/fi.yml: -------------------------------------------------------------------------------- 1 | fi: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Lisää uusi {name}' 4 | AddMultipleOptions: 'Lisää uusi' 5 | GridFieldSiteTreeState: 6 | Draft: ' Tallennettu luonnoksena {date}' 7 | Modified: Muokattu 8 | Published: ' Julkaistu {date}' 9 | StateTitle: Tila 10 | Lumberjack: 11 | TabTitle: Alasivut 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Lisää uusi {name}' 14 | AddMultipleOptions: 'Lisää uusi' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Tallennettu luonnoksena {date}' 17 | Modified: Muokattu 18 | Published: 'Julkaistu {date}' 19 | StateTitle: Tila 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: Alasivut 22 | -------------------------------------------------------------------------------- /lang/ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Добавить {name}' 4 | AddMultipleOptions: Добавить 5 | GridFieldSiteTreeState: 6 | Draft: ' Сохранено как черновик {date}' 7 | Modified: Изменено 8 | Published: ' Опубликовано {date}' 9 | StateTitle: Статус 10 | Lumberjack: 11 | TabTitle: Под-страницы 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Добавить {name}' 14 | AddMultipleOptions: Добавить 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Сохранено как черновик {date}' 17 | Modified: Изменено 18 | Published: 'Опубликовано {date}' 19 | StateTitle: Статус 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: Под-страницы 22 | -------------------------------------------------------------------------------- /client/src/styles/lumberjack.scss: -------------------------------------------------------------------------------- 1 | .cms { 2 | .ss-gridfield { 3 | .gridfield-dropdown { 4 | margin: 3px 8px 0 0; 5 | border-bottom: 0; 6 | 7 | .chzn-container, 8 | .dropdown { 9 | min-width: 195px; 10 | } 11 | } 12 | 13 | .dropdown-action { 14 | font-size: 12px; 15 | margin-top: 0.24em; 16 | } 17 | } 18 | 19 | .gridfield-icon i { 20 | width: 16px; 21 | height: 16px; 22 | display: block; 23 | float: left; 24 | margin-right: 6px; 25 | } 26 | 27 | .gridfield-icon.published i { 28 | color: #3fa142; 29 | } 30 | 31 | .modified { 32 | margin-left: 5px; 33 | color: #7E7470; 34 | background-color: #fff0bc; 35 | padding: 1px 3px; 36 | border: 1px solid #C9B800; 37 | font-size: 80%; 38 | border-radius: 3px; 39 | text-transform: uppercase; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/tag-patch-release.yml: -------------------------------------------------------------------------------- 1 | name: Tag patch release 2 | 3 | on: 4 | # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch 5 | workflow_dispatch: 6 | inputs: 7 | latest_local_sha: 8 | description: The latest local sha 9 | required: true 10 | type: string 11 | 12 | permissions: {} 13 | 14 | jobs: 15 | tagpatchrelease: 16 | name: Tag patch release 17 | # Only run cron on the silverstripe account 18 | if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule') 19 | runs-on: ubuntu-latest 20 | permissions: 21 | contents: write 22 | steps: 23 | - name: Tag release 24 | uses: silverstripe/gha-tag-release@v2 25 | with: 26 | latest_local_sha: ${{ inputs.latest_local_sha }} 27 | -------------------------------------------------------------------------------- /lang/hr.yml: -------------------------------------------------------------------------------- 1 | hr: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Dodaj novi {name}' 4 | AddMultipleOptions: 'Dodaj novi' 5 | GridFieldSiteTreeState: 6 | Draft: ' Spremljeno kao Draft u {date}' 7 | Modified: Promjenjeno 8 | Published: ' Objavljeno u {date}' 9 | StateTitle: Stanje 10 | Lumberjack: 11 | TabTitle: Podstranice 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Dodaj novi {name}' 14 | AddMultipleOptions: 'Dodaj novi' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Spremljeno kao Draft u {date}' 17 | Modified: Promjenjeno 18 | Published: 'Objavljeno u {date}' 19 | StateTitle: Stanje 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: Podstranice 22 | -------------------------------------------------------------------------------- /lang/eo.yml: -------------------------------------------------------------------------------- 1 | eo: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Enmeti novan {name}' 4 | AddMultipleOptions: 'Enmeti novan' 5 | GridFieldSiteTreeState: 6 | Draft: ' konserviĝis kiel malneto je {date}' 7 | Modified: Ŝanĝita 8 | Published: ' publikiĝis je {date}' 9 | StateTitle: Stato 10 | Lumberjack: 11 | TabTitle: 'Idoj de paĝoj' 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Enmeti novan {name}' 14 | AddMultipleOptions: 'Enmeti novan' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Konservita kiel malneta je {date}' 17 | Modified: Ŝanĝita 18 | Published: 'Publikigita je {date}' 19 | StateTitle: Stato 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: 'Idoj de paĝoj' 22 | -------------------------------------------------------------------------------- /lang/it.yml: -------------------------------------------------------------------------------- 1 | it: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Aggiungi nuovo {name}' 4 | AddMultipleOptions: 'Aggiungi nuovo' 5 | GridFieldSiteTreeState: 6 | Draft: 'Salvato come Bozza il {date}' 7 | Modified: Modificato 8 | Published: 'Pubblicato il {date}' 9 | StateTitle: Stato 10 | Lumberjack: 11 | TabTitle: 'Pagine Figlio' 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Aggiungi nuovo {name}' 14 | AddMultipleOptions: 'Aggiungi nuovo' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Salvato come Bozza il {date}' 17 | Modified: Modificato 18 | Published: 'Pubblicato il {date}' 19 | StateTitle: Stato 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: 'Pagine Figlio' 22 | -------------------------------------------------------------------------------- /lang/de.yml: -------------------------------------------------------------------------------- 1 | de: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Neuen {name} hinzufügen' 4 | AddMultipleOptions: 'Neuen hinzufügen' 5 | GridFieldSiteTreeState: 6 | Draft: ' Als Entwurf am {date} gespeichert' 7 | Modified: Geändert 8 | Published: ' Veröffentlicht am {date}' 9 | StateTitle: Status 10 | Lumberjack: 11 | TabTitle: Unterseiten 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Neuen {name} hinzufügen' 14 | AddMultipleOptions: 'Neuen hinzufügen' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Als Entwurf gespeichert am {date}' 17 | Modified: Geändert 18 | Published: 'Veröffentlicht am {date}' 19 | StateTitle: Status 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: Unterseiten 22 | -------------------------------------------------------------------------------- /lang/nl.yml: -------------------------------------------------------------------------------- 1 | nl: 2 | GridFieldSiteTreeAddNewButton: 3 | Add: 'Voeg nieuwe {name} toe' 4 | AddMultipleOptions: 'Voeg nieuwe toe' 5 | GridFieldSiteTreeState: 6 | Draft: ' Opgeslagen als concept op {date}' 7 | Modified: Aangepast 8 | Published: ' Gepubliceerd op {date}' 9 | StateTitle: Status 10 | Lumberjack: 11 | TabTitle: "Onderliggende pagina's" 12 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeAddNewButton: 13 | Add: 'Voeg nieuwe {name} toe' 14 | AddMultipleOptions: 'Voeg nieuwe toe' 15 | SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState: 16 | Draft: 'Opgeslagen als concept op {date}' 17 | Modified: Aangepast 18 | Published: 'Gepubliceerd op {date}' 19 | StateTitle: Status 20 | SilverStripe\Lumberjack\Model\Lumberjack: 21 | TabTitle: "Onderliggende pagina's" 22 | -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | 3 | # Set this to the root of your project when deployed: 4 | http_path = "/" 5 | css_dir = "css" 6 | sass_dir = "scss" 7 | images_dir = "images" 8 | javascripts_dir = "javascript" 9 | 10 | # You can select your preferred output style here (can be overridden via the command line): 11 | # output_style = :expanded or :nested or :compact or :compressed 12 | 13 | # To enable relative paths to assets via compass helper functions. Uncomment: 14 | relative_assets = true 15 | 16 | # To disable debugging comments that display the original location of your selectors. Uncomment: 17 | line_comments = true 18 | 19 | 20 | # If you prefer the indented syntax, you might want to regenerate this 21 | # project again passing --syntax sass, or you can uncomment this: 22 | # preferred_syntax = :sass 23 | # and then run: 24 | # sass-convert -R --from scss --to sass scss scss && rm -rf sass && mv scss sass 25 | -------------------------------------------------------------------------------- /.github/workflows/update-js.yml: -------------------------------------------------------------------------------- 1 | name: Update JS 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | branch_type: 7 | description: 'The branch type to run action on' 8 | required: true 9 | default: 'schedule' 10 | type: choice 11 | options: 12 | - 'schedule' 13 | - 'prev-major-curr-minor' 14 | - 'curr-major-curr-minor' 15 | - 'curr-major-next-minor' 16 | # At 10:50 PM UTC, on day 1 of the month, only in February and August 17 | schedule: 18 | - cron: '50 22 1 2,8 *' 19 | 20 | permissions: {} 21 | 22 | jobs: 23 | update-js: 24 | name: Update JS 25 | # Only run cron on the silverstripe account 26 | if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule') 27 | runs-on: ubuntu-latest 28 | permissions: 29 | contents: write 30 | pull-requests: write 31 | actions: write 32 | steps: 33 | - name: Update JS 34 | uses: silverstripe/gha-update-js@v1 35 | with: 36 | branch_type: ${{ github.event_name == 'schedule' && 'schedule' || github.event.inputs.branch_type }} 37 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "silverstripe/lumberjack", 3 | "description": "A module to make managing pages in a GridField easy without losing any of the functionality that you're used to in the CMS.", 4 | "type": "silverstripe-vendormodule", 5 | "require": { 6 | "php": "^8.3", 7 | "silverstripe/framework": "^6", 8 | "silverstripe/cms": "^6" 9 | }, 10 | "require-dev": { 11 | "phpunit/phpunit": "^11.3", 12 | "squizlabs/php_codesniffer": "^3", 13 | "silverstripe/standards": "^1", 14 | "phpstan/extension-installer": "^1.3", 15 | "silverstripe/frameworktest": "^2" 16 | }, 17 | "extra": { 18 | "expose": [ 19 | "client/dist" 20 | ] 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "SilverStripe\\Lumberjack\\": "src/", 25 | "SilverStripe\\Lumberjack\\Tests\\": "tests/php/" 26 | } 27 | }, 28 | "license": "BSD-2-Clause", 29 | "minimum-stability": "dev", 30 | "prefer-stable": true, 31 | "authors": [ 32 | { 33 | "name": "Michael Strong", 34 | "email": "mstrong@silverstripe.org" 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src/Forms/GridFieldSiteTreeEditButton.php: -------------------------------------------------------------------------------- 1 | 16 | **/ 17 | class GridFieldSiteTreeEditButton extends GridFieldEditButton 18 | { 19 | /** 20 | * @param GridField $gridField 21 | * @param DataObject $record 22 | * @param string $columnName 23 | * @return string - the HTML for the column 24 | */ 25 | public function getColumnContent($gridField, $record, $columnName) 26 | { 27 | // No permission checks - handled through GridFieldDetailForm 28 | // which can make the form readonly if no edit permissions are available. 29 | 30 | $data = ArrayData::create([ 31 | 'Link' => $record->getCMSEditLink(), 32 | 'ExtraClass' => $this->getExtraClass(), 33 | ]); 34 | 35 | return $data->renderWith(GridFieldEditButton::class); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Michael Strong 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /behat.yml: -------------------------------------------------------------------------------- 1 | default: 2 | suites: 3 | lumberjack: 4 | paths: 5 | - "%paths.modules.lumberjack%/tests/behat/features" 6 | contexts: 7 | - SilverStripe\Framework\Tests\Behaviour\FeatureContext 8 | - SilverStripe\Framework\Tests\Behaviour\CmsFormsContext 9 | - SilverStripe\Framework\Tests\Behaviour\CmsUiContext 10 | - SilverStripe\BehatExtension\Context\BasicContext 11 | - SilverStripe\BehatExtension\Context\LoginContext 12 | - 13 | SilverStripe\BehatExtension\Context\FixtureContext: 14 | - '%paths.modules.lumberjack%/tests/behat/features/files/' 15 | - 16 | SilverStripe\Framework\Tests\Behaviour\ConfigContext: 17 | - '%paths.modules.lumberjack%/tests/behat/features/files/' 18 | 19 | extensions: 20 | SilverStripe\BehatExtension\MinkExtension: 21 | default_session: facebook_web_driver 22 | javascript_session: facebook_web_driver 23 | facebook_web_driver: 24 | browser: chrome 25 | wd_host: "http://127.0.0.1:9515" #chromedriver port 26 | browser_name: chrome 27 | 28 | SilverStripe\BehatExtension\Extension: 29 | screenshot_path: "%paths.base%/artifacts/screenshots" 30 | bootstrap_file: "vendor/silverstripe/framework/tests/behat/serve-bootstrap.php" 31 | -------------------------------------------------------------------------------- /.github/workflows/dispatch-ci.yml: -------------------------------------------------------------------------------- 1 | name: Dispatch CI 2 | 3 | on: 4 | # At 6:30 PM UTC, only on Monday, Tuesday, and Wednesday 5 | schedule: 6 | - cron: '30 18 * * 1,2,3' 7 | workflow_dispatch: 8 | inputs: 9 | major_type: 10 | description: 'Major branch type' 11 | required: true 12 | type: choice 13 | options: 14 | - 'dynamic' 15 | - 'current' 16 | - 'next' 17 | - 'previous' 18 | default: 'dynamic' 19 | minor_type: 20 | description: 'Minor branch type' 21 | required: true 22 | type: choice 23 | options: 24 | - 'dynamic' 25 | - 'next-minor' 26 | - 'next-patch' 27 | default: 'dynamic' 28 | 29 | permissions: {} 30 | 31 | jobs: 32 | dispatch-ci: 33 | name: Dispatch CI 34 | # Only run cron on the silverstripe account 35 | if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule') 36 | runs-on: ubuntu-latest 37 | permissions: 38 | contents: read 39 | actions: write 40 | steps: 41 | - name: Dispatch CI 42 | uses: silverstripe/gha-dispatch-ci@v1 43 | with: 44 | major_type: ${{ inputs.major_type }} 45 | minor_type: ${{ inputs.minor_type }} 46 | -------------------------------------------------------------------------------- /src/Forms/GridFieldConfig_Lumberjack.php: -------------------------------------------------------------------------------- 1 | 21 | **/ 22 | class GridFieldConfig_Lumberjack extends GridFieldConfig 23 | { 24 | /** 25 | * @param int|null $itemsPerPage 26 | */ 27 | public function __construct($itemsPerPage = null) 28 | { 29 | parent::__construct($itemsPerPage); 30 | $this->addComponent(new GridFieldButtonRow('before')); 31 | $this->addComponent(new GridFieldSiteTreeAddNewButton('buttons-before-left')); 32 | $this->addComponent(new GridFieldToolbarHeader()); 33 | $this->addComponent(new GridFieldSortableHeader()); 34 | $this->addComponent(new GridFieldFilterHeader()); 35 | $this->addComponent(new GridFieldDataColumns()); 36 | $this->addComponent(new GridFieldSiteTreeEditButton()); 37 | $this->addComponent(new GridFieldPageCount('toolbar-header-right')); 38 | $this->addComponent(new GridFieldPaginator($itemsPerPage)); 39 | $this->addComponent(new GridFieldSiteTreeState()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature Request 2 | description: Submit a feature request (but only if you're planning on implementing it) 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | Please only submit feature requests if you plan on implementing the feature yourself. 8 | See the [contributing code documentation](https://docs.silverstripe.org/en/contributing/code/#make-or-find-a-github-issue) for more guidelines about submitting feature requests. 9 | - type: textarea 10 | id: description 11 | attributes: 12 | label: Description 13 | description: A clear and concise description of the new feature, and why it belongs in core 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: more-info 18 | attributes: 19 | label: Additional context or points of discussion 20 | description: | 21 | *Optional: Any additional context, points of discussion, etc that might help validate and refine your idea* 22 | - type: checkboxes 23 | id: validations 24 | attributes: 25 | label: Validations 26 | description: "Before submitting the issue, please confirm the following:" 27 | options: 28 | - label: You intend to implement the feature yourself 29 | required: true 30 | - label: You have read the [contributing guide](https://docs.silverstripe.org/en/contributing/code/) 31 | required: true 32 | - label: You strongly believe this feature should be in core, rather than being its own community module 33 | required: true 34 | - label: You have checked for existing issues or pull requests related to this feature (and didn't find any) 35 | required: true 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | ## Description 7 | 11 | 12 | ## Manual testing steps 13 | 17 | 18 | ## Issues 19 | 23 | - # 24 | 25 | ## Pull request checklist 26 | 30 | - [ ] The target branch is correct 31 | - See [picking the right version](https://docs.silverstripe.org/en/contributing/code/#picking-the-right-version) 32 | - [ ] All commits are relevant to the purpose of the PR (e.g. no debug statements, unrelated refactoring, or arbitrary linting) 33 | - Small amounts of additional linting are usually okay, but if it makes it hard to concentrate on the relevant changes, ask for the unrelated changes to be reverted, and submitted as a separate PR. 34 | - [ ] The commit messages follow our [commit message guidelines](https://docs.silverstripe.org/en/contributing/code/#commit-messages) 35 | - [ ] The PR follows our [contribution guidelines](https://docs.silverstripe.org/en/contributing/code/) 36 | - [ ] Code changes follow our [coding conventions](https://docs.silverstripe.org/en/contributing/coding_conventions/) 37 | - [ ] This change is covered with tests (or tests aren't necessary for this change) 38 | - [ ] Any relevant User Help/Developer documentation is updated; for impactful changes, information is added to the changelog for the intended release 39 | - [ ] CI is green 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Silverstripe Lumberjack 2 | 3 | [![CI](https://github.com/silverstripe/silverstripe-lumberjack/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/silverstripe-lumberjack/actions/workflows/ci.yml) 4 | [![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/) 5 | 6 | A module to make managing pages in a GridField easy without losing any of the functionality that you're used to in the CMS. 7 | 8 | This is intended to be used in cases where the SiteTree grows beyond a manageable level. eg. blogs, news sections, shops, etc. 9 | 10 | This module was born out of and decoupled from [micmania1/silverstripe-blog](https://github.com/micmania1/silverstripe-blogger). 11 | 12 | ## Installation 13 | 14 | ```sh 15 | composer require silverstripe/lumberjack 16 | ``` 17 | 18 | ## Features 19 | 20 | * Easily define which page types to show in the SiteTree and which to manage in a GridField. 21 | * Keep all functionality that comes with the CMS, including versioning and preview. 22 | 23 | ## Usage 24 | 25 | In this example we have a `NewsHolder` page which is the root of our news section, containing `NewsArticle`s and 26 | `NewsPage`s. We want to display `NewsPage` in the site tree but we want to display `NewsArticle`s in a `GridField`. 27 | 28 | ```php 29 | 15 | **/ 16 | class GridFieldSiteTreeState implements GridField_ColumnProvider 17 | { 18 | use Injectable; 19 | 20 | public function augmentColumns($gridField, &$columns) 21 | { 22 | // Ensure Actions always appears as the last column. 23 | $key = array_search('Actions', $columns ?? []); 24 | if ($key !== false) { 25 | unset($columns[$key]); 26 | } 27 | 28 | $columns = array_merge($columns, array( 29 | 'State', 30 | 'Actions', 31 | )); 32 | } 33 | 34 | public function getColumnsHandled($gridField) 35 | { 36 | return array('State'); 37 | } 38 | 39 | public function getColumnContent($gridField, $record, $columnName) 40 | { 41 | if ($columnName == 'State') { 42 | if ($record->hasMethod('isPublished')) { 43 | $modifiedLabel = ''; 44 | if ($record->isModifiedOnDraft()) { 45 | $modifiedLabel = '' . _t(__CLASS__ . '.Modified', 'Modified') . ''; 46 | } 47 | 48 | $published = $record->isPublished(); 49 | if (!$published) { 50 | return '' . _t( 51 | __CLASS__ . '.Draft', 52 | 'Saved as Draft on {date}', 53 | 'State for when a post is saved.', 54 | array( 55 | 'date' => $record->dbObject('LastEdited')->Nice() 56 | ) 57 | ); 58 | } 59 | return '' . _t( 60 | __CLASS__ . '.Published', 61 | 'Published on {date}', 62 | 'State for when a post is published.', 63 | array( 64 | 'date' => $record->dbObject('LastEdited')->Nice() 65 | ) 66 | ) . $modifiedLabel; 67 | } 68 | } 69 | } 70 | 71 | public function getColumnAttributes($gridField, $record, $columnName) 72 | { 73 | if ($columnName == 'State') { 74 | if ($record->hasMethod('isPublished')) { 75 | $published = $record->isPublished(); 76 | if (!$published) { 77 | $class = 'gridfield-icon draft'; 78 | } else { 79 | $class = 'gridfield-icon published'; 80 | } 81 | return array('class' => $class); 82 | } 83 | } 84 | return array(); 85 | } 86 | 87 | public function getColumnMetaData($gridField, $columnName) 88 | { 89 | switch ($columnName) { 90 | case 'State': 91 | return array('title' => _t(__CLASS__ . '.StateTitle', 'State', 'Column title for state')); 92 | default: 93 | break; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1_bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🪳 Bug Report 2 | description: Tell us if something isn't working the way it's supposed to 3 | 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | We strongly encourage you to [submit a pull request](https://docs.silverstripe.org/en/contributing/code/) which fixes the issue. 9 | Bug reports which are accompanied with a pull request are a lot more likely to be resolved quickly. 10 | - type: input 11 | id: affected-versions 12 | attributes: 13 | label: Module version(s) affected 14 | description: | 15 | What version of _this module_ have you reproduced this bug on? 16 | Run `composer info` to see the specific version of each module installed in your project. 17 | If you don't have access to that, check inside the help menu in the bottom left of the CMS. 18 | placeholder: x.y.z 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: description 23 | attributes: 24 | label: Description 25 | description: A clear and concise description of the problem 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: how-to-reproduce 30 | attributes: 31 | label: How to reproduce 32 | description: | 33 | ⚠️ This is the most important part of the report ⚠️ 34 | Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix. 35 | - Please, take the time to show us some code and/or configuration that is needed for others to reproduce the problem easily. 36 | - If the bug is too complex to reproduce with some short code samples, please reproduce it in a public repository and provide a link to the repository along with steps for setting up and reproducing the bug using that repository. 37 | - If part of the bug includes an error or exception, please provide a full stack trace. 38 | - If any user interaction is required to reproduce the bug, please add an ordered list of steps that are required to reproduce it. 39 | - Be as clear as you can, but don't miss any steps out. Simply saying "create a page" is less useful than guiding us through the steps you're taking to create a page, for example. 40 | placeholder: | 41 | 42 | #### Code sample 43 | ```php 44 | 45 | ``` 46 | 47 | #### Reproduction steps 48 | 1. 49 | validations: 50 | required: true 51 | - type: textarea 52 | id: possible-solution 53 | attributes: 54 | label: Possible Solution 55 | description: | 56 | *Optional: only if you have suggestions on a fix/reason for the bug* 57 | Please consider [submitting a pull request](https://docs.silverstripe.org/en/contributing/code/) with your solution! It helps get faster feedback and greatly increases the chance of the bug being fixed. 58 | - type: textarea 59 | id: additional-context 60 | attributes: 61 | label: Additional Context 62 | description: "*Optional: any other context about the problem: log messages, screenshots, etc.*" 63 | - type: checkboxes 64 | id: validations 65 | attributes: 66 | label: Validations 67 | description: "Before submitting the issue, please make sure you do the following:" 68 | options: 69 | - label: Check that there isn't already an issue that reports the same bug 70 | required: true 71 | - label: Double check that your reproduction steps work in a fresh installation of [`silverstripe/installer`](https://github.com/silverstripe/silverstripe-installer) (with any code examples you've provided) 72 | required: true 73 | -------------------------------------------------------------------------------- /src/Forms/GridFieldSiteTreeAddNewButton.php: -------------------------------------------------------------------------------- 1 | 31 | */ 32 | class GridFieldSiteTreeAddNewButton extends GridFieldAddNewButton implements GridField_ActionProvider 33 | { 34 | /** 35 | * Determine the list of classnames and titles allowed for a given parent object 36 | * 37 | * @param SiteTree $parent 38 | * @return boolean 39 | */ 40 | public function getAllowedChildren(?SiteTree $parent = null) 41 | { 42 | if (!$parent || !$parent->canAddChildren()) { 43 | return array(); 44 | } 45 | 46 | $nonHiddenPageTypes = ClassInfo::getValidSubClasses(SiteTree::class); 47 | SiteTree::singleton()->updateAllowedSubClasses($nonHiddenPageTypes); 48 | $allowedChildren = $parent->allowedChildren(); 49 | $children = array(); 50 | foreach ($allowedChildren as $class) { 51 | if (Config::inst()->get($class, 'show_in_sitetree') === false) { 52 | $instance = Injector::inst()->get($class); 53 | // Note: Second argument to SiteTree::canCreate will support inherited permissions 54 | // post 3.1.12, and will default to the old permission model in 3.1.11 or below 55 | // See http://docs.silverstripe.org/en/changelogs/3.1.11 56 | if ( 57 | $instance->canCreate(null, array('Parent' => $parent)) && 58 | in_array($class, $nonHiddenPageTypes ?? []) 59 | ) { 60 | $children[$class] = $instance->i18n_singular_name(); 61 | } 62 | } 63 | } 64 | return $children; 65 | } 66 | 67 | public function getHTMLFragments($gridField) 68 | { 69 | $state = $gridField->State->GridFieldSiteTreeAddNewButton; 70 | 71 | $parent = SiteTree::get()->byId(Controller::curr()->currentRecordID()); 72 | 73 | if ($parent) { 74 | $state->currentRecordID = $parent->ID; 75 | } 76 | 77 | $children = $this->getAllowedChildren($parent); 78 | if (empty($children)) { 79 | return array(); 80 | } elseif (count($children ?? []) > 1) { 81 | $pageTypes = DropdownField::create('RecordType', 'Page Type', $children, $parent->defaultChild()); 82 | $pageTypes 83 | ->setFieldHolderTemplate(__CLASS__ . '_holder') 84 | ->addExtraClass('gridfield-dropdown no-change-track'); 85 | 86 | $state->RecordType = $parent->defaultChild(); 87 | 88 | if (!$this->buttonName) { 89 | $this->buttonName = _t( 90 | __CLASS__ . '.AddMultipleOptions', 91 | 'Add new', 92 | 'Add button text for multiple options.' 93 | ); 94 | } 95 | } else { 96 | $keys = array_keys($children ?? []); 97 | $pageTypes = HiddenField::create('RecordType', 'Page Type', $keys[0]); 98 | 99 | $state->recordType = $keys[0]; 100 | 101 | if (!$this->buttonName) { 102 | $this->buttonName = _t( 103 | __CLASS__ . '.Add', 104 | 'Add new {name}', 105 | 'Add button text for a single option.', 106 | ['name' => $children[$keys[0]]] 107 | ); 108 | } 109 | } 110 | 111 | $addAction = GridField_FormAction::create($gridField, 'add', $this->buttonName, 'add', 'add'); 112 | $addAction 113 | ->setIcon('add') 114 | ->addExtraClass('no-ajax btn btn-primary'); 115 | 116 | $forTemplate = ArrayData::create(); 117 | $forTemplate->Fields = ArrayList::create(); 118 | $forTemplate->Fields->push($pageTypes); 119 | $forTemplate->Fields->push($addAction); 120 | 121 | return [$this->targetFragment => $forTemplate->renderWith(__CLASS__)]; 122 | } 123 | 124 | /** 125 | * Provide actions to this component. 126 | * 127 | * @param GridField $gridField 128 | * @return array 129 | **/ 130 | public function getActions($gridField) 131 | { 132 | return array('add'); 133 | } 134 | 135 | /** 136 | * Handles the add action, but only acts as a wrapper for CMSMain 137 | * 138 | * @param GridField $gridField 139 | * @param string $actionName 140 | * @param mixed $arguments 141 | * @param array $data 142 | * 143 | * @return HTTPResponse|null 144 | */ 145 | public function handleAction(GridField $gridField, $actionName, $arguments, $data) 146 | { 147 | if ($actionName == 'add') { 148 | $tmpData = json_decode($data['ChildPages']['GridState'] ?? '', true); 149 | $tmpData = $tmpData['GridFieldSiteTreeAddNewButton']; 150 | 151 | $data = array( 152 | 'ParentID' => $tmpData['currentRecordID'], 153 | 'RecordType' => $tmpData['recordType'] 154 | ); 155 | 156 | $controller = Injector::inst()->create(CMSMain::class); 157 | $form = $controller->AddForm(); 158 | 159 | // pass current request down in case either of these needs it 160 | $request = Controller::curr()->getRequest(); 161 | $controller->setRequest($request); 162 | $form->getRequestHandler()->setRequest($request); 163 | 164 | $form->loadDataFrom($data); 165 | return $form->doAdd($data, $form); 166 | } 167 | 168 | return null; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/Model/Lumberjack.php: -------------------------------------------------------------------------------- 1 | 31 | * 32 | * @extends Extension 33 | */ 34 | class Lumberjack extends Extension 35 | { 36 | /** 37 | * Loops through subclasses of the owner (intended to be SiteTree) and checks if they've been hidden. 38 | * 39 | * @return array 40 | **/ 41 | public function getExcludedSiteTreeClassNames() 42 | { 43 | $classes = array(); 44 | $siteTreeClasses = $this->owner->allowedChildren(); 45 | 46 | foreach ($siteTreeClasses as $class) { 47 | if (Config::inst()->get($class, 'show_in_sitetree') === false) { 48 | $classes[$class] = $class; 49 | } 50 | } 51 | 52 | $this->owner->extend('updateSiteTreeExcludedClassNames', $classes); 53 | 54 | return $classes; 55 | } 56 | 57 | /** 58 | * This is responsible for adding the child pages tab and gridfield. 59 | * 60 | * @param FieldList $fields 61 | */ 62 | protected function updateCMSFields(FieldList $fields) 63 | { 64 | $excluded = $this->owner->getExcludedSiteTreeClassNames(); 65 | if (!empty($excluded)) { 66 | $pages = $this->getLumberjackPagesForGridfield($excluded); 67 | $gridField = GridField::create( 68 | 'ChildPages', 69 | $this->getLumberjackTitle(), 70 | $pages, 71 | $this->getLumberjackGridFieldConfig() 72 | ); 73 | 74 | // Ensure correct link is used when gridfield is readonly 75 | $readonlyComponents = $gridField->getReadonlyComponents(); 76 | $viewButtonIndex = array_search(GridFieldViewButton::class, $readonlyComponents); 77 | if ($viewButtonIndex !== false) { 78 | unset($readonlyComponents[$viewButtonIndex]); 79 | } 80 | $readonlyComponents[] = GridFieldSiteTreeViewButton::class; 81 | $gridField->setReadonlyComponents($readonlyComponents); 82 | 83 | $tab = Tab::create('ChildPages', $this->getLumberjackTitle(), $gridField); 84 | $fields->insertAfter('Main', $tab); 85 | } 86 | } 87 | 88 | /** 89 | * Return children in the stage site. 90 | * 91 | * @param bool $showAll Include all of the elements, even those not shown in the menus. Only applicable when 92 | * extension is applied to {@link SiteTree}. 93 | * @return DataList 94 | */ 95 | public function stageChildren($showAll = false) 96 | { 97 | $config = $this->owner->config(); 98 | $hideFromHierarchy = $config->get('hide_from_hierarchy'); 99 | $hideFromCMSTree = $config->get('hide_from_cms_tree'); 100 | $baseClass = $this->owner->baseClass(); 101 | 102 | $staged = $baseClass::get() 103 | ->filter('ParentID', (int)$this->owner->ID) 104 | ->exclude('ID', (int)$this->owner->ID); 105 | 106 | if ($hideFromHierarchy) { 107 | $staged = $staged->exclude('ClassName', $hideFromHierarchy); 108 | } 109 | 110 | if ($hideFromCMSTree && $this->owner->showingCMSTree()) { 111 | $staged = $staged->exclude('ClassName', $hideFromCMSTree); 112 | } 113 | 114 | if (!$showAll && DataObject::getSchema()->fieldSpec($this->owner, 'ShowInMenus')) { 115 | $staged = $staged->filter('ShowInMenus', 1); 116 | } 117 | 118 | $this->owner->extend("augmentStageChildren", $staged, $showAll); 119 | $staged = $this->excludeSiteTreeClassNames($staged); 120 | return $staged; 121 | } 122 | 123 | /** 124 | * @param mixed $includeDeleted @deprecated - this parameter is unused and will be removed in a future major release 125 | */ 126 | protected function updateGetChildrenForTree(mixed $includeDeleted, SS_List &$children): void 127 | { 128 | $children = $this->excludeSiteTreeClassNames($children); 129 | } 130 | 131 | /** 132 | * Excludes any hidden owner subclasses. Note that the returned DataList will be a different 133 | * instance from the original. 134 | * 135 | * @param SS_List $list 136 | * @return SS_List 137 | */ 138 | protected function excludeSiteTreeClassNames($list) 139 | { 140 | $classNames = $this->owner->getExcludedSiteTreeClassNames(); 141 | if ($this->shouldFilter() && count($classNames ?? [])) { 142 | // Filter the SiteTree 143 | $list = $list->exclude('ClassName', $classNames); 144 | } 145 | return $list; 146 | } 147 | 148 | /** 149 | * Return children in the live site, if it exists. 150 | * 151 | * @param bool $showAll Include all of the elements, even those not shown in the menus. Only 152 | * applicable when extension is applied to {@link SiteTree}. 153 | * @param bool $onlyDeletedFromStage Only return items that have been deleted from stage 154 | * @return DataList 155 | * @throws Exception 156 | */ 157 | public function liveChildren($showAll = false, $onlyDeletedFromStage = false) 158 | { 159 | if (!$this->owner->hasExtension(Versioned::class)) { 160 | throw new Exception('Hierarchy->liveChildren() only works with Versioned extension applied'); 161 | } 162 | 163 | $config = $this->owner->config(); 164 | $hideFromHierarchy = $config->get('hide_from_hierarchy'); 165 | $hideFromCMSTree = $config->get('hide_from_cms_tree'); 166 | $baseClass = $this->owner->baseClass(); 167 | 168 | $children = $baseClass::get() 169 | ->filter('ParentID', (int)$this->owner->ID) 170 | ->exclude('ID', (int)$this->owner->ID) 171 | ->setDataQueryParam(array( 172 | 'Versioned.mode' => $onlyDeletedFromStage ? 'stage_unique' : 'stage', 173 | 'Versioned.stage' => 'Live' 174 | )); 175 | 176 | if ($hideFromHierarchy) { 177 | $children = $children->exclude('ClassName', $hideFromHierarchy); 178 | } 179 | 180 | if ($hideFromCMSTree && $this->owner->showingCMSTree()) { 181 | $children = $children->exclude('ClassName', $hideFromCMSTree); 182 | } 183 | 184 | if (!$showAll && DataObject::getSchema()->fieldSpec($this->owner, 'ShowInMenus')) { 185 | $children = $children->filter('ShowInMenus', 1); 186 | } 187 | $children = $this->excludeSiteTreeClassNames($children); 188 | 189 | return $children; 190 | } 191 | 192 | /** 193 | * This returns the title for the tab and GridField. This can be overwritten 194 | * in the owner class. 195 | * 196 | * @return string 197 | */ 198 | protected function getLumberjackTitle() 199 | { 200 | if (method_exists($this->owner, 'getLumberjackTitle')) { 201 | return $this->owner->getLumberjackTitle(); 202 | } 203 | 204 | return _t(__CLASS__ . '.TabTitle', 'Child Pages'); 205 | } 206 | 207 | /** 208 | * This returns the gird field config for the lumberjack gridfield. 209 | * 210 | * @return GridFieldConfig_Lumberjack 211 | */ 212 | protected function getLumberjackGridFieldConfig() 213 | { 214 | if (method_exists($this->owner, 'getLumberjackGridFieldConfig')) { 215 | return $this->owner->getLumberjackGridFieldConfig(); 216 | } 217 | 218 | return GridFieldConfig_Lumberjack::create(); 219 | } 220 | 221 | /** 222 | * Checks if we're on a controller where we should filter. ie. Are we loading the SiteTree? 223 | * NB: This only checks the current controller. See https://github.com/silverstripe/silverstripe-lumberjack/pull/60 224 | * for a discussion around this. 225 | * 226 | * @return bool 227 | */ 228 | protected function shouldFilter() 229 | { 230 | $controller = Controller::curr(); 231 | 232 | // relevant only for CMS 233 | if (!($controller instanceof LeftAndMain)) { 234 | return false; 235 | } 236 | 237 | return in_array($controller->getAction(), [ 238 | 'index', 'show', 'treeview', 'listview', 'getsubtree' 239 | ]); 240 | } 241 | 242 | /** 243 | * Returns list of pages for the CMS gridfield 244 | * 245 | * This also allows the owner class to override this method, e.g. to provide custom ordering. 246 | * 247 | * @var array $excluded List of class names excluded from the SiteTree 248 | * @return DataList 249 | */ 250 | public function getLumberjackPagesForGridfield($excluded = array()) 251 | { 252 | if (method_exists($this->owner, 'getLumberjackPagesForGridfield')) { 253 | return $this->owner->getLumberjackPagesForGridfield($excluded); 254 | } 255 | 256 | return SiteTree::get()->filter([ 257 | 'ParentID' => $this->owner->ID, 258 | 'ClassName' => $excluded, 259 | ]); 260 | } 261 | } 262 | --------------------------------------------------------------------------------