This commit is contained in:
2025-08-25 20:24:23 +08:00
parent 30106e0129
commit 0ae8d7a709
1044 changed files with 321581 additions and 0 deletions

View File

@@ -0,0 +1,305 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.2.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.2.0...decap-cms-backend-test@3.2.1) (2025-07-10)
**Note:** Version bump only for package decap-cms-backend-test
# [3.2.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.1.3...decap-cms-backend-test@3.2.0) (2025-06-26)
**Note:** Version bump only for package decap-cms-backend-test
## [3.1.3](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.1.2...decap-cms-backend-test@3.1.3) (2024-08-13)
### Reverts
- Revert "Update dependencies (#7264)" ([22d483a](https://github.com/decaporg/decap-cms/commit/22d483a5b0c654071ae05735ac4f49abdc13d38c)), closes [#7264](https://github.com/decaporg/decap-cms/issues/7264)
## [3.1.2](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.1.1...decap-cms-backend-test@3.1.2) (2024-08-13)
**Note:** Version bump only for package decap-cms-backend-test
## [3.1.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.1.0-beta.1...decap-cms-backend-test@3.1.1) (2024-03-21)
**Note:** Version bump only for package decap-cms-backend-test
# [3.1.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.1.0-beta.1...decap-cms-backend-test@3.1.0) (2024-02-01)
**Note:** Version bump only for package decap-cms-backend-test
# [3.1.0-beta.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.1.0-beta.0...decap-cms-backend-test@3.1.0-beta.1) (2024-01-31)
**Note:** Version bump only for package decap-cms-backend-test
# [3.1.0-beta.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.1.0...decap-cms-backend-test@3.1.0-beta.0) (2023-10-20)
### Reverts
- Revert "chore(release): publish" ([b89fc89](https://github.com/decaporg/decap-cms/commit/b89fc894dfbb5f4136b2e5427fd25a29378a58c6))
## [3.0.2](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.0.1...decap-cms-backend-test@3.0.2) (2023-10-13)
**Note:** Version bump only for package decap-cms-backend-test
## [3.0.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@3.0.0...decap-cms-backend-test@3.0.1) (2023-08-25)
### Bug Fixes
- update peer dependencies ([#6886](https://github.com/decaporg/decap-cms/issues/6886)) ([e580ce5](https://github.com/decaporg/decap-cms/commit/e580ce52ce5f80fa040e8fbcab7fed0744f4f695))
# [3.0.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@2.12.0...decap-cms-backend-test@3.0.0) (2023-08-18)
**Note:** Version bump only for package decap-cms-backend-test
# [2.12.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@2.12.0-beta.0...decap-cms-backend-test@2.12.0) (2023-08-18)
**Note:** Version bump only for package decap-cms-backend-test
# 2.12.0-beta.0 (2023-08-18)
### Features
- rename packages ([#6863](https://github.com/decaporg/decap-cms/issues/6863)) ([d515e7b](https://github.com/decaporg/decap-cms/commit/d515e7bd33216a775d96887b08c4f7b1962941bb))
## [2.11.4-beta.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-test@2.11.3...decap-cms-backend-test@2.11.4-beta.0) (2023-07-27)
**Note:** Version bump only for package decap-cms-backend-test
## [2.11.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.11.2...decap-cms-backend-test@2.11.3) (2021-06-01)
**Note:** Version bump only for package decap-cms-backend-test
## [2.11.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.11.1...decap-cms-backend-test@2.11.2) (2021-05-31)
**Note:** Version bump only for package decap-cms-backend-test
## [2.11.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.11.0...decap-cms-backend-test@2.11.1) (2021-05-19)
**Note:** Version bump only for package decap-cms-backend-test
# [2.11.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.10.7...decap-cms-backend-test@2.11.0) (2021-05-04)
### Features
- added react 17 as peer dependency in packages ([#5316](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/5316)) ([9e42380](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
## [2.10.7](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.10.6...decap-cms-backend-test@2.10.7) (2021-02-23)
**Note:** Version bump only for package decap-cms-backend-test
## [2.10.6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.10.5...decap-cms-backend-test@2.10.6) (2021-02-10)
**Note:** Version bump only for package decap-cms-backend-test
## [2.10.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.10.4...decap-cms-backend-test@2.10.5) (2020-09-20)
**Note:** Version bump only for package decap-cms-backend-test
## [2.10.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.10.3...decap-cms-backend-test@2.10.4) (2020-09-15)
**Note:** Version bump only for package decap-cms-backend-test
## 2.10.3 (2020-09-08)
### Reverts
- Revert "chore(release): publish" ([828bb16](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
## 2.10.2 (2020-08-20)
### Reverts
- Revert "chore(release): publish" ([8262487](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/82624879ccbcb16610090041db28f00714d924c8))
## 2.10.1 (2020-07-27)
### Reverts
- Revert "chore(release): publish" ([118d50a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/118d50a7a70295f25073e564b5161aa2b9883056))
# [2.10.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.9.0...decap-cms-backend-test@2.10.0) (2020-06-18)
### Bug Fixes
- handle token expiry ([#3847](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/3847)) ([285c940](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/285c940562548d7bc88de244123ba87ff66fba65))
### Features
- add backend status down indicator ([#3889](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/3889)) ([a50edc7](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
# [2.9.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.8.1...decap-cms-backend-test@2.9.0) (2020-06-01)
### Features
- add pre save/ post save hooks ([#3812](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/3812)) ([812716e](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/812716e18b09a716547f128b783c8e6f3d54cc5b))
## [2.8.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.8.0...decap-cms-backend-test@2.8.1) (2020-04-01)
**Note:** Version bump only for package decap-cms-backend-test
# [2.8.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.7.3...decap-cms-backend-test@2.8.0) (2020-03-30)
### Features
- add publish configuration option to collections ([#3467](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/3467)) ([df33bc6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/df33bc64a996eedcb10835064a7cab8e7862e94d))
## [2.7.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.7.2...decap-cms-backend-test@2.7.3) (2020-03-03)
### Bug Fixes
- **locale:** Remove hard coded string literals ([#3333](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/3333)) ([7c45a3c](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/7c45a3cda983be427864a56e58791565eb9232e2))
## [2.7.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.7.1...decap-cms-backend-test@2.7.2) (2020-02-06)
### Bug Fixes
- **locale:** remove hard coded strings ([#3193](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/3193)) ([fc91bf8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/fc91bf8781e65ce1dc946363dbb10419a145c66b))
## [2.7.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.7.0...decap-cms-backend-test@2.7.1) (2020-01-14)
**Note:** Version bump only for package decap-cms-backend-test
# [2.7.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.7.0-beta.0...decap-cms-backend-test@2.7.0) (2020-01-07)
**Note:** Version bump only for package decap-cms-backend-test
# [2.7.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.6.0...decap-cms-backend-test@2.7.0-beta.0) (2019-12-18)
### Features
- bundle assets with content ([#2958](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2958)) ([2b41d8a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/2b41d8a838a9c8a6b21cde2ddd16b9288334e298))
# [2.6.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.6.0-beta.0...decap-cms-backend-test@2.6.0) (2019-12-18)
**Note:** Version bump only for package decap-cms-backend-test
# [2.6.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.5.0...decap-cms-backend-test@2.6.0-beta.0) (2019-12-02)
### Bug Fixes
- **backend-test:** delete nested file path ([#2930](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2930)) ([b0fba6d](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/b0fba6dc9ab89784e72d69a71752f68e0255a7e0))
- keep editor slug path ([#2934](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2934)) ([3c4865f](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/3c4865f2a76e6b0f156ab801081251eb620495b2))
### Features
- content in sub folders ([#2897](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2897)) ([afcfe5b](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/afcfe5b6d5f32669e9061ec596bd35ad545d61a3))
# [2.5.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.4.0...decap-cms-backend-test@2.5.0) (2019-11-26)
### Features
- workflow unpublished entry ([#2914](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2914)) ([41bb9aa](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/41bb9aac0dd6fd9f8ff157bb0b29c85aa87fe04d))
# [2.4.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.3.0...decap-cms-backend-test@2.4.0) (2019-11-18)
### Features
- commit media with post ([#2851](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2851)) ([6515dee](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/6515dee8715d8571ea19484a7dfab7cfd0cc40be))
# [2.3.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.2.3...decap-cms-backend-test@2.3.0) (2019-11-07)
### Features
- add go back to site button ([#2538](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2538)) ([f206e7e](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/f206e7e5a13fb48ec6b27dce0dbb3a59b61de8f9))
## [2.2.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.2.2...decap-cms-backend-test@2.2.3) (2019-07-24)
**Note:** Version bump only for package decap-cms-backend-test
## [2.2.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.2.2-beta.0...decap-cms-backend-test@2.2.2) (2019-04-10)
**Note:** Version bump only for package decap-cms-backend-test
## [2.2.2-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.2.1...decap-cms-backend-test@2.2.2-beta.0) (2019-04-05)
**Note:** Version bump only for package decap-cms-backend-test
## [2.2.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.2.1-beta.1...decap-cms-backend-test@2.2.1) (2019-03-29)
**Note:** Version bump only for package decap-cms-backend-test
## [2.2.1-beta.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.2.1-beta.0...decap-cms-backend-test@2.2.1-beta.1) (2019-03-26)
### Bug Fixes
- export on decap-cms and maps on esm ([#2244](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2244)) ([6ffd13b](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/6ffd13b))
## [2.2.1-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.2.0...decap-cms-backend-test@2.2.1-beta.0) (2019-03-25)
### Bug Fixes
- update peer dep versions ([#2234](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2234)) ([7987091](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/7987091))
# [2.2.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.1.0...decap-cms-backend-test@2.2.0) (2019-03-22)
### Features
- add ES module builds ([#2215](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2215)) ([d142b32](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/d142b32))
# [2.1.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.1.0-beta.0...decap-cms-backend-test@2.1.0) (2019-03-22)
**Note:** Version bump only for package decap-cms-backend-test
# [2.1.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.0.7-beta.0...decap-cms-backend-test@2.1.0-beta.0) (2019-03-21)
### Bug Fixes
- fix umd builds ([#2214](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2214)) ([e04f6be](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/e04f6be))
### Features
- provide usable UMD builds for all packages ([#2141](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2141)) ([82cc794](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/82cc794))
## [2.0.7-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.0.6...decap-cms-backend-test@2.0.7-beta.0) (2019-03-15)
### Features
- upgrade to Emotion 10 ([#2166](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/2166)) ([ccef446](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/ccef446))
<a name="2.0.6"></a>
## [2.0.6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.0.5...decap-cms-backend-test@2.0.6) (2018-08-24)
**Note:** Version bump only for package decap-cms-backend-test
<a name="2.0.5"></a>
## [2.0.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.0.4...decap-cms-backend-test@2.0.5) (2018-08-07)
### Bug Fixes
- **backends:** fix commit message handling ([#1568](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/1568)) ([f7e7120](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/f7e7120))
<a name="2.0.4"></a>
## [2.0.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.0.3...decap-cms-backend-test@2.0.4) (2018-08-01)
### Bug Fixes
- **workflow:** enable workflow per method ([#1569](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/1569)) ([90b8156](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/90b8156))
<a name="2.0.3"></a>
## [2.0.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.0.2...decap-cms-backend-test@2.0.3) (2018-08-01)
### Bug Fixes
- **workflow:** fix status not set on new workflow entries ([#1558](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/issues/1558)) ([0aa085f](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/commit/0aa085f))
<a name="2.0.2"></a>
## [2.0.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test/compare/decap-cms-backend-test@2.0.1...decap-cms-backend-test@2.0.2) (2018-07-28)
**Note:** Version bump only for package decap-cms-backend-test
<a name="2.0.1"></a>
## 2.0.1 (2018-07-26)
<a name="2.0.0"></a>
# 2.0.0 (2018-07-26)
**Note:** Version bump only for package decap-cms-backend-test

View File

@@ -0,0 +1,17 @@
# Test backend
The backend behind https://demo.decapcms.org/.
Used for demo purposes only.
## Code structure
`Implementation` for [File Management System API](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-lib-util/README.md) based on simple JS objects:
```js
window.repoFiles // json file-system tree
window.repoFilesUnpublished // flat file list
```
`AuthenticationPage` - A component which allow skip `login screen` for demo purposes.
Look at tests or types for more info.

View File

@@ -0,0 +1,36 @@
{
"name": "decap-cms-backend-test",
"description": "Development testing backend for Decap CMS",
"version": "3.2.1",
"repository": "https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-test",
"bugs": "https://github.com/decaporg/decap-cms/issues",
"license": "MIT",
"module": "dist/esm/index.js",
"main": "dist/decap-cms-backend-test.js",
"keywords": [
"decap-cms",
"backend"
],
"sideEffects": false,
"scripts": {
"develop": "npm run build:esm -- --watch",
"build": "cross-env NODE_ENV=production webpack",
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore \"**/__tests__\" --root-mode upward --extensions \".js,.jsx,.ts,.tsx\""
},
"dependencies": {
"path-browserify": "^1.0.1"
},
"peerDependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"decap-cms-lib-util": "^3.0.0",
"decap-cms-ui-default": "^3.0.0",
"lodash": "^4.17.11",
"prop-types": "^15.7.2",
"react": "^19.1.0",
"uuid": "^8.3.2"
},
"browser": {
"path": "path-browserify"
}
}

View File

@@ -0,0 +1,80 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { Icon, buttons, shadows, GoBackButton } from 'decap-cms-ui-default';
const StyledAuthenticationPage = styled.section`
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: center;
gap: 50px;
height: 100vh;
`;
const PageLogoIcon = styled(Icon)`
height: auto;
`;
const LoginButton = styled.button`
${buttons.button};
${shadows.dropDeep};
${buttons.default};
${buttons.gray};
padding: 0 30px;
margin-top: 0;
display: flex;
align-items: center;
position: relative;
${Icon} {
margin-right: 18px;
}
`;
export default class AuthenticationPage extends React.Component {
static propTypes = {
onLogin: PropTypes.func.isRequired,
inProgress: PropTypes.bool,
config: PropTypes.object.isRequired,
t: PropTypes.func.isRequired,
};
componentDidMount() {
// Manually validate PropTypes - React 19 breaking change
PropTypes.checkPropTypes(
AuthenticationPage.propTypes,
this.props,
'prop',
'AuthenticationPage',
);
/**
* Allow login screen to be skipped for demo purposes.
*/
const skipLogin = this.props.config.backend.login === false;
if (skipLogin) {
this.props.onLogin(this.state);
}
}
handleLogin = e => {
e.preventDefault();
this.props.onLogin(this.state);
};
render() {
const { config, inProgress, t } = this.props;
return (
<StyledAuthenticationPage>
<PageLogoIcon size="300px" type="decap-cms" />
<LoginButton disabled={inProgress} onClick={this.handleLogin}>
{inProgress ? t('auth.loggingIn') : t('auth.login')}
</LoginButton>
{config.site_url && <GoBackButton href={config.site_url} t={t}></GoBackButton>}
</StyledAuthenticationPage>
);
}
}

View File

@@ -0,0 +1,266 @@
import TestBackend, { getFolderFiles } from '../implementation';
describe('test backend implementation', () => {
beforeEach(() => {
jest.resetModules();
});
describe('getEntry', () => {
it('should get entry by path', async () => {
window.repoFiles = {
posts: {
'some-post.md': {
content: 'post content',
},
},
};
const backend = new TestBackend({});
await expect(backend.getEntry('posts/some-post.md')).resolves.toEqual({
file: { path: 'posts/some-post.md', id: null },
data: 'post content',
});
});
it('should get entry by nested path', async () => {
window.repoFiles = {
posts: {
dir1: {
dir2: {
'some-post.md': {
content: 'post content',
},
},
},
},
};
const backend = new TestBackend({});
await expect(backend.getEntry('posts/dir1/dir2/some-post.md')).resolves.toEqual({
file: { path: 'posts/dir1/dir2/some-post.md', id: null },
data: 'post content',
});
});
});
describe('persistEntry', () => {
it('should persist entry', async () => {
window.repoFiles = {};
const backend = new TestBackend({});
const entry = {
dataFiles: [{ path: 'posts/some-post.md', raw: 'content', slug: 'some-post.md' }],
assets: [],
};
await backend.persistEntry(entry, { newEntry: true });
expect(window.repoFiles).toEqual({
posts: {
'some-post.md': {
content: 'content',
path: 'posts/some-post.md',
},
},
});
});
it('should persist entry and keep existing unrelated entries', async () => {
window.repoFiles = {
pages: {
'other-page.md': {
content: 'content',
},
},
posts: {
'other-post.md': {
content: 'content',
},
},
};
const backend = new TestBackend({});
const entry = {
dataFiles: [{ path: 'posts/new-post.md', raw: 'content', slug: 'new-post.md' }],
assets: [],
};
await backend.persistEntry(entry, { newEntry: true });
expect(window.repoFiles).toEqual({
pages: {
'other-page.md': {
content: 'content',
},
},
posts: {
'new-post.md': {
content: 'content',
path: 'posts/new-post.md',
},
'other-post.md': {
content: 'content',
},
},
});
});
it('should persist nested entry', async () => {
window.repoFiles = {};
const backend = new TestBackend({});
const slug = 'dir1/dir2/some-post.md';
const path = `posts/${slug}`;
const entry = { dataFiles: [{ path, raw: 'content', slug }], assets: [] };
await backend.persistEntry(entry, { newEntry: true });
expect(window.repoFiles).toEqual({
posts: {
dir1: {
dir2: {
'some-post.md': {
content: 'content',
path: 'posts/dir1/dir2/some-post.md',
},
},
},
},
});
});
it('should update existing nested entry', async () => {
window.repoFiles = {
posts: {
dir1: {
dir2: {
'some-post.md': {
mediaFiles: ['file1'],
content: 'content',
},
},
},
},
};
const backend = new TestBackend({});
const slug = 'dir1/dir2/some-post.md';
const path = `posts/${slug}`;
const entry = { dataFiles: [{ path, raw: 'new content', slug }], assets: [] };
await backend.persistEntry(entry, { newEntry: false });
expect(window.repoFiles).toEqual({
posts: {
dir1: {
dir2: {
'some-post.md': {
path: 'posts/dir1/dir2/some-post.md',
content: 'new content',
},
},
},
},
});
});
});
describe('deleteFiles', () => {
it('should delete entry by path', async () => {
window.repoFiles = {
posts: {
'some-post.md': {
content: 'post content',
},
},
};
const backend = new TestBackend({});
await backend.deleteFiles(['posts/some-post.md']);
expect(window.repoFiles).toEqual({
posts: {},
});
});
it('should delete entry by nested path', async () => {
window.repoFiles = {
posts: {
dir1: {
dir2: {
'some-post.md': {
content: 'post content',
},
},
},
},
};
const backend = new TestBackend({});
await backend.deleteFiles(['posts/dir1/dir2/some-post.md']);
expect(window.repoFiles).toEqual({
posts: {
dir1: {
dir2: {},
},
},
});
});
});
describe('getFolderFiles', () => {
it('should get files by depth', () => {
const tree = {
pages: {
'root-page.md': {
content: 'root page content',
},
dir1: {
'nested-page-1.md': {
content: 'nested page 1 content',
},
dir2: {
'nested-page-2.md': {
content: 'nested page 2 content',
},
},
},
},
};
expect(getFolderFiles(tree, 'pages', 'md', 1)).toEqual([
{
path: 'pages/root-page.md',
content: 'root page content',
},
]);
expect(getFolderFiles(tree, 'pages', 'md', 2)).toEqual([
{
path: 'pages/dir1/nested-page-1.md',
content: 'nested page 1 content',
},
{
path: 'pages/root-page.md',
content: 'root page content',
},
]);
expect(getFolderFiles(tree, 'pages', 'md', 3)).toEqual([
{
path: 'pages/dir1/dir2/nested-page-2.md',
content: 'nested page 2 content',
},
{
path: 'pages/dir1/nested-page-1.md',
content: 'nested page 1 content',
},
{
path: 'pages/root-page.md',
content: 'root page content',
},
]);
});
});
});

View File

@@ -0,0 +1,434 @@
import attempt from 'lodash/attempt';
import isError from 'lodash/isError';
import take from 'lodash/take';
import unset from 'lodash/unset';
import isEmpty from 'lodash/isEmpty';
import { v4 as uuid } from 'uuid';
import {
EditorialWorkflowError,
Cursor,
CURSOR_COMPATIBILITY_SYMBOL,
basename,
} from 'decap-cms-lib-util';
import { extname, dirname } from 'path';
import AuthenticationPage from './AuthenticationPage';
import type {
Implementation,
Entry,
ImplementationEntry,
AssetProxy,
PersistOptions,
User,
Config,
ImplementationFile,
DataFile,
} from 'decap-cms-lib-util';
type RepoFile = { path: string; content: string | AssetProxy };
type RepoTree = { [key: string]: RepoFile | RepoTree };
type Diff = {
id: string;
originalPath?: string;
path: string;
newFile: boolean;
status: string;
content: string | AssetProxy;
};
type UnpublishedRepoEntry = {
slug: string;
collection: string;
status: string;
diffs: Diff[];
updatedAt: string;
};
declare global {
interface Window {
repoFiles: RepoTree;
repoFilesUnpublished: { [key: string]: UnpublishedRepoEntry };
}
}
window.repoFiles = window.repoFiles || {};
window.repoFilesUnpublished = window.repoFilesUnpublished || [];
function getFile(path: string, tree: RepoTree) {
const segments = path.split('/');
let obj: RepoTree = tree;
while (obj && segments.length) {
obj = obj[segments.shift() as string] as RepoTree;
}
return (obj as unknown as RepoFile) || {};
}
function writeFile(path: string, content: string | AssetProxy, tree: RepoTree) {
const segments = path.split('/');
let obj = tree;
while (segments.length > 1) {
const segment = segments.shift() as string;
obj[segment] = obj[segment] || {};
obj = obj[segment] as RepoTree;
}
(obj[segments.shift() as string] as RepoFile) = { content, path };
}
function deleteFile(path: string, tree: RepoTree) {
unset(tree, path.split('/'));
}
const pageSize = 10;
function getCursor(
folder: string,
extension: string,
entries: ImplementationEntry[],
index: number,
depth: number,
) {
const count = entries.length;
const pageCount = Math.floor(count / pageSize);
return Cursor.create({
actions: [
...(index < pageCount ? ['next', 'last'] : []),
...(index > 0 ? ['prev', 'first'] : []),
],
meta: { index, count, pageSize, pageCount },
data: { folder, extension, index, pageCount, depth },
});
}
export function getFolderFiles(
tree: RepoTree,
folder: string,
extension: string,
depth: number,
files = [] as RepoFile[],
path = folder,
) {
if (depth <= 0) {
return files;
}
Object.keys(tree[folder] || {}).forEach(key => {
if (extname(key)) {
const file = (tree[folder] as RepoTree)[key] as RepoFile;
if (!extension || key.endsWith(`.${extension}`)) {
files.unshift({ content: file.content, path: `${path}/${key}` });
}
} else {
const subTree = tree[folder] as RepoTree;
return getFolderFiles(subTree, key, extension, depth - 1, files, `${path}/${key}`);
}
});
return files;
}
export default class TestBackend implements Implementation {
mediaFolder: string;
options: { initialWorkflowStatus?: string };
constructor(config: Config, options = {}) {
this.options = options;
this.mediaFolder = config.media_folder;
}
isGitBackend() {
return false;
}
status() {
return Promise.resolve({ auth: { status: true }, api: { status: true, statusPage: '' } });
}
authComponent() {
return AuthenticationPage;
}
restoreUser() {
return this.authenticate();
}
authenticate() {
return Promise.resolve() as unknown as Promise<User>;
}
logout() {
return null;
}
getToken() {
return Promise.resolve('');
}
traverseCursor(cursor: Cursor, action: string) {
const { folder, extension, index, pageCount, depth } = cursor.data!.toObject() as {
folder: string;
extension: string;
index: number;
pageCount: number;
depth: number;
};
const newIndex = (() => {
if (action === 'next') {
return (index as number) + 1;
}
if (action === 'prev') {
return (index as number) - 1;
}
if (action === 'first') {
return 0;
}
if (action === 'last') {
return pageCount;
}
return 0;
})();
// TODO: stop assuming cursors are for collections
const allFiles = getFolderFiles(window.repoFiles, folder, extension, depth);
const allEntries = allFiles.map(f => ({
data: f.content as string,
file: { path: f.path, id: f.path },
}));
const entries = allEntries.slice(newIndex * pageSize, newIndex * pageSize + pageSize);
const newCursor = getCursor(folder, extension, allEntries, newIndex, depth);
return Promise.resolve({ entries, cursor: newCursor });
}
entriesByFolder(folder: string, extension: string, depth: number) {
const files = folder ? getFolderFiles(window.repoFiles, folder, extension, depth) : [];
const entries = files.map(f => ({
data: f.content as string,
file: { path: f.path, id: f.path },
}));
const cursor = getCursor(folder, extension, entries, 0, depth);
const ret = take(entries, pageSize);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ret[CURSOR_COMPATIBILITY_SYMBOL] = cursor;
return Promise.resolve(ret);
}
entriesByFiles(files: ImplementationFile[]) {
return Promise.all(
files.map(file => ({
file,
data: getFile(file.path, window.repoFiles).content as string,
})),
);
}
getEntry(path: string) {
return Promise.resolve({
file: { path, id: null },
data: getFile(path, window.repoFiles).content as string,
});
}
unpublishedEntries() {
return Promise.resolve(Object.keys(window.repoFilesUnpublished));
}
unpublishedEntry({ id, collection, slug }: { id?: string; collection?: string; slug?: string }) {
if (id) {
const parts = id.split('/');
collection = parts[0];
slug = parts[1];
}
const entry = window.repoFilesUnpublished[`${collection}/${slug}`];
if (!entry) {
return Promise.reject(
new EditorialWorkflowError('content is not under editorial workflow', true),
);
}
return Promise.resolve(entry);
}
async unpublishedEntryDataFile(collection: string, slug: string, path: string) {
const entry = window.repoFilesUnpublished[`${collection}/${slug}`];
const file = entry.diffs.find(d => d.path === path);
return file?.content as string;
}
async unpublishedEntryMediaFile(collection: string, slug: string, path: string) {
const entry = window.repoFilesUnpublished[`${collection}/${slug}`];
const file = entry.diffs.find(d => d.path === path);
return this.normalizeAsset(file?.content as AssetProxy);
}
deleteUnpublishedEntry(collection: string, slug: string) {
delete window.repoFilesUnpublished[`${collection}/${slug}`];
return Promise.resolve();
}
async addOrUpdateUnpublishedEntry(
key: string,
dataFiles: DataFile[],
assetProxies: AssetProxy[],
slug: string,
collection: string,
status: string,
) {
const diffs: Diff[] = [];
dataFiles.forEach(dataFile => {
const { path, newPath, raw } = dataFile;
const currentDataFile = window.repoFilesUnpublished[key]?.diffs.find(d => d.path === path);
const originalPath = currentDataFile ? currentDataFile.originalPath : path;
diffs.push({
originalPath,
id: newPath || path,
path: newPath || path,
newFile: isEmpty(getFile(originalPath as string, window.repoFiles)),
status: 'added',
content: raw,
});
});
assetProxies.forEach(a => {
const asset = this.normalizeAsset(a);
diffs.push({
id: asset.id,
path: asset.path,
newFile: true,
status: 'added',
content: asset,
});
});
window.repoFilesUnpublished[key] = {
slug,
collection,
status,
diffs,
updatedAt: new Date().toISOString(),
};
}
async persistEntry(entry: Entry, options: PersistOptions) {
if (options.useWorkflow) {
const slug = entry.dataFiles[0].slug;
const key = `${options.collectionName}/${slug}`;
const currentEntry = window.repoFilesUnpublished[key];
const status =
currentEntry?.status || options.status || (this.options.initialWorkflowStatus as string);
this.addOrUpdateUnpublishedEntry(
key,
entry.dataFiles,
entry.assets,
slug,
options.collectionName as string,
status,
);
return Promise.resolve();
}
entry.dataFiles.forEach(dataFile => {
const { path, raw } = dataFile;
writeFile(path, raw, window.repoFiles);
});
entry.assets.forEach(a => {
writeFile(a.path, a, window.repoFiles);
});
return Promise.resolve();
}
updateUnpublishedEntryStatus(collection: string, slug: string, newStatus: string) {
window.repoFilesUnpublished[`${collection}/${slug}`].status = newStatus;
return Promise.resolve();
}
publishUnpublishedEntry(collection: string, slug: string) {
const key = `${collection}/${slug}`;
const unpubEntry = window.repoFilesUnpublished[key];
delete window.repoFilesUnpublished[key];
const tree = window.repoFiles;
unpubEntry.diffs.forEach(d => {
if (d.originalPath && !d.newFile) {
const originalPath = d.originalPath;
const sourceDir = dirname(originalPath);
const destDir = dirname(d.path);
const toMove = getFolderFiles(tree, originalPath.split('/')[0], '', 100).filter(f =>
f.path.startsWith(sourceDir),
);
toMove.forEach(f => {
deleteFile(f.path, tree);
writeFile(f.path.replace(sourceDir, destDir), f.content, tree);
});
}
writeFile(d.path, d.content, tree);
});
return Promise.resolve();
}
getMedia(mediaFolder = this.mediaFolder) {
const files = getFolderFiles(window.repoFiles, mediaFolder.split('/')[0], '', 100).filter(f =>
f.path.startsWith(mediaFolder),
);
const assets = files.map(f => this.normalizeAsset(f.content as AssetProxy));
return Promise.resolve(assets);
}
async getMediaFile(path: string) {
const asset = getFile(path, window.repoFiles).content as AssetProxy;
const url = asset.toString();
const name = basename(path);
const blob = await fetch(url).then(res => res.blob());
const fileObj = new File([blob], name);
return {
id: url,
displayURL: url,
path,
name,
size: fileObj.size,
file: fileObj,
url,
};
}
normalizeAsset(assetProxy: AssetProxy) {
const fileObj = assetProxy.fileObj as File;
const { name, size } = fileObj;
const objectUrl = attempt(window.URL.createObjectURL, fileObj);
const url = isError(objectUrl) ? '' : objectUrl;
const normalizedAsset = {
id: uuid(),
name,
size,
path: assetProxy.path,
url,
displayURL: url,
fileObj,
};
return normalizedAsset;
}
persistMedia(assetProxy: AssetProxy) {
const normalizedAsset = this.normalizeAsset(assetProxy);
writeFile(assetProxy.path, assetProxy, window.repoFiles);
return Promise.resolve(normalizedAsset);
}
deleteFiles(paths: string[]) {
paths.forEach(path => {
deleteFile(path, window.repoFiles);
});
return Promise.resolve();
}
async getDeployPreview() {
return null;
}
}

View File

@@ -0,0 +1,8 @@
import TestBackend from './implementation';
import AuthenticationPage from './AuthenticationPage';
export const DecapCmsBackendTest = {
TestBackend,
AuthenticationPage,
};
export { TestBackend, AuthenticationPage };

View File

@@ -0,0 +1,3 @@
const { getConfig } = require('../../scripts/webpack.js');
module.exports = getConfig();