Compare commits

...

69 Commits

Author SHA1 Message Date
github-actions
37d2ccff76 Merge branch '4.1' into 4 2024-02-10 12:28:13 +00:00
github-actions
85664ce91b Merge branch '3' into 4.1 2024-02-10 12:28:12 +00:00
Guy Sartorelli
5d9007d5d7
MNT Run module-standardiser (#741) 2024-02-02 13:57:32 +13:00
Guy Sartorelli
3b8092272b
ENH Add generic types (#739) 2024-01-19 09:58:02 +13:00
Guy Sartorelli
e8e40a808d
Merge pull request #738 from silverstripe/pulls/4/update-js-1704075825
DEP Update JS dependencies
2024-01-08 14:32:20 +13:00
github-actions
63516905a4 DEP Update JS dependencies 2024-01-01 02:23:45 +00:00
github-actions
a1858fad6c Merge branch '4.1' into 4 2023-12-23 12:28:31 +00:00
Guy Sartorelli
0d037571ac
MNT Run module-standardiser (#737) 2023-12-21 16:15:25 +13:00
Guy Sartorelli
283ca6a664
Merge pull request #736 from silverstripeltd/bugfix/icons-in-add-gridfield
Remove icons from gridfield add button
2023-12-20 13:01:58 +13:00
Mohamed Alsharaf
b2f0d12dd6 Remove icons from gridfield add button 2023-12-19 14:10:15 +13:00
Guy Sartorelli
0704d99992
Merge branch '4.1' into 4 2023-12-18 15:18:17 +13:00
Guy Sartorelli
1e982c8f31
Merge pull request #734 from creative-commoners/pulls/4.1/docblock
MNT Update @methods on class docblocks
2023-12-15 12:45:23 +13:00
Steve Boyd
33da9d042d MNT Update @methods on class docblocks 2023-12-14 15:08:00 +13:00
Will Rossiter
e6228eae37
Merge pull request #733 from lerni/mb-again
addition to #685 also, respect mb-config in controller for tags & categories
2023-11-21 10:49:05 +13:00
Lukas Erni
d6375c5048 addition to #685 also, respect mb in controller 2023-11-20 21:30:38 +01:00
dependabot[bot]
1d901be802
Merge pull request #731 from silverstripe/dependabot/npm_and_yarn/babel/traverse-7.23.2 2023-11-17 05:33:02 +00:00
Michal Kleiner
c394361e14
Merge pull request #732 from lerni/remove-plus-icon-on-summary
remove plus icon for consistency
2023-11-17 14:39:44 +13:00
Lukas Erni
926ce562f1 remove plus icon for consistency 2023-11-16 15:26:12 +01:00
github-actions
4a71f93f23 Merge branch '4.1' into 4 2023-11-04 12:28:26 +00:00
Guy Sartorelli
99d74f9c43
Merge pull request #730 from creative-commoners/pulls/4.1/remove-todo
MNT Remove TODO comments
2023-10-30 12:20:52 +13:00
Sabina Talipova
7d15e3cc68 MNT Remove TODO comments 2023-10-26 09:14:16 +13:00
dependabot[bot]
2ef3981000
Bump @babel/traverse from 7.23.0 to 7.23.2
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.23.0 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-19 13:24:40 +00:00
Guy Sartorelli
08e2bd38e7
Merge pull request #685 from wilr/wilr-patch-1
Allow multibyte to be configured (fixes #605)
2023-10-09 20:48:45 +13:00
Will Rossiter
99d1063361
FIX: Allow multibyte to be configured (#605) 2023-10-09 19:17:31 +13:00
Guy Sartorelli
ff9b019c2d
Merge pull request #728 from silverstripe/pulls/4/update-js-1696126787
DEP Update JS dependencies
2023-10-03 14:04:22 +13:00
github-actions
e363b0e590 DEP Update JS dependencies 2023-10-01 02:19:47 +00:00
github-actions
685ccf39a8 Merge branch '4.1' into 4 2023-09-30 12:28:26 +00:00
github-actions
fe638a0ccb Merge branch '4.0' into 4.1 2023-09-30 12:28:25 +00:00
github-actions
38bad2d658 Merge branch '3' into 4.0 2023-09-30 12:28:24 +00:00
github-actions
f4ae122351 Merge branch '4.0' into 4 2023-08-29 22:25:36 +00:00
Guy Sartorelli
0f93f6a842
Merge pull request #726 from creative-commoners/pulls/4.0/module-standardiser-1693278479
MNT Run module-standardiser
2023-08-29 17:02:53 +12:00
Steve Boyd
7964baa544 MNT Run module-standardiser 2023-08-29 15:07:59 +12:00
github-actions
ca5dfb4ed3 Merge branch '4.0' into 4 2023-08-26 12:28:30 +00:00
github-actions
81c661caf2 Merge branch '3' into 4.0 2023-08-26 12:28:28 +00:00
github-actions[bot]
1f3878bc3f
DEP Update JS dependencies (#725)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-08-24 11:48:42 +12:00
Guy Sartorelli
b9c535ac67
Merge pull request #720 from 3Dgoo/4
Replace deprecated sort rand with shuffle
2023-08-19 11:02:43 +12:00
Guy Sartorelli
e9390c3525
ENH Update translations (#722) 2023-08-17 18:15:20 +12:00
Guy Sartorelli
29ca438a9f
Merge pull request #719 from creative-commoners/pulls/4/module-standardiser-1691549948
MNT Run module-standardiser
2023-08-15 12:09:04 +12:00
Steve Boyd
6f3b32264e MNT Run module-standardiser 2023-08-14 15:43:42 +12:00
3Dgoo
bcbb40e08d
Replace deprecated sort rand with shuffle 2023-08-10 12:31:45 +09:30
3Dgoo
7189427bf3
Replace deprecated sort rand with shuffle 2023-08-10 12:20:25 +09:30
dependabot[bot]
c93566f7a8
Merge pull request #718 from silverstripe/dependabot/npm_and_yarn/word-wrap-1.2.4 2023-08-03 05:25:35 +00:00
dependabot[bot]
23fd31c105
Bump word-wrap from 1.2.3 to 1.2.4
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-19 02:03:25 +00:00
Sabina Talipova
1514d0b982
DEP Update eslint module (#716) 2023-07-12 11:04:37 +12:00
Sabina Talipova
84b815d0a0
MNT ESLint issues (#714) 2023-07-10 09:47:20 +12:00
Steve Boyd
3f4b87489c Merge branch '4.0' into 4 2023-06-16 11:38:35 +12:00
Steve Boyd
7f86285552 Merge branch '3' into 4.0 2023-06-16 11:37:59 +12:00
Guy Sartorelli
f2388c6408
Merge pull request #712 from creative-commoners/pulls/4/tx-1686703251
ENH Update translations
2023-06-14 15:17:34 +12:00
Steve Boyd
7cbeb90280 ENH Update translations 2023-06-14 12:40:51 +12:00
Steve Boyd
08cee006fc Merge branch '4.0' into 4 2023-05-31 14:42:18 +12:00
Steve Boyd
058e2aced6 Merge branch '3' into 4.0 2023-05-31 14:42:02 +12:00
Steve Boyd
d8be9212cd Merge branch '4.0' into 4 2023-05-04 13:27:32 +12:00
Guy Sartorelli
dbeefc15c7
Merge branch '3' into 4.0 2023-04-27 14:45:17 +12:00
Sabina Talipova
0f8f0ac0cb
Merge pull request #707 from creative-commoners/pulls/4.0/cms5-readme
DOC Update README.md for CMS 5
2023-04-21 15:24:03 +12:00
Guy Sartorelli
05ed7e3be7
DOC Update README.md for CMS 5 2023-04-19 16:00:33 +12:00
Maxime Rainville
262b66dffd
Merge pull request #706 from creative-commoners/pulls/4.0/devjs
MNT Update dev JS
2023-04-03 15:32:14 +12:00
Steve Boyd
692c8fc390 MNT Update dev JS 2023-04-03 14:28:32 +12:00
Steve Boyd
008b2d4816 Merge branch '4.0' into 4 2023-03-30 13:31:11 +13:00
Steve Boyd
631fb53713 Merge branch '3' into 4.0 2023-03-30 13:30:34 +13:00
Steve Boyd
fb7ba28a24 Merge branch '4.0' into 4 2023-03-08 12:24:35 +13:00
Steve Boyd
85f8f32736 Merge branch '3' into 4.0 2023-03-08 12:24:25 +13:00
Guy Sartorelli
ffea8acb0e
DEP Upgrade frontend build stack (#697) 2023-02-07 13:35:34 +13:00
Steve Boyd
f01d421ee2 Merge branch '3' into 4 2023-02-03 10:12:51 +13:00
Guy Sartorelli
624444e136
Merge pull request #699 from creative-commoners/pulls/4/broken-builds
MNT Broken builds
2023-01-25 12:46:17 +13:00
Steve Boyd
9b49e1bfcc MNT Broken builds 2023-01-24 15:41:55 +13:00
Maxime Rainville
d24ea64be2
Merge pull request #698 from creative-commoners/pulls/4/remove-legacy-upgrader
MNT Remove legacy upgrader config
2023-01-23 10:39:10 +13:00
Steve Boyd
57b81dbbe3 MNT Remove legacy upgrader config 2023-01-20 17:14:18 +13:00
Maxime Rainville
0f1da8c938
Merge pull request #693 from creative-commoners/pulls/4/upgrade-cms5
DEP PHP Support in CMS5
2023-01-13 10:51:29 +13:00
Sabina Talipova
29f0b39271 DEP PHP Support in CMS5 2023-01-13 10:18:14 +13:00
47 changed files with 4690 additions and 7077 deletions

1
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1 @@
<!-- Blank templates are for use by maintainers only! If you aren't a maintainer, please go back and pick one of the issue templates. -->

72
.github/ISSUE_TEMPLATE/1_bug_report.yml vendored Normal file
View File

@ -0,0 +1,72 @@
name: 🪳 Bug Report
description: Tell us if something isn't working the way it's supposed to
body:
- type: markdown
attributes:
value: |
We strongly encourage you to [submit a pull request](https://docs.silverstripe.org/en/contributing/code/) which fixes the issue.
Bug reports which are accompanied with a pull request are a lot more likely to be resolved quickly.
- type: input
id: affected-versions
attributes:
label: Module version(s) affected
description: |
What version of _this module_ have you reproduced this bug on?
Run `composer info` to see the specific version of each module installed in your project.
If you don't have access to that, check inside the help menu in the bottom left of the CMS.
placeholder: x.y.z
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: A clear and concise description of the problem
validations:
required: true
- type: textarea
id: how-to-reproduce
attributes:
label: How to reproduce
description: |
⚠️ This is the most important part of the report ⚠️
Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix.
- Please, take the time to show us some code and/or configuration that is needed for others to reproduce the problem easily.
- 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.
- If part of the bug includes an error or exception, please provide a full stack trace.
- If any user interaction is required to reproduce the bug, please add an ordered list of steps that are required to reproduce it.
- 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.
placeholder: |
#### Code sample
```php
```
#### Reproduction steps
1.
validations:
required: true
- type: textarea
id: possible-solution
attributes:
label: Possible Solution
description: |
*Optional: only if you have suggestions on a fix/reason for the bug*
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.
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: "*Optional: any other context about the problem: log messages, screenshots, etc.*"
- type: checkboxes
id: validations
attributes:
label: Validations
description: "Before submitting the issue, please make sure you do the following:"
options:
- label: Check that there isn't already an issue that reports the same bug
required: true
- 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)
required: true

View File

@ -0,0 +1,35 @@
name: 🚀 Feature Request
description: Submit a feature request (but only if you're planning on implementing it)
body:
- type: markdown
attributes:
value: |
Please only submit feature requests if you plan on implementing the feature yourself.
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.
- type: textarea
id: description
attributes:
label: Description
description: A clear and concise description of the new feature, and why it belongs in core
validations:
required: true
- type: textarea
id: more-info
attributes:
label: Additional context or points of discussion
description: |
*Optional: Any additional context, points of discussion, etc that might help validate and refine your idea*
- type: checkboxes
id: validations
attributes:
label: Validations
description: "Before submitting the issue, please confirm the following:"
options:
- label: You intend to implement the feature yourself
required: true
- label: You have read the [contributing guide](https://docs.silverstripe.org/en/contributing/code/)
required: true
- label: You strongly believe this feature should be in core, rather than being its own community module
required: true
- label: You have checked for existing issues or pull requests related to this feature (and didn't find any)
required: true

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Security Vulnerability
url: https://docs.silverstripe.org/en/contributing/issues_and_bugs/#reporting-security-issues
about: ⚠️ We do not use GitHub issues to track security vulnerability reports. Click "open" on the right to see how to report security vulnerabilities.
- name: Support Question
url: https://www.silverstripe.org/community/
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.

39
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,39 @@
<!--
Thanks for contributing, you're awesome! ⭐
Please read https://docs.silverstripe.org/en/contributing/code/ if you haven't contributed to this project recently.
-->
## Description
<!--
Please describe expected and observed behaviour, and what you're fixing.
For visual fixes, please include tested browsers and screenshots.
-->
## Manual testing steps
<!--
Include any manual testing steps here which a reviewer can perform to validate your pull request works correctly.
Note that this DOES NOT replace unit or end-to-end tests.
-->
## Issues
<!--
List all issues here that this pull request fixes/resolves.
If there is no issue already, create a new one! You must link your pull request to at least one issue.
-->
- #
## Pull request checklist
<!--
PLEASE check each of these to ensure you have done everything you need to do!
If there's something in this list you need help with, please ask so that we can assist you.
-->
- [ ] The target branch is correct
- See [picking the right version](https://docs.silverstripe.org/en/contributing/code/#picking-the-right-version)
- [ ] All commits are relevant to the purpose of the PR (e.g. no debug statements, unrelated refactoring, or arbitrary linting)
- 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.
- [ ] The commit messages follow our [commit message guidelines](https://docs.silverstripe.org/en/contributing/code/#commit-messages)
- [ ] The PR follows our [contribution guidelines](https://docs.silverstripe.org/en/contributing/code/)
- [ ] Code changes follow our [coding conventions](https://docs.silverstripe.org/en/contributing/coding_conventions/)
- [ ] This change is covered with tests (or tests aren't necessary for this change)
- [ ] Any relevant User Help/Developer documentation is updated; for impactful changes, information is added to the changelog for the intended release
- [ ] CI is green

View File

@ -1,10 +1,10 @@
name: Keepalive name: Keepalive
on: on:
workflow_dispatch: # At 2:10 AM UTC, on day 11 of the month
# The 4th of every month at 10:50am UTC
schedule: schedule:
- cron: '50 10 4 * *' - cron: '10 2 11 * *'
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 12:20 PM UTC, only on Saturday
schedule:
- cron: '20 12 * * 6'
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: '10 2 1 */3 *'
jobs: jobs:
update-js: update-js:

2
.nvmrc
View File

@ -1 +1 @@
10 18

View File

@ -1,33 +0,0 @@
mappings:
GridFieldCategorisationConfig: SilverStripe\Blog\Admin\GridFieldCategorisationConfig
GridFieldFormAction: SilverStripe\Blog\Admin\GridFieldFormAction
GridFieldMergeAction: SilverStripe\Blog\Admin\GridFieldMergeAction
BlogCommentExtension: SilverStripe\Blog\Model\BlogCommentExtension
BlogFilter: SilverStripe\Blog\Model\BlogFilter
BlogFilter_GridField: SilverStripe\Blog\Model\BlogFilter\BlogFilterGridField
BlogMemberExtension: SilverStripe\Blog\Model\BlogMemberExtension
BlogPostFilter: SilverStripe\Blog\Model\BlogPostFilter
BlogPostNotifications: SilverStripe\Blog\Model\BlogPostNotifications
Blog: SilverStripe\Blog\Model\Blog
Blog_Controller: SilverStripe\Blog\Model\BlogController
BlogController: SilverStripe\Blog\Model\BlogController
BlogCategory: SilverStripe\Blog\Model\BlogCategory
BlogPost: SilverStripe\Blog\Model\BlogPost
BlogPost_Controller: SilverStripe\Blog\Model\BlogPostController
BlogPostController: SilverStripe\Blog\Model\BlogPostController
BlogTag: SilverStripe\Blog\Model\BlogTag
CategorisationObject: SilverStripe\Blog\Model\CategorisationObject
BlogAdminSidebar: SilverStripe\Blog\Forms\BlogAdminSidebar
GridFieldAddByDBField: SilverStripe\Blog\Forms\GridField\GridFieldAddByDBField
GridFieldBlogPostState: SilverStripe\Blog\Forms\GridField\GridFieldBlogPostState
GridFieldConfig_BlogPost: SilverStripe\Blog\Forms\GridField\GridFieldConfigBlogPost
BlogArchiveWidget: SilverStripe\Blog\Widgets\BlogArchiveWidget
BlogArchiveWidget_Controller: SilverStripe\Blog\Widgets\BlogArchiveWidgetController
BlogCategoriesWidget: SilverStripe\Blog\Widgets\BlogCategoriesWidget
BlogCategoriesWidget_Controller: SilverStripe\Blog\Widgets\BlogCategoriesWidgetController
BlogRecentPostsWidget: SilverStripe\Blog\Widgets\BlogRecentPostsWidget
BlogRecentPostsWidget_Controller: SilverStripe\Blog\Widgets\BlogRecentPostsWidgetController
BlogTagsCloudWidget: SilverStripe\Blog\Widgets\BlogTagsCloudWidget
BlogTagsCloudWidget_Controller: SilverStripe\Blog\Widgets\BlogTagsCloudWidgetController
BlogTagsWidget: SilverStripe\Blog\Widgets\BlogTagsWidget
BlogTagsWidget_Controller: SilverStripe\Blog\Widgets\BlogTagsWidgetController

View File

View File

@ -8,16 +8,6 @@
* [User guide](docs/en/userguide/index.md) * [User guide](docs/en/userguide/index.md)
* [Developer documentation](docs/en/index.md) * [Developer documentation](docs/en/index.md)
## Requirements
* Silverstripe CMS 4.0+
* Silverstripe Lumberjack Module 2.0+
* Silverstripe Tag Field Module 2.0+
* Silverstripe Assets 1.0+
* Silverstripe Asset Admin Module 1.0+
Note: this version is compatible with Silverstripe 4. For Silverstripe 3, please see [the 2.x release line](https://github.com/silverstripe/silverstripe-blog/tree/2).
### Suggested Modules ### Suggested Modules
* Silverstripe Widgets Module * Silverstripe Widgets Module
@ -28,13 +18,3 @@ Note: this version is compatible with Silverstripe 4. For Silverstripe 3, please
``` ```
composer require silverstripe/blog composer require silverstripe/blog
``` ```
## Upgrading
### Upgrading from 2.x to 3.x
Aside from the framework and CMS upgrades required the blog module should not require anything extra to be completed.
### Upgrading legacy blog to 2.x
If you're upgrading from blog version 1.0 to 2.x you will need to run the `BlogMigrationTask`. Run the task using `dev/tasks/BlogMigrationTask` either via the browser or sake CLI to migrate your legacy blog to the new version data structure.

View File

@ -1,14 +0,0 @@
---
Name: bloglegacy
---
SilverStripe\ORM\DatabaseAdmin:
classname_value_remapping:
Blog: SilverStripe\Blog\Model\Blog
BlogCategory: SilverStripe\Blog\Model\BlogCategory
BlogPost: SilverStripe\Blog\Model\BlogPost
BlogTag: SilverStripe\Blog\Model\BlogTag
BlogArchiveWidget: SilverStripe\Blog\Widgets\BlogArchiveWidget
BlogCategoriesWidget: SilverStripe\Blog\Widgets\BlogCategoriesWidget
BlogRecentPostsWidget: SilverStripe\Blog\Widgets\BlogRecentPostsWidget
BlogTagsCloudWidget: SilverStripe\Blog\Widgets\BlogTagsCloudWidget
BlogTagsWidget: SilverStripe\Blog\Widgets\BlogTagsWidget

6
babel.config.json Normal file
View File

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

View File

@ -1 +1 @@
!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s="./client/src/main.js")}({"./client/src/bundles/cms.js":function(t,e,n){"use strict";var i=n(0);n.n(i).a.entwine("ss",function(t){t(".cms-content-fields > #Form_EditForm_error").entwine({onadd:function(){var e=t(".blog-admin-outer");1===e.length&&e.prepend(this)}}),t(".toggle-description").entwine({onadd:function(){var e=t(this);if(!e.hasClass("toggle-description-enabled")){e.addClass("toggle-description-enabled");var n=!1,i=e.closest(".field").find(".form-text");e.on("click",function(){i[n?"hide":"show"](),e.toggleClass("toggle-description-shown"),n=!n}),i.hide(),e.parent().addClass("toggle-description-correct-right"),e.parent().prev(".middleColumn").addClass("toggle-description-correct-middle"),e.parent().next(".description").addClass("toggle-description-correct-description")}}}),t(".MergeAction").entwine({onadd:function(){var e=t(this);e.on("click","select",function(){return!1}),e.children("button").each(function(e,n){var i=t(n),o=i.prev("select");i.before('<input type="hidden" name="'+i.attr("data-target")+'" value="'+o.val()+'" />')}),e.on("change","select",function(e){var n=t(e.target);n.next("input").val(n.val())}),e.children("button, select").hide(),e.on("click",".MergeActionReveal",function(e){var n=t(e.target);return n.parent().children("button, select").show(),n.hide(),!1})}}),t(".blog-admin-sidebar.cms-panel").entwine({MinInnerWidth:620,onadd:function(){var e=this;this._super(),this.updateLayout(),!this.hasClass("collapsed")&&t(".blog-admin-outer").width()<this.getMinInnerWidth()&&this.collapsePanel();var n=function(){e.updateLayout()};n.bind(this),window.onresize=n},togglePanel:function(t,e){this._super(t,e),this.updateLayout()},updateLayout:function(){t(this).css("height","100%");var e=t(this).outerHeight(),n=t(".cms-content-actions").eq(0).outerHeight();t(this).css("height",e-n+"px"),t(this).css("bottom",n+"px"),t(".cms-container").updateLayoutOptions({minContentWidth:820+this.width()})}})})},"./client/src/bundles/gridfieldaddbydbfield.js":function(t,e,n){"use strict";var i=n(0);n.n(i).a.entwine("ss",function(t){t(".add-existing-autocompleter input.text").entwine({onkeydown:function(e){13===e.which&&(t(this).parents(".add-existing-autocompleter").find('button[type="submit"]').click(),e.preventDefault())}})})},"./client/src/main.js":function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),n("./client/src/bundles/cms.js"),n("./client/src/bundles/gridfieldaddbydbfield.js")},0:function(t,e){t.exports=jQuery}}); !function(){"use strict";var t={949:function(t,e,n){var i;((i=n(311))&&i.__esModule?i:{default:i}).default.entwine("ss",(t=>{t(".cms-content-fields > #Form_EditForm_error").entwine({onadd(){const e=t(".blog-admin-outer");1===e.length&&e.prepend(this)}}),t(".toggle-description").entwine({onadd(){const e=t(this);if(e.hasClass("toggle-description-enabled"))return;e.addClass("toggle-description-enabled");let n=!1;const i=e.closest(".field").find(".form-text");e.on("click",(()=>{i[n?"hide":"show"](),e.toggleClass("toggle-description-shown"),n=!n})),i.hide(),e.parent().addClass("toggle-description-correct-right"),e.parent().prev(".middleColumn").addClass("toggle-description-correct-middle"),e.parent().next(".description").addClass("toggle-description-correct-description")}}),t(".MergeAction").entwine({onadd(){const e=t(this);e.on("click","select",(()=>!1)),e.children("button").each(((e,n)=>{const i=t(n),s=i.prev("select");i.before(`<input type="hidden" name="${i.attr("data-target")}" value="${s.val()}" />`)})),e.on("change","select",(e=>{const n=t(e.target);n.next("input").val(n.val())})),e.children("button, select").hide(),e.on("click",".MergeActionReveal",(e=>{const n=t(e.target);return n.parent().children("button, select").show(),n.hide(),!1}))}}),t(".blog-admin-sidebar.cms-panel").entwine({MinInnerWidth:620,onadd(){this._super(),this.updateLayout(),!this.hasClass("collapsed")&&t(".blog-admin-outer").width()<this.getMinInnerWidth()&&this.collapsePanel();const e=()=>{this.updateLayout()};e.bind(this),window.onresize=e},togglePanel(t,e){this._super(t,e),this.updateLayout()},updateLayout(){t(this).css("height","100%");const e=t(this).outerHeight(),n=t(".cms-content-actions").eq(0).outerHeight();t(this).css("height",e-n+"px"),t(this).css("bottom",`${n}px`),t(".cms-container").updateLayoutOptions({minContentWidth:820+this.width()})}})}))},997:function(t,e,n){var i;((i=n(311))&&i.__esModule?i:{default:i}).default.entwine("ss",(t=>{t(".add-existing-autocompleter input.text").entwine({onkeydown(e){if(13===e.which){t(this).parents(".add-existing-autocompleter").find('button[type="submit"]').click(),e.preventDefault()}}})}))},311:function(t){t.exports=jQuery}},e={};function n(i){var s=e[i];if(void 0!==s)return s.exports;var o=e[i]={exports:{}};return t[i](o,o.exports,n),o.exports}n(949),n(997)}();

View File

@ -1 +1 @@
.no-sidebar .content-container.size3of4{width:75%}.blog-entry .post-image img{width:98.75%}.blog-sidebar .WidgetHolder ul{margin-left:0}.blog-sidebar .WidgetHolder ul li,ul.blogTagCloud{list-style-type:none}ul.blogTagCloud{clear:both}ul.blogTagCloud li{float:left;display:inline;padding-right:8px}ul.blogTagCloud li a span{float:left;line-height:30px;text-align:center;padding:0}ul.blogTagCloud .tagCount10{font-size:26pt}ul.blogTagCloud .tagCount9{font-size:24pt}ul.blogTagCloud .tagCount8{font-size:22pt}ul.blogTagCloud .tagCount7{font-size:20pt}ul.blogTagCloud .tagCount6{font-size:18pt}ul.blogTagCloud .tagCount5{font-size:16pt}ul.blogTagCloud .tagCount4{font-size:14pt}ul.blogTagCloud .tagCount3{font-size:12pt}ul.blogTagCloud .tagCount2{font-size:10pt}ul.blogTagCloud .tagCount1{font-size:8pt}#FeaturedImage .middleColumn{clear:none;float:left}.has-panel .cms-content-tools.blog-admin-sidebar{width:280px;border-right:0;border-left:1px solid #c0c0c2;position:absolute!important;right:0;top:0;height:100%}.has-panel .cms-content-tools.blog-admin-sidebar .cms-panel-toggle a{text-align:left;margin:0}.has-panel .cms-content-tools.blog-admin-sidebar .cms-panel-toggle.south{border-top:1px solid #aaa}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer{width:100%;padding-right:280px;position:absolute;height:100%;overflow-y:hidden;overflow-x:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset{position:relative;overflow:auto;height:100%;width:100%}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset #Title label{float:none}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset #Title .middleColumn,.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset #Title input{width:100%;max-width:100%;margin-left:0}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field+.field{margin-top:10px}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.urlsegment .preview{padding-top:0;line-height:25px}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.urlsegment .edit{float:right}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn>.date{width:60%}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn>.time{width:36%;float:right}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn .middleColumn,.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn input{width:100%}.has-panel .cms-content-tools.blog-admin-sidebar.collapsed~.blog-admin-outer{padding-right:41px}.has-panel .cms-content-tools.blog-admin-sidebar.collapsed~.blog-admin-outer #Root_Main{margin-right:15px}.has-panel .cms-content-tools.blog-admin-sidebar.cms-content-tools .cms-panel-content{width:auto}.toggle-description{display:inline-block;font-size:1.2rem;width:20px;height:20px;margin-top:1px;cursor:pointer}.middleColumn.toggle-description-correct-middle{margin-left:0;float:left;width:416px}.tab-content .field p.toggle-description-correct-right{display:inline-block;margin-left:0;padding-left:0;clear:none;float:left}.description.toggle-description-correct-description{width:416px;padding:12px 0}.custom-summary .ui-accordion-content,.custom-summary .ui-accordion-content .field{padding:0}.custom-summary .ui-icon-triangle-1-e{background-position:-16px -128px}.cms table.ss-gridfield-table tr td.MergeAction{width:225px}.cms table.ss-gridfield-table tr td.MergeAction a{display:block;height:100%;width:100%}.cms table.ss-gridfield-table tr td.MergeAction select{width:150px}.blog-cms-categorisation .toolbar--content{margin-top:0}.blog-cms-categorisation .MergeActionReveal:after{content:"@";font-family:silverstripe;display:inline-block;position:relative;margin-left:10px;top:3px}.blog-cms-categorisation .blog-merge-action{margin-top:5px} .no-sidebar .content-container.size3of4{width:75%}.blog-entry .post-image img{width:98.75%}.blog-sidebar .WidgetHolder ul{margin-left:0}.blog-sidebar .WidgetHolder ul li{list-style-type:none}ul.blogTagCloud{list-style-type:none;clear:both}ul.blogTagCloud li{float:left;display:inline;padding-right:8px}ul.blogTagCloud li a span{float:left;line-height:30px;text-align:center;padding:0}ul.blogTagCloud .tagCount10{font-size:26pt}ul.blogTagCloud .tagCount9{font-size:24pt}ul.blogTagCloud .tagCount8{font-size:22pt}ul.blogTagCloud .tagCount7{font-size:20pt}ul.blogTagCloud .tagCount6{font-size:18pt}ul.blogTagCloud .tagCount5{font-size:16pt}ul.blogTagCloud .tagCount4{font-size:14pt}ul.blogTagCloud .tagCount3{font-size:12pt}ul.blogTagCloud .tagCount2{font-size:10pt}ul.blogTagCloud .tagCount1{font-size:8pt}#FeaturedImage .middleColumn{clear:none;float:left}.has-panel .cms-content-tools.blog-admin-sidebar{width:280px;border-right:0;border-left:1px solid #c0c0c2;position:absolute !important;right:0;top:0;height:100%}.has-panel .cms-content-tools.blog-admin-sidebar .cms-panel-toggle a{text-align:left;margin:0}.has-panel .cms-content-tools.blog-admin-sidebar .cms-panel-toggle.south{border-top:1px solid #aaa}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer{width:100%;padding-right:280px;position:absolute;height:100%;overflow-y:hidden;overflow-x:hidden;box-sizing:border-box}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset{position:relative;overflow:auto;height:100%;width:100%}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset #Title label{float:none}.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset #Title .middleColumn,.has-panel .cms-content-tools.blog-admin-sidebar~.blog-admin-outer>.ss-tabset #Title input{width:100%;max-width:100%;margin-left:0}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field+.field{margin-top:10px}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.urlsegment .preview{padding-top:0;line-height:25px}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.urlsegment .edit{float:right}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn>.date{width:60%}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn>.time{width:36%;float:right}.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn .middleColumn,.has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view>.field.datetime>.middleColumn input{width:100%}.has-panel .cms-content-tools.blog-admin-sidebar.collapsed~.blog-admin-outer{padding-right:41px}.has-panel .cms-content-tools.blog-admin-sidebar.collapsed~.blog-admin-outer #Root_Main{margin-right:15px}.has-panel .cms-content-tools.blog-admin-sidebar.cms-content-tools .cms-panel-content{width:auto}.toggle-description{display:inline-block;font-size:1.2rem;width:20px;height:20px;margin-top:1px;cursor:pointer}.middleColumn.toggle-description-correct-middle{margin-left:0;float:left;width:416px}.tab-content .field p.toggle-description-correct-right{display:inline-block;margin-left:0;padding-left:0;clear:none;float:left}.description.toggle-description-correct-description{width:416px;padding:12px 0}.custom-summary .ui-accordion-content,.custom-summary .ui-accordion-content .field{padding:0}.cms table.ss-gridfield-table tr td.MergeAction{width:225px}.cms table.ss-gridfield-table tr td.MergeAction a{display:block;height:100%;width:100%}.cms table.ss-gridfield-table tr td.MergeAction select{width:150px}.blog-cms-categorisation .toolbar--content{margin-top:0}.blog-cms-categorisation .MergeActionReveal:after{content:"@";font-family:silverstripe;display:inline-block;position:relative;margin-left:10px;top:3px}.blog-cms-categorisation .blog-merge-action{margin-top:5px}

View File

@ -2,141 +2,141 @@
import jQuery from 'jquery'; import jQuery from 'jquery';
jQuery.entwine('ss', ($) => { jQuery.entwine('ss', ($) => {
/** /**
* The page success/error message sits outside of the html block * The page success/error message sits outside of the html block
* containing the sidebar and cms fields. This means it overflows * containing the sidebar and cms fields. This means it overflows
* underneath the sidebar. * underneath the sidebar.
* *
* @see https://github.com/silverstripe/silverstripe-blog/issues/210 * @see https://github.com/silverstripe/silverstripe-blog/issues/210
*/ */
$('.cms-content-fields > #Form_EditForm_error').entwine({ $('.cms-content-fields > #Form_EditForm_error').entwine({
onadd() { onadd() {
const $target = $('.blog-admin-outer'); const $target = $('.blog-admin-outer');
if ($target.length === 1) { if ($target.length === 1) {
$target.prepend(this); $target.prepend(this);
} }
} }
}); });
/** /**
* Register expandable help text functions with fields. * Register expandable help text functions with fields.
*/ */
$('.toggle-description').entwine({ $('.toggle-description').entwine({
onadd() { onadd() {
const $this = $(this); const $this = $(this);
/** /**
* Prevent multiple events being added. * Prevent multiple events being added.
*/ */
if ($this.hasClass('toggle-description-enabled')) { if ($this.hasClass('toggle-description-enabled')) {
return; return;
} }
$this.addClass('toggle-description-enabled'); $this.addClass('toggle-description-enabled');
/** /**
* Toggle next description when button is clicked. * Toggle next description when button is clicked.
*/ */
let shown = false; let shown = false;
const $helpInfo = $this.closest('.field').find('.form-text'); const $helpInfo = $this.closest('.field').find('.form-text');
$this.on('click', () => { $this.on('click', () => {
$helpInfo[shown ? 'hide' : 'show'](); $helpInfo[shown ? 'hide' : 'show']();
$this.toggleClass('toggle-description-shown'); $this.toggleClass('toggle-description-shown');
shown = !shown; shown = !shown;
}); });
/** /**
* Hide next description by default. * Hide next description by default.
*/ */
$helpInfo.hide(); $helpInfo.hide();
/** /**
* Add classes to correct inherited layout issues in a small context. * Add classes to correct inherited layout issues in a small context.
*/ */
$this.parent().addClass('toggle-description-correct-right'); $this.parent().addClass('toggle-description-correct-right');
$this.parent().prev('.middleColumn').addClass('toggle-description-correct-middle'); $this.parent().prev('.middleColumn').addClass('toggle-description-correct-middle');
$this.parent().next('.description').addClass('toggle-description-correct-description'); $this.parent().next('.description').addClass('toggle-description-correct-description');
} }
}); });
/** /**
* Custom merge actions for tags and categories * Custom merge actions for tags and categories
*/ */
$('.MergeAction').entwine({ $('.MergeAction').entwine({
onadd() { onadd() {
const $this = $(this); const $this = $(this);
$this.on('click', 'select', () => false); $this.on('click', 'select', () => false);
$this.children('button').each((i, button) => { $this.children('button').each((i, button) => {
const $button = $(button); const $button = $(button);
const $select = $button.prev('select'); const $select = $button.prev('select');
$button.before(`<input type="hidden" name="${$button.attr('data-target')}" value="${$select.val()}" />`); $button.before(`<input type="hidden" name="${$button.attr('data-target')}" value="${$select.val()}" />`);
}); });
$this.on('change', 'select', (e) => { $this.on('change', 'select', (e) => {
const $target = $(e.target); const $target = $(e.target);
$target.next('input').val($target.val()); $target.next('input').val($target.val());
}); });
$this.children('button, select').hide(); $this.children('button, select').hide();
$this.on('click', '.MergeActionReveal', (e) => { $this.on('click', '.MergeActionReveal', (e) => {
const $target = $(e.target); const $target = $(e.target);
$target.parent().children('button, select').show(); $target.parent().children('button, select').show();
$target.hide(); $target.hide();
return false; return false;
}); });
} }
}); });
/** /**
* Customise the cms-panel behaviour for blog sidebar * Customise the cms-panel behaviour for blog sidebar
* *
* see LeftAndMain.Panel.js for base behaviour * see LeftAndMain.Panel.js for base behaviour
*/ */
$('.blog-admin-sidebar.cms-panel').entwine({ $('.blog-admin-sidebar.cms-panel').entwine({
MinInnerWidth: 620, MinInnerWidth: 620,
onadd() { onadd() {
this._super(); this._super();
this.updateLayout(); this.updateLayout();
// Contract panel if it's open and the left hand column is smaller than the minimum // Contract panel if it's open and the left hand column is smaller than the minimum
if (!this.hasClass('collapsed') && ($('.blog-admin-outer').width() < this.getMinInnerWidth())) { if (!this.hasClass('collapsed') && ($('.blog-admin-outer').width() < this.getMinInnerWidth())) {
this.collapsePanel(); this.collapsePanel();
} }
const onresize = () => { const onresize = () => {
this.updateLayout(); this.updateLayout();
}; };
onresize.bind(this); onresize.bind(this);
window.onresize = onresize; window.onresize = onresize;
}, },
togglePanel(bool, silent) { togglePanel(bool, silent) {
this._super(bool, silent); this._super(bool, silent);
this.updateLayout(); this.updateLayout();
}, },
/** /**
* Adjust minimum width of content to account for extra panel * Adjust minimum width of content to account for extra panel
* *
* @returns {undefined} * @returns {undefined}
*/ */
updateLayout() { updateLayout() {
$(this).css('height', '100%'); $(this).css('height', '100%');
const currentHeight = $(this).outerHeight(); const currentHeight = $(this).outerHeight();
const bottomHeight = $('.cms-content-actions').eq(0).outerHeight(); const bottomHeight = $('.cms-content-actions').eq(0).outerHeight();
$(this).css('height', `${currentHeight - bottomHeight}px`); $(this).css('height', `${currentHeight - bottomHeight}px`);
$(this).css('bottom', `${bottomHeight}px`); $(this).css('bottom', `${bottomHeight}px`);
$('.cms-container').updateLayoutOptions({ $('.cms-container').updateLayoutOptions({
minContentWidth: 820 + this.width() minContentWidth: 820 + this.width()
}); });
} }
}); });
}); });

View File

@ -1,16 +1,16 @@
import jQuery from 'jquery'; import jQuery from 'jquery';
jQuery.entwine('ss', ($) => { jQuery.entwine('ss', ($) => {
/** /**
* Prevent the CMS hijacking the return key * Prevent the CMS hijacking the return key
*/ */
$('.add-existing-autocompleter input.text').entwine({ $('.add-existing-autocompleter input.text').entwine({
onkeydown(e) { onkeydown(e) {
if (e.which === 13) { if (e.which === 13) {
const $parent = $(this).parents('.add-existing-autocompleter'); const $parent = $(this).parents('.add-existing-autocompleter');
$parent.find('button[type="submit"]').click(); $parent.find('button[type="submit"]').click();
e.preventDefault(); e.preventDefault();
} }
} }
}); });
}); });

View File

@ -142,11 +142,6 @@
.ui-accordion-content .field { .ui-accordion-content .field {
padding: 0; padding: 0;
} }
// Change the caret to a plus icon
.ui-icon-triangle-1-e {
background-position: -16px -128px;
}
} }
.cms table.ss-gridfield-table { .cms table.ss-gridfield-table {

View File

@ -8,19 +8,21 @@
], ],
"type": "silverstripe-vendormodule", "type": "silverstripe-vendormodule",
"require": { "require": {
"php": "^7.4 || ^8.0", "php": "^8.1",
"silverstripe/cms": "^4.0", "silverstripe/cms": "^5",
"silverstripe/lumberjack": "^2.0", "silverstripe/lumberjack": "^3.0",
"silverstripe/tagfield": "^2.0", "silverstripe/tagfield": "^3.0",
"silverstripe/assets": "^1.0", "silverstripe/assets": "^2.0",
"silverstripe/asset-admin": "^1.0" "silverstripe/asset-admin": "^2.0"
}, },
"require-dev": { "require-dev": {
"silverstripe/recipe-testing": "^2", "silverstripe/recipe-testing": "^3",
"squizlabs/php_codesniffer": "^3.0", "squizlabs/php_codesniffer": "^3",
"silverstripe/widgets": "^2", "silverstripe/widgets": "^3",
"silverstripe/comments": "^3.7", "silverstripe/comments": "^4",
"silverstripe/content-widget": "^2" "silverstripe/content-widget": "^3",
"silverstripe/standards": "^1",
"phpstan/extension-installer": "^1.3"
}, },
"extra": { "extra": {
"expose": [ "expose": [

View File

@ -8,7 +8,7 @@ en:
Add: 'Add {name}' Add: 'Add {name}'
AddFail: 'Unable to save {class} to the database.' AddFail: 'Unable to save {class} to the database.'
ButtonName: '{name}' ButtonName: '{name}'
PermissionFail: 'You don''t have permission to create a {class}.' PermissionFail: "You don't have permission to create a {class}."
SilverStripe\Blog\Forms\GridField\GridFieldBlogPostState: SilverStripe\Blog\Forms\GridField\GridFieldBlogPostState:
Draft: 'Saved as Draft on {date}' Draft: 'Saved as Draft on {date}'
Modified: Modified Modified: Modified
@ -47,7 +47,7 @@ en:
PostedIn: 'Posted in' PostedIn: 'Posted in'
PostsByUser: 'Posts by {firstname} {surname} for {title}' PostsByUser: 'Posts by {firstname} {surname} for {title}'
PostsPerPage: 'Posts Per Page' PostsPerPage: 'Posts Per Page'
ReadMoreAbout: 'Read more about ''{title}''...' ReadMoreAbout: "Read more about '{title}'..."
SINGULARNAME: Blog SINGULARNAME: Blog
Tag: Tag Tag: Tag
Tagged: Tagged Tagged: Tagged
@ -85,7 +85,7 @@ en:
SilverStripe\Blog\Model\BlogPost: SilverStripe\Blog\Model\BlogPost:
AUTHOR: Author AUTHOR: Author
AdditionalCredits: 'Additional Credits' AdditionalCredits: 'Additional Credits'
AdditionalCredits_Description: 'If some authors of this post don''t have CMS access, enter their name(s) here. You can separate multiple names with a comma.' AdditionalCredits_Description: "If some authors of this post don't have CMS access, enter their name(s) here. You can separate multiple names with a comma."
Authors: Authors Authors: Authors
CUSTOMSUMMARY: 'Add A Custom Summary' CUSTOMSUMMARY: 'Add A Custom Summary'
Categories: Categories Categories: Categories

View File

@ -1,9 +1,8 @@
{ {
"name": "silverstripe-blog", "name": "silverstripe-blog",
"version": "3.0.0",
"description": "A fresh take on blogging in Silverstripe set out to tackle the issue of a cluttered Site Tree", "description": "A fresh take on blogging in Silverstripe set out to tackle the issue of a cluttered Site Tree",
"scripts": { "scripts": {
"build": "yarn && yarn lint && 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", "dev": "NODE_ENV=development webpack --progress",
"watch": "NODE_ENV=development webpack --watch --progress", "watch": "NODE_ENV=development webpack --watch --progress",
"css": "WEBPACK_CHILD=css npm run build", "css": "WEBPACK_CHILD=css npm run build",
@ -28,11 +27,16 @@
}, },
"homepage": "https://github.com/silverstripe/silverstripe-blog#readme", "homepage": "https://github.com/silverstripe/silverstripe-blog#readme",
"dependencies": {}, "dependencies": {},
"peerDependencies": {
"jquery": "^3"
},
"devDependencies": { "devDependencies": {
"@silverstripe/eslint-config": "^0.0.5", "@silverstripe/eslint-config": "^1.1.0",
"@silverstripe/webpack-config": "^1.3" "@silverstripe/webpack-config": "^2.0.0",
} "webpack": "^5.74.0",
"webpack-cli": "^5.0.0"
},
"resolutions": {
"colors": "1.4.0"
},
"browserslist": [
"defaults"
]
} }

3
phpstan.neon.dist Normal file
View File

@ -0,0 +1,3 @@
parameters:
paths:
- src

View File

@ -226,7 +226,6 @@ class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLP
'add', 'add',
'add' 'add'
); );
$addAction->setAttribute('data-icon', 'add');
$addAction->addExtraClass('btn btn-primary'); $addAction->addExtraClass('btn btn-primary');
$forTemplate = ArrayData::create([]); $forTemplate = ArrayData::create([]);

View File

@ -31,11 +31,11 @@ use SilverStripe\View\Requirements;
/** /**
* Blog Holder * Blog Holder
* *
* @method HasManyList Tags() List of tags in this blog * @method HasManyList<BlogCategory> Categories()
* @method HasManyList Categories() List of categories in this blog * @method ManyManyList<Member> Contributors()
* @method ManyManyList Editors() List of editors * @method ManyManyList<Member> Editors()
* @method ManyManyList Writers() List of writers * @method HasManyList<BlogTag> Tags()
* @method ManyManyList Contributors() List of contributors * @method ManyManyList<Member> Writers()
*/ */
class Blog extends Page implements PermissionProvider class Blog extends Page implements PermissionProvider
{ {
@ -533,7 +533,7 @@ class Blog extends Page implements PermissionProvider
* @param null|int $month * @param null|int $month
* @param null|int $day * @param null|int $day
* *
* @return DataList * @return DataList<BlogPost>
*/ */
public function getArchivedBlogPosts($year, $month = null, $day = null) public function getArchivedBlogPosts($year, $month = null, $day = null)
{ {
@ -574,7 +574,7 @@ class Blog extends Page implements PermissionProvider
/** /**
* Return blog posts. * Return blog posts.
* *
* @return DataList of BlogPost objects * @return DataList<BlogPost> of BlogPost objects
*/ */
public function getBlogPosts() public function getBlogPosts()
{ {

View File

@ -7,12 +7,10 @@ use SilverStripe\ORM\DataObject;
/** /**
* A blog category for generalising blog posts. * A blog category for generalising blog posts.
* *
*
* @method Blog Blog()
*
* @property string $Title * @property string $Title
* @property string $URLSegment * @property string $URLSegment
* @property int $BlogID * @property int $BlogID
* @method Blog Blog()
*/ */
class BlogCategory extends DataObject implements CategorisationObject class BlogCategory extends DataObject implements CategorisationObject
{ {
@ -33,6 +31,8 @@ class BlogCategory extends DataObject implements CategorisationObject
*/ */
private static $table_name = 'BlogCategory'; private static $table_name = 'BlogCategory';
private static bool $allow_urlsegment_multibyte = true;
/** /**
* @var array * @var array
*/ */

View File

@ -2,10 +2,13 @@
namespace SilverStripe\Blog\Model; namespace SilverStripe\Blog\Model;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\ORM\DataExtension; use SilverStripe\ORM\DataExtension;
/** /**
* Adds Blog specific behaviour to Comment. * Adds Blog specific behaviour to Comment.
*
* @extends DataExtension<Comment>
*/ */
class BlogCommentExtension extends DataExtension class BlogCommentExtension extends DataExtension
{ {

View File

@ -11,9 +11,15 @@ use SilverStripe\ORM\DataList;
use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\PaginatedList; use SilverStripe\ORM\PaginatedList;
use SilverStripe\Security\Member; use SilverStripe\Security\Member;
use SilverStripe\Blog\Model\BlogTag;
use SilverStripe\Blog\Model\BlogCategory;
use SilverStripe\View\Parsers\URLSegmentFilter; use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\ORM\SS_List;
/**
* @extends PageController<Blog>
*/
class BlogController extends PageController class BlogController extends PageController
{ {
/** /**
@ -56,7 +62,7 @@ class BlogController extends PageController
/** /**
* The current Blog Post DataList query. * The current Blog Post DataList query.
* *
* @var DataList * @var DataList<BlogPost>
*/ */
protected $blogPosts; protected $blogPosts;
@ -65,9 +71,6 @@ class BlogController extends PageController
*/ */
public function index(HTTPRequest $request) public function index(HTTPRequest $request)
{ {
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord; $dataRecord = $this->dataRecord;
$this->blogPosts = $dataRecord->getBlogPosts(); $this->blogPosts = $dataRecord->getBlogPosts();
@ -126,7 +129,7 @@ class BlogController extends PageController
/** /**
* Get posts related to the current Member profile. * Get posts related to the current Member profile.
* *
* @return null|DataList * @return null|DataList<BlogPost>
*/ */
public function getCurrentProfilePosts() public function getCurrentProfilePosts()
{ {
@ -268,6 +271,7 @@ class BlogController extends PageController
$tag = $this->request->param('Tag'); $tag = $this->request->param('Tag');
if ($tag) { if ($tag) {
$filter = URLSegmentFilter::create(); $filter = URLSegmentFilter::create();
$filter->setAllowMultibyte(BlogTag::config()->get('allow_urlsegment_multibyte'));
// url encode unless it's multibyte (already pre-encoded in the database) // url encode unless it's multibyte (already pre-encoded in the database)
// see https://github.com/silverstripe/silverstripe-cms/pull/2384 // see https://github.com/silverstripe/silverstripe-cms/pull/2384
if (!$filter->getAllowMultibyte()) { if (!$filter->getAllowMultibyte()) {
@ -318,6 +322,7 @@ class BlogController extends PageController
$category = $this->request->param('Category'); $category = $this->request->param('Category');
if ($category) { if ($category) {
$filter = URLSegmentFilter::create(); $filter = URLSegmentFilter::create();
$filter->setAllowMultibyte(BlogCategory::config()->get('allow_urlsegment_multibyte'));
// url encode unless it's multibyte (already pre-encoded in the database) // url encode unless it's multibyte (already pre-encoded in the database)
// see https://github.com/silverstripe/silverstripe-cms/pull/2384 // see https://github.com/silverstripe/silverstripe-cms/pull/2384
if (!$filter->getAllowMultibyte()) { if (!$filter->getAllowMultibyte()) {
@ -439,7 +444,7 @@ class BlogController extends PageController
/** /**
* Returns a list of paginated blog posts based on the BlogPost dataList. * Returns a list of paginated blog posts based on the BlogPost dataList.
* *
* @return PaginatedList * @return PaginatedList<SS_List, BlogPost>
*/ */
public function PaginatedList() public function PaginatedList()
{ {

View File

@ -16,7 +16,6 @@ use SilverStripe\Versioned\Versioned;
/** /**
* This class is responsible for filtering the SiteTree when necessary and also overlaps into * This class is responsible for filtering the SiteTree when necessary and also overlaps into
* filtering only published posts. * filtering only published posts.
*
*/ */
class BlogFilter extends Lumberjack class BlogFilter extends Lumberjack
{ {

View File

@ -10,6 +10,7 @@ use SilverStripe\Forms\GridField\GridFieldAddNewButton;
use SilverStripe\Forms\Tab; use SilverStripe\Forms\Tab;
use SilverStripe\Forms\TextareaField; use SilverStripe\Forms\TextareaField;
use SilverStripe\ORM\DataExtension; use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\ManyManyList;
use SilverStripe\Security\Member; use SilverStripe\Security\Member;
use SilverStripe\View\Parsers\URLSegmentFilter; use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\View\Requirements; use SilverStripe\View\Requirements;
@ -17,6 +18,10 @@ use SilverStripe\View\Requirements;
/** /**
* This class is responsible for add Blog specific behaviour to Members. * This class is responsible for add Blog specific behaviour to Members.
* *
* @method ManyManyList<BlogPost> BlogPosts()
* @method Image BlogProfileImage()
*
* @extends DataExtension<Member>
*/ */
class BlogMemberExtension extends DataExtension class BlogMemberExtension extends DataExtension
{ {

View File

@ -21,7 +21,7 @@ trait BlogObject
{ {
/** /**
* @param int|array|null $id Optional ID(s) for parent of this relation, if not the current record * @param int|array|null $id Optional ID(s) for parent of this relation, if not the current record
* @return DataList * @return DataList<BlogPost>
*/ */
public function BlogPosts($id = null) public function BlogPosts($id = null)
{ {
@ -181,12 +181,7 @@ trait BlogObject
{ {
$increment = (int) $increment; $increment = (int) $increment;
$filter = URLSegmentFilter::create(); $filter = URLSegmentFilter::create();
$filter->setAllowMultibyte($this->config()->get('allow_urlsegment_multibyte') ?? true);
// Setting this to on. Because of the UI flow, it would be quite a lot of work
// to support turning this off. (ie. the add by title flow would not work).
// If this becomes a problem we can approach it then.
// @see https://github.com/silverstripe/silverstripe-blog/issues/376
$filter->setAllowMultibyte(true);
$this->URLSegment = $filter->filter($this->Title); $this->URLSegment = $filter->filter($this->Title);

View File

@ -31,17 +31,15 @@ use SilverStripe\View\Requirements;
/** /**
* An individual blog post. * An individual blog post.
* *
* @method ManyManyList Categories()
* @method ManyManyList Tags()
* @method ManyManyList Authors()
* @method Blog Parent()
* @method Image FeaturedImage()
*
* @property string $PublishDate * @property string $PublishDate
* @property string $AuthorNames * @property string $AuthorNames
* @property string $Summary * @property string $Summary
* @property int $ParentID * @property int $ParentID
* @property int $FeaturedImageID * @property int $FeaturedImageID
* @method ManyManyList<Member> Authors()
* @method ManyManyList<BlogCategory> Categories()
* @method Image FeaturedImage()
* @method ManyManyList<BlogTag> Tags()
*/ */
class BlogPost extends Page class BlogPost extends Page
{ {
@ -334,8 +332,6 @@ class BlogPost extends Page
? $parent->Tags() ? $parent->Tags()
: BlogTag::get(); : BlogTag::get();
// @todo: Reimplement the sidebar
// $options = BlogAdminSidebar::create(
$fields->addFieldsToTab( $fields->addFieldsToTab(
'Root.PostOptions', 'Root.PostOptions',
[ [
@ -360,9 +356,6 @@ class BlogPost extends Page
$authorNames $authorNames
] ]
); );
// )->setTitle('Post Options');
// $options->setName('blog-admin-sidebar');
// $fields->insertBefore($options, 'Root');
$fields->fieldByName('Root.PostOptions') $fields->fieldByName('Root.PostOptions')
->setTitle(_t(__CLASS__ . '.PostOptions', 'Post Options')); ->setTitle(_t(__CLASS__ . '.PostOptions', 'Post Options'));

View File

@ -4,6 +4,9 @@ namespace SilverStripe\Blog\Model;
use PageController; use PageController;
/**
* @extends PageController<BlogPost>
*/
class BlogPostController extends PageController class BlogPostController extends PageController
{ {

View File

@ -8,6 +8,8 @@ use SilverStripe\Forms\CheckboxField;
/** /**
* Adds a checkbox field for featured blog posts widget. * Adds a checkbox field for featured blog posts widget.
*
* @extends DataExtension<BlogPost>
*/ */
class BlogPostFeaturedExtension extends DataExtension class BlogPostFeaturedExtension extends DataExtension
{ {

View File

@ -17,6 +17,7 @@ use SilverStripe\Versioned\Versioned;
* This is responsible for filtering only published posts to users who do not have permission to * This is responsible for filtering only published posts to users who do not have permission to
* view non-published posts. * view non-published posts.
* *
* @extends DataExtension<BlogPost>
*/ */
class BlogPostFilter extends DataExtension class BlogPostFilter extends DataExtension
{ {

View File

@ -12,6 +12,8 @@ use SilverStripe\Security\Member;
* Customise blog post to support comment notifications. * Customise blog post to support comment notifications.
* *
* Extends {@see BlogPost} with extensions to {@see CommentNotifiable}. * Extends {@see BlogPost} with extensions to {@see CommentNotifiable}.
*
* @extends DataExtension<BlogPost>
*/ */
class BlogPostNotifications extends DataExtension class BlogPostNotifications extends DataExtension
{ {

View File

@ -7,17 +7,17 @@ use SilverStripe\ORM\DataObject;
/** /**
* A blog tag for keyword descriptions of a blog post. * A blog tag for keyword descriptions of a blog post.
* *
*
* @method Blog Blog()
*
* @property string $Title * @property string $Title
* @property string $URLSegment * @property string $URLSegment
* @property int $BlogID * @property int $BlogID
* @method Blog Blog()
*/ */
class BlogTag extends DataObject implements CategorisationObject class BlogTag extends DataObject implements CategorisationObject
{ {
use BlogObject; use BlogObject;
private static bool $allow_urlsegment_multibyte = true;
/** /**
* Use an exception code so that attempted writes can continue on * Use an exception code so that attempted writes can continue on
* duplicate errors. * duplicate errors.

View File

@ -108,7 +108,7 @@ class BlogArchiveWidget extends Widget
/** /**
* Returns a list of months where blog posts are present. * Returns a list of months where blog posts are present.
* *
* @return ArrayList * @return ArrayList<ArrayData>
*/ */
public function getArchive() public function getArchive()
{ {

View File

@ -3,6 +3,7 @@
namespace SilverStripe\Blog\Widgets; namespace SilverStripe\Blog\Widgets;
use SilverStripe\Blog\Model\Blog; use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogCategory;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Forms\DropdownField; use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
@ -106,7 +107,7 @@ class BlogCategoriesWidget extends Widget
} }
/** /**
* @return DataList * @return DataList<BlogCategory>
*/ */
public function getCategories() public function getCategories()
{ {

View File

@ -84,7 +84,7 @@ class BlogFeaturedPostsWidget extends Widget
return $blog->getBlogPosts() return $blog->getBlogPosts()
->filter('ID:not', Director::get_current_page()->ID) ->filter('ID:not', Director::get_current_page()->ID)
->filter('FeaturedInWidget', true) ->filter('FeaturedInWidget', true)
->sort('RAND()') ->shuffle()
->limit($this->NumberOfPosts); ->limit($this->NumberOfPosts);
} }

View File

@ -9,6 +9,7 @@ use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\Widgets\Model\Widget; use SilverStripe\Widgets\Model\Widget;
use SilverStripe\Control\Controller;
if (!class_exists(Widget::class)) { if (!class_exists(Widget::class)) {
return; return;
@ -98,7 +99,7 @@ class BlogTagsCloudWidget extends Widget
foreach ($records as $record) { foreach ($records as $record) {
$tag = DataObject::create(); $tag = DataObject::create();
$tag->TagName = $record['Title']; $tag->TagName = $record['Title'];
$link = $bloglink.'tag/'.$record['URLSegment']; $link = Controller::join_links($bloglink, 'tag', $record['URLSegment']);
$tag->Link = $link; $tag->Link = $link;
if ($record['TagCount'] > $maxTagCount) { if ($record['TagCount'] > $maxTagCount) {
$maxTagCount = $record['TagCount']; $maxTagCount = $record['TagCount'];

View File

@ -3,6 +3,7 @@
namespace SilverStripe\Blog\Widgets; namespace SilverStripe\Blog\Widgets;
use SilverStripe\Blog\Model\Blog; use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogTag;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Forms\DropdownField; use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
@ -106,7 +107,7 @@ class BlogTagsWidget extends Widget
} }
/** /**
* @return DataList * @return DataList<BlogTag>
*/ */
public function getTags() public function getTags()
{ {

View File

@ -65,8 +65,8 @@ Feature: Create a blog
# Add categories and tags # Add categories and tags
And I click the "Post Options" CMS tab And I click the "Post Options" CMS tab
And I add "My Category" to the "Categories" tag field And I add "My Category" to the "#Form_EditForm_Categories_Holder" tag field
And I add "My Tag" to the "Tags" tag field And I add "My Tag" to the "#Form_EditForm_Tags_Holder" tag field
# Publish the blog post and logout # Publish the blog post and logout
And I press the "Publish" button And I press the "Publish" button

View File

@ -11,8 +11,6 @@ class BlogFunctionalTest extends FunctionalTest
{ {
protected static $fixture_file = 'BlogFunctionalTest.yml'; protected static $fixture_file = 'BlogFunctionalTest.yml';
protected static $use_draft_site = true;
protected function setUp(): void protected function setUp(): void
{ {
Config::modify()->set(URLSegmentFilter::class, 'default_allow_multibyte', true); Config::modify()->set(URLSegmentFilter::class, 'default_allow_multibyte', true);
@ -23,14 +21,16 @@ class BlogFunctionalTest extends FunctionalTest
public function testBlogWithMultibyteUrl() public function testBlogWithMultibyteUrl()
{ {
$result = $this->get(rawurlencode('آبید')); $this->logInWithPermission('VIEW_DRAFT_CONTENT');
$result = $this->get(rawurlencode('آبید') . '?stage=Stage');
$this->assertEquals(200, $result->getStatusCode()); $this->assertEquals(200, $result->getStatusCode());
} }
public function testMemberProfileWithMultibyteUrlAndName() public function testMemberProfileWithMultibyteUrlAndName()
{ {
$result = $this->get(rawurlencode('آبید') . '/profile/' . rawurlencode('عبّاس-آبان')); $this->logInWithPermission('VIEW_DRAFT_CONTENT');
$result = $this->get(rawurlencode('آبید') . '/profile/' . rawurlencode('عبّاس-آبان') . '?stage=Stage');
$this->assertEquals(200, $result->getStatusCode()); $this->assertEquals(200, $result->getStatusCode());
$this->assertStringContainsString('My Blog Post', $result->getBody()); $this->assertStringContainsString('My Blog Post', $result->getBody());
@ -38,7 +38,8 @@ class BlogFunctionalTest extends FunctionalTest
public function testMemberProfileWithMultibyteUrlAndEnglishName() public function testMemberProfileWithMultibyteUrlAndEnglishName()
{ {
$result = $this->get(rawurlencode('آبید') . '/profile/bob-jones'); $this->logInWithPermission('VIEW_DRAFT_CONTENT');
$result = $this->get(rawurlencode('آبید') . '/profile/bob-jones' . '?stage=Stage');
$this->assertEquals(200, $result->getStatusCode()); $this->assertEquals(200, $result->getStatusCode());
$this->assertStringContainsString('My Blog Post', $result->getBody()); $this->assertStringContainsString('My Blog Post', $result->getBody());

View File

@ -11,8 +11,6 @@ class BlogControllerFunctionalTest extends FunctionalTest
{ {
protected static $fixture_file = 'BlogControllerFunctionalTest.yml'; protected static $fixture_file = 'BlogControllerFunctionalTest.yml';
protected static $use_draft_site = true;
protected function setUp(): void protected function setUp(): void
{ {
Config::modify()->set(URLSegmentFilter::class, 'default_allow_multibyte', true); Config::modify()->set(URLSegmentFilter::class, 'default_allow_multibyte', true);
@ -23,7 +21,8 @@ class BlogControllerFunctionalTest extends FunctionalTest
public function testGetCategoriesWithMultibyteUrl() public function testGetCategoriesWithMultibyteUrl()
{ {
$result = $this->get('my-blog/category/' . rawurlencode('آبید')); $this->logInWithPermission('VIEW_DRAFT_CONTENT');
$result = $this->get('my-blog/category/' . rawurlencode('آبید') . '?stage=Stage');
$this->assertEquals(200, $result->getStatusCode()); $this->assertEquals(200, $result->getStatusCode());
$this->assertStringContainsString('آبید', $result->getBody()); $this->assertStringContainsString('آبید', $result->getBody());
@ -31,7 +30,8 @@ class BlogControllerFunctionalTest extends FunctionalTest
public function testGetTagsWithMultibyteUrl() public function testGetTagsWithMultibyteUrl()
{ {
$result = $this->get('my-blog/tag/' . rawurlencode('برتراند')); $this->logInWithPermission('VIEW_DRAFT_CONTENT');
$result = $this->get('my-blog/tag/' . rawurlencode('برتراند') . '?stage=Stage');
$this->assertEquals(200, $result->getStatusCode()); $this->assertEquals(200, $result->getStatusCode());
$this->assertStringContainsString('برتراند', $result->getBody()); $this->assertStringContainsString('برتراند', $result->getBody());

View File

@ -1,55 +1,31 @@
const Path = require('path'); const Path = require('path');
const webpack = require('webpack'); const { JavascriptWebpackConfig, CssWebpackConfig } = require('@silverstripe/webpack-config');
// Import the core 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 = {
ROOT: Path.resolve(), ROOT: Path.resolve(),
MODULES: 'node_modules',
FILES_PATH: '../',
THIRDPARTY: 'thirdparty',
SRC: Path.resolve('client/src'), SRC: Path.resolve('client/src'),
DIST: Path.resolve('client/dist'), DIST: Path.resolve('client/dist'),
}; };
const config = [ const config = [
{ // Main JS bundle
name: 'bundle', new JavascriptWebpackConfig('js', PATHS, 'silverstripe/blog')
entry: { .setEntry({
main: `${PATHS.SRC}/main.js` main: `${PATHS.SRC}/main.js`
}, })
output: { .mergeConfig({
path: PATHS.DIST, output: {
filename: 'js/[name].bundle.js', filename: 'js/[name].bundle.js',
}, },
devtool: (ENV !== 'production') ? 'source-map' : '', })
resolve: resolveJS(ENV, PATHS), .getConfig(),
externals: externalJS(ENV, PATHS), // sass to css
module: moduleJS(ENV, PATHS), new CssWebpackConfig('css', PATHS)
plugins: pluginJS(ENV, PATHS), .setEntry({
}, main: `${PATHS.SRC}/main.scss`
{ })
name: 'bundle', .getConfig(),
entry: {
main: `${PATHS.SRC}/main.scss`
},
output: {
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;

11067
yarn.lock

File diff suppressed because it is too large Load Diff