Feature/single package (#1)

This commit is contained in:
Daniel Lautzenheiser
2022-09-28 20:04:00 -06:00
committed by GitHub
parent 5963227066
commit 0b64464611
1110 changed files with 7842 additions and 257596 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,47 +0,0 @@
# Netlify CMS App
_For a Netlify CMS overview, see the general [Netlify CMS project README](https://github.com/netlify/netlify-cms)._
## Community Chat
<a href="https://netlifycms.org/chat">
<img alt="Join us on Slack" src="https://raw.githubusercontent.com/netlify/netlify-cms/master/website/static/img/slack.png" width="165">
</a>
## Purpose
This package is similar to the [`netlify-cms`](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms/) package, but is designed for use with extensions. It serves that purpose in the following ways.
- It does not automatically initialize - you must run the CMS `init` method.
- It does not include `react` or `react-dom` - they are required as peer dependencies.
- It does not include the following extensions:
- [`netlify-cms-media-library-cloudinary`]
- [`netlify-cms-media-library-uploadcare`]
## Usage
Install via script tag:
```html
<!-- Excluding `doctype` and `head` but you should add them -->
<body>
<!-- Add these scripts to the bottom of the body -->
<script src="https://unpkg.com/react@^16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@^16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/netlify-cms-app/dist/netlify-cms-app.js"></script>
<!-- Initialize the CMS -->
<script>
NetlifyCmsApp.init();
</script>
</body>
```
Install via npm:
```
npm i react react-dom netlify-cms-app
```
```js
import CMS from 'netlify-cms-app';
CMS.init();
```

View File

@ -1,7 +0,0 @@
declare module 'netlify-cms-app' {
import type { CMS } from 'netlify-cms-core';
export const NetlifyCmsApp: CMS;
export default NetlifyCmsApp;
}

View File

@ -1,75 +0,0 @@
{
"name": "netlify-cms-app",
"description": "An extensible, open source, Git-based, React CMS for static sites. Reusable congiuration with React as peer.",
"version": "2.15.108",
"homepage": "https://www.netlifycms.org",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-app",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"main": "dist/netlify-cms-app.js",
"files": [
"src/",
"dist/",
"index.d.ts"
],
"types": "index.d.ts",
"scripts": {
"develop": "yarn build:esm --watch",
"webpack": "node --max_old_space_size=4096 ../../node_modules/webpack/bin/webpack.js",
"build": "cross-env NODE_ENV=production run-s webpack",
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore \"**/__tests__\" --root-mode upward"
},
"keywords": [
"netlify",
"cms",
"content editing",
"static site generators",
"jamstack"
],
"license": "MIT",
"dependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"codemirror": "^5.46.0",
"immutable": "^3.7.6",
"lodash": "^4.17.11",
"moment": "^2.24.0",
"netlify-cms-backend-azure": "^1.3.3",
"netlify-cms-backend-bitbucket": "^2.14.2",
"netlify-cms-backend-git-gateway": "^2.13.4",
"netlify-cms-backend-github": "^2.14.3",
"netlify-cms-backend-gitlab": "^2.13.2",
"netlify-cms-backend-proxy": "^1.2.5",
"netlify-cms-backend-test": "^2.11.5",
"netlify-cms-core": "^2.55.36",
"netlify-cms-editor-component-image": "^2.7.0",
"netlify-cms-lib-auth": "^2.4.2",
"netlify-cms-lib-util": "^2.15.3",
"netlify-cms-lib-widgets": "^1.8.1",
"netlify-cms-locales": "^1.39.0",
"netlify-cms-ui-default": "^2.15.21",
"netlify-cms-widget-boolean": "^2.4.3",
"netlify-cms-widget-code": "^1.3.6",
"netlify-cms-widget-colorstring": "^1.1.4",
"netlify-cms-widget-date": "^2.6.5",
"netlify-cms-widget-datetime": "^2.7.6",
"netlify-cms-widget-file": "^2.12.5",
"netlify-cms-widget-image": "^2.8.3",
"netlify-cms-widget-list": "^2.10.3",
"netlify-cms-widget-map": "^1.5.3",
"netlify-cms-widget-markdown": "^2.15.3",
"netlify-cms-widget-number": "^2.5.0",
"netlify-cms-widget-object": "^2.7.4",
"netlify-cms-widget-relation": "^2.11.3",
"netlify-cms-widget-select": "^2.8.2",
"netlify-cms-widget-string": "^2.3.0",
"netlify-cms-widget-text": "^2.4.1",
"prop-types": "^15.7.2",
"react-immutable-proptypes": "^2.1.0",
"uuid": "^3.3.2"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0"
},
"incrementToForceBump": 2
}

View File

@ -1,74 +0,0 @@
import React from 'react';
// Core
import { NetlifyCmsCore as CMS } from 'netlify-cms-core';
// Backends
import { AzureBackend } from 'netlify-cms-backend-azure';
import { GitHubBackend } from 'netlify-cms-backend-github';
import { GitLabBackend } from 'netlify-cms-backend-gitlab';
import { GitGatewayBackend } from 'netlify-cms-backend-git-gateway';
import { BitbucketBackend } from 'netlify-cms-backend-bitbucket';
import { TestBackend } from 'netlify-cms-backend-test';
import { ProxyBackend } from 'netlify-cms-backend-proxy';
// Widgets
import NetlifyCmsWidgetString from 'netlify-cms-widget-string';
import NetlifyCmsWidgetNumber from 'netlify-cms-widget-number';
import NetlifyCmsWidgetText from 'netlify-cms-widget-text';
import NetlifyCmsWidgetImage from 'netlify-cms-widget-image';
import NetlifyCmsWidgetFile from 'netlify-cms-widget-file';
import NetlifyCmsWidgetSelect from 'netlify-cms-widget-select';
import NetlifyCmsWidgetMarkdown from 'netlify-cms-widget-markdown';
import NetlifyCmsWidgetList from 'netlify-cms-widget-list';
import NetlifyCmsWidgetObject from 'netlify-cms-widget-object';
import NetlifyCmsWidgetRelation from 'netlify-cms-widget-relation';
import NetlifyCmsWidgetBoolean from 'netlify-cms-widget-boolean';
import NetlifyCmsWidgetMap from 'netlify-cms-widget-map';
import NetlifyCmsWidgetDate from 'netlify-cms-widget-date';
import NetlifyCmsWidgetDatetime from 'netlify-cms-widget-datetime';
import NetlifyCmsWidgetCode from 'netlify-cms-widget-code';
import NetlifyCmsWidgetColorString from 'netlify-cms-widget-colorstring';
// Editor Components
import image from 'netlify-cms-editor-component-image';
// Locales
import * as locales from 'netlify-cms-locales';
import { images, Icon } from 'netlify-cms-ui-default';
// Register all the things
CMS.registerBackend('git-gateway', GitGatewayBackend);
CMS.registerBackend('azure', AzureBackend);
CMS.registerBackend('github', GitHubBackend);
CMS.registerBackend('gitlab', GitLabBackend);
CMS.registerBackend('bitbucket', BitbucketBackend);
CMS.registerBackend('test-repo', TestBackend);
CMS.registerBackend('proxy', ProxyBackend);
CMS.registerWidget([
NetlifyCmsWidgetString.Widget(),
NetlifyCmsWidgetNumber.Widget(),
NetlifyCmsWidgetText.Widget(),
NetlifyCmsWidgetImage.Widget(),
NetlifyCmsWidgetFile.Widget(),
NetlifyCmsWidgetSelect.Widget(),
NetlifyCmsWidgetMarkdown.Widget(),
NetlifyCmsWidgetList.Widget(),
NetlifyCmsWidgetObject.Widget(),
NetlifyCmsWidgetRelation.Widget(),
NetlifyCmsWidgetBoolean.Widget(),
NetlifyCmsWidgetMap.Widget(),
NetlifyCmsWidgetDate.Widget(),
NetlifyCmsWidgetDatetime.Widget(),
NetlifyCmsWidgetCode.Widget(),
NetlifyCmsWidgetColorString.Widget(),
]);
CMS.registerEditorComponent(image);
CMS.registerEditorComponent({
id: 'code-block',
label: 'Code Block',
widget: 'code',
type: 'code-block',
});
Object.keys(locales).forEach(locale => {
CMS.registerLocale(locale, locales[locale]);
});
Object.keys(images).forEach(iconName => {
CMS.registerIcon(iconName, <Icon type={iconName} />);
});

View File

@ -1,16 +0,0 @@
import { NetlifyCmsCore as CMS } from 'netlify-cms-core';
import moment from 'moment';
import './extensions.js';
// Log version
if (typeof window !== 'undefined') {
if (typeof NETLIFY_CMS_APP_VERSION === 'string') {
console.log(`netlify-cms-app ${NETLIFY_CMS_APP_VERSION}`);
}
}
export const NetlifyCmsApp = {
...CMS,
moment,
};
export default CMS;

View File

@ -1,4 +0,0 @@
import { NetlifyCmsCore as CMS } from 'netlify-cms-core';
import { en } from 'netlify-cms-locales';
CMS.registerLocale('en', en);

View File

@ -1,22 +0,0 @@
const webpack = require('webpack');
const pkg = require('./package.json');
const { getConfig, plugins } = require('../../scripts/webpack');
const baseWebpackConfig = getConfig({ baseOnly: true });
const isProduction = process.env.NODE_ENV === 'production';
console.log(`${pkg.version}${isProduction ? '' : '-dev'}`);
const baseConfig = {
...baseWebpackConfig,
plugins: [
...Object.entries(plugins)
.filter(([key]) => key !== 'friendlyErrors')
.map(([, plugin]) => plugin()),
new webpack.DefinePlugin({
NETLIFY_CMS_APP_VERSION: JSON.stringify(`${pkg.version}${isProduction ? '' : '-dev'}`),
}),
],
};
module.exports = baseConfig;

View File

@ -1,89 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.3](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-azure@1.3.2...netlify-cms-backend-azure@1.3.3) (2022-09-22)
**Note:** Version bump only for package netlify-cms-backend-azure
## [1.3.2](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-azure@1.3.1...netlify-cms-backend-azure@1.3.2) (2022-09-21)
**Note:** Version bump only for package netlify-cms-backend-azure
## [1.3.1](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-azure@1.3.0...netlify-cms-backend-azure@1.3.1) (2022-04-13)
**Note:** Version bump only for package netlify-cms-backend-azure
# [1.3.0](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-azure@1.2.2...netlify-cms-backend-azure@1.3.0) (2021-10-18)
### Features
* display author of changes in workflow tab ([#5780](https://github.com/netlify/netlify-cms/issues/5780)) ([3f607e4](https://github.com/netlify/netlify-cms/commit/3f607e41d9c4d8fe5329a9ab6841cada7742825e))
## [1.2.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/compare/netlify-cms-backend-azure@1.2.1...netlify-cms-backend-azure@1.2.2) (2021-06-01)
**Note:** Version bump only for package netlify-cms-backend-azure
## [1.2.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/compare/netlify-cms-backend-azure@1.2.0...netlify-cms-backend-azure@1.2.1) (2021-05-31)
**Note:** Version bump only for package netlify-cms-backend-azure
# [1.2.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/compare/netlify-cms-backend-azure@1.1.2...netlify-cms-backend-azure@1.2.0) (2021-05-04)
### Features
* added react 17 as peer dependency in packages ([#5316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/issues/5316)) ([9e42380](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
## [1.1.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/compare/netlify-cms-backend-azure@1.1.1...netlify-cms-backend-azure@1.1.2) (2021-02-23)
**Note:** Version bump only for package netlify-cms-backend-azure
## [1.1.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/compare/netlify-cms-backend-azure@1.1.0...netlify-cms-backend-azure@1.1.1) (2021-02-10)
**Note:** Version bump only for package netlify-cms-backend-azure
# 1.1.0 (2020-11-26)
### Features
* add azure devops backend ([#4427](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/issues/4427)) ([4e6dc88](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure/commit/4e6dc88efb1dae4cf6137730c3b4fb6d0f75a8cc))

View File

@ -1,13 +0,0 @@
# Azure backend
An abstraction layer between the CMS and [Azure DevOps](https://docs.microsoft.com/en-us/rest/api/azure/devops/git/)
## Code structure
`Implementation` for [File Management System API](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-util/README.md) based on `Api`.
`Api` - A wrapper for Azure DevOps REST API.
`AuthenticationPage` - facilitates implicit authentication flow. Uses [lib-auth](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-auth/README.md).
Look at tests or types for more info.

View File

@ -1,38 +0,0 @@
{
"name": "netlify-cms-backend-azure",
"description": "Azure DevOps backend for Netlify CMS",
"version": "1.3.3",
"license": "MIT",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-azure",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"module": "dist/esm/index.js",
"main": "dist/netlify-cms-backend-azure.js",
"keywords": [
"netlify",
"netlify-cms",
"backend",
"azure",
"devops"
],
"sideEffects": false,
"scripts": {
"develop": "yarn 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": {
"js-base64": "^3.0.0",
"semaphore": "^1.1.0"
},
"peerDependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"immutable": "^3.7.6",
"lodash": "^4.17.11",
"netlify-cms-lib-auth": "^2.3.0",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0"
}
}

View File

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

View File

@ -1,570 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.14.2](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-bitbucket@2.14.1...netlify-cms-backend-bitbucket@2.14.2) (2022-09-22)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.14.1](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-bitbucket@2.14.0...netlify-cms-backend-bitbucket@2.14.1) (2022-09-21)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
# [2.14.0](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-bitbucket@2.13.3...netlify-cms-backend-bitbucket@2.14.0) (2021-10-18)
### Features
* display author of changes in workflow tab ([#5780](https://github.com/netlify/netlify-cms/issues/5780)) ([3f607e4](https://github.com/netlify/netlify-cms/commit/3f607e41d9c4d8fe5329a9ab6841cada7742825e))
## [2.13.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.13.2...netlify-cms-backend-bitbucket@2.13.3) (2021-06-01)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.13.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.13.1...netlify-cms-backend-bitbucket@2.13.2) (2021-05-31)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.13.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.13.0...netlify-cms-backend-bitbucket@2.13.1) (2021-05-19)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
# [2.13.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.12.8...netlify-cms-backend-bitbucket@2.13.0) (2021-05-04)
### Features
* added react 17 as peer dependency in packages ([#5316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/5316)) ([9e42380](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
## [2.12.8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.12.7...netlify-cms-backend-bitbucket@2.12.8) (2021-02-23)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.12.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.12.6...netlify-cms-backend-bitbucket@2.12.7) (2021-02-15)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.12.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.12.5...netlify-cms-backend-bitbucket@2.12.6) (2021-02-10)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.12.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.12.4...netlify-cms-backend-bitbucket@2.12.5) (2020-09-20)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.12.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.12.3...netlify-cms-backend-bitbucket@2.12.4) (2020-09-15)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## 2.12.3 (2020-09-08)
### Reverts
* Revert "chore(release): publish" ([828bb16](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
## 2.12.2 (2020-08-20)
### Reverts
* Revert "chore(release): publish" ([8262487](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/82624879ccbcb16610090041db28f00714d924c8))
## 2.12.1 (2020-07-27)
### Reverts
* Revert "chore(release): publish" ([118d50a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/118d50a7a70295f25073e564b5161aa2b9883056))
# [2.12.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.11.5...netlify-cms-backend-bitbucket@2.12.0) (2020-06-18)
### Bug Fixes
* handle token expiry ([#3847](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3847)) ([285c940](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/285c940562548d7bc88de244123ba87ff66fba65))
### Features
* add backend status down indicator ([#3889](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3889)) ([a50edc7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
* **backend-gitgateway:** improve deploy preview visibility ([#3882](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3882)) ([afc9bf4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/afc9bf4f3fe14ccb60851fc24e68922a6e4a85a9))
## [2.11.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.11.4...netlify-cms-backend-bitbucket@2.11.5) (2020-05-19)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.11.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.11.3...netlify-cms-backend-bitbucket@2.11.4) (2020-04-21)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.11.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.11.2...netlify-cms-backend-bitbucket@2.11.3) (2020-04-01)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.11.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.11.1...netlify-cms-backend-bitbucket@2.11.2) (2020-03-20)
### Bug Fixes
* missing workflow timestamp ([#3445](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3445)) ([9616cdb](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/9616cdb8bb0a564771e5755bcd3718a07f2e2072))
## [2.11.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.11.0...netlify-cms-backend-bitbucket@2.11.1) (2020-03-03)
### Bug Fixes
* **locale:** Remove hard coded string literals ([#3333](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3333)) ([7c45a3c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/7c45a3cda983be427864a56e58791565eb9232e2))
# [2.11.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.10.1...netlify-cms-backend-bitbucket@2.11.0) (2020-02-25)
### Features
* **core:** align GitHub metadata handling with other backends ([#3316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3316)) ([7e0a8ad](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/7e0a8ad532012576dc5e40bd4e9d54522e307123)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3292)
## [2.10.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.10.0...netlify-cms-backend-bitbucket@2.10.1) (2020-02-22)
### Reverts
* Revert "feat(core): Align GitHub metadata handling with other backends (#3292)" ([5bdd3df](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/5bdd3df9ccbb5149c22d79987ebdcd6cab4b261f)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3292)
# [2.10.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.9.0...netlify-cms-backend-bitbucket@2.10.0) (2020-02-22)
### Features
* **core:** Align GitHub metadata handling with other backends ([#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3292)) ([8193b5a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/8193b5ace89d6f14a6c756235a50b186a763b6b1))
# [2.9.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.8.1...netlify-cms-backend-bitbucket@2.9.0) (2020-02-10)
### Bug Fixes
* filter paginated results ([#3216](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3216)) ([0a482b1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/0a482b10049bcfa022b81165cabf4512d77e0b88))
* workflow file collection ([#3207](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3207)) ([d22f7e6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/d22f7e680e7064e8607cf8b420571fa40a6c314e))
### Features
* field based media/public folders ([#3208](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3208)) ([97bc0c8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/97bc0c8dc489e736f89d748ba832d78400fe4332))
### Reverts
* Revert "chore(release): publish" ([a015d1d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/a015d1d92a4b1c0130c44fcef1c9ecdb157a0f07))
## [2.8.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.8.0...netlify-cms-backend-bitbucket@2.8.1) (2020-02-06)
### Bug Fixes
* **locale:** remove hard coded strings ([#3193](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3193)) ([fc91bf8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/fc91bf8781e65ce1dc946363dbb10419a145c66b))
# [2.8.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.7.2...netlify-cms-backend-bitbucket@2.8.0) (2020-01-21)
### Features
* **backend-bitbucket:** Add Git-LFS support ([#3118](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3118)) ([a48c02d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/a48c02d852ca5e11055da3a14cefae8d17a68498))
## [2.7.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.7.1...netlify-cms-backend-bitbucket@2.7.2) (2020-01-14)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.7.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.7.0...netlify-cms-backend-bitbucket@2.7.1) (2020-01-09)
### Bug Fixes
* **backend-bitbucket:** fix media library not loaded on BitBucket ([#3059](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/3059)) ([8849c0e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/8849c0ea5777ee0eb85375d6e4a74d7f956c77ee))
# [2.7.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.7.0-beta.0...netlify-cms-backend-bitbucket@2.7.0) (2020-01-07)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
# [2.7.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.6.0...netlify-cms-backend-bitbucket@2.7.0-beta.0) (2019-12-18)
### Features
* bundle assets with content ([#2958](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2958)) ([2b41d8a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/2b41d8a838a9c8a6b21cde2ddd16b9288334e298))
# [2.6.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.6.0-beta.1...netlify-cms-backend-bitbucket@2.6.0) (2019-12-18)
### Bug Fixes
* **backend-bitbucket:** 404 for new entry ([#2976](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2976)) ([20851fe](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/20851fe7eae0487484e775c9cb219d1aa973e878))
# [2.6.0-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.6.0-beta.0...netlify-cms-backend-bitbucket@2.6.0-beta.1) (2019-12-16)
### Bug Fixes
* **bitbucket:** branchname containing slash ([#2963](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2963)) ([afea448](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/afea44895b9ef7379f5a8726a60fb4d371c76ebf))
# [2.6.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.5.0...netlify-cms-backend-bitbucket@2.6.0-beta.0) (2019-12-02)
### Features
* content in sub folders ([#2897](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2897)) ([afcfe5b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/afcfe5b6d5f32669e9061ec596bd35ad545d61a3))
# [2.5.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.4.2...netlify-cms-backend-bitbucket@2.5.0) (2019-11-07)
### Features
* add go back to site button ([#2538](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2538)) ([f206e7e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/f206e7e5a13fb48ec6b27dce0dbb3a59b61de8f9))
* enable specifying custom open authoring commit message ([#2810](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2810)) ([2841ff9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/2841ff9ffe58afcf4dba45514a84a262ad370f1d))
## [2.4.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.4.1...netlify-cms-backend-bitbucket@2.4.2) (2019-09-26)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.4.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.4.0...netlify-cms-backend-bitbucket@2.4.1) (2019-07-24)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
# [2.4.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.4.0-beta.0...netlify-cms-backend-bitbucket@2.4.0) (2019-04-10)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
# [2.4.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.3.1...netlify-cms-backend-bitbucket@2.4.0-beta.0) (2019-04-05)
### Features
* **backend-bitbucket:** add implicit auth ([#2247](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2247)) ([54fde06](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/54fde06))
## [2.3.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.3.1-beta.1...netlify-cms-backend-bitbucket@2.3.1) (2019-03-29)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.3.1-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.3.1-beta.0...netlify-cms-backend-bitbucket@2.3.1-beta.1) (2019-03-26)
### Bug Fixes
* export on netlify-cms and maps on esm ([#2244](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2244)) ([6ffd13b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/6ffd13b))
## [2.3.1-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.3.0...netlify-cms-backend-bitbucket@2.3.1-beta.0) (2019-03-25)
### Bug Fixes
* update peer dep versions ([#2234](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2234)) ([7987091](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/7987091))
# [2.3.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.2.0...netlify-cms-backend-bitbucket@2.3.0) (2019-03-22)
### Features
* add ES module builds ([#2215](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2215)) ([d142b32](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/d142b32))
# [2.2.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.2.0-beta.0...netlify-cms-backend-bitbucket@2.2.0) (2019-03-22)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
# [2.2.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.1.3-beta.0...netlify-cms-backend-bitbucket@2.2.0-beta.0) (2019-03-21)
### Bug Fixes
* fix umd builds ([#2214](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2214)) ([e04f6be](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/e04f6be))
### Features
* provide usable UMD builds for all packages ([#2141](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2141)) ([82cc794](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/82cc794))
## [2.1.3-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.1.2...netlify-cms-backend-bitbucket@2.1.3-beta.0) (2019-03-15)
### Features
* upgrade to Emotion 10 ([#2166](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/2166)) ([ccef446](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/ccef446))
## [2.1.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.1.1...netlify-cms-backend-bitbucket@2.1.2) (2019-03-08)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
## [2.1.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.1.0...netlify-cms-backend-bitbucket@2.1.1) (2019-02-26)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
# [2.1.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.0.7...netlify-cms-backend-bitbucket@2.1.0) (2018-11-12)
### Features
* allow custom logo on auth page ([#1818](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/1818)) ([c6ae1e8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/c6ae1e8))
<a name="2.0.7"></a>
## [2.0.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.0.6...netlify-cms-backend-bitbucket@2.0.7) (2018-09-06)
### Bug Fixes
* **bitbucket:** setting site_id for BitBucket auth ([#1660](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/1660)) ([d139ac4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/d139ac4))
<a name="2.0.6"></a>
## [2.0.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.0.5...netlify-cms-backend-bitbucket@2.0.6) (2018-08-27)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
<a name="2.0.5"></a>
## [2.0.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.0.4...netlify-cms-backend-bitbucket@2.0.5) (2018-08-24)
### Bug Fixes
* **gitlab:** fetch media library images through API ([#1433](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/1433)) ([83d2adc](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/83d2adc))
<a name="2.0.4"></a>
## [2.0.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.0.3...netlify-cms-backend-bitbucket@2.0.4) (2018-08-07)
### Bug Fixes
* **backends:** fix commit message handling ([#1568](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/issues/1568)) ([f7e7120](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/commit/f7e7120))
<a name="2.0.3"></a>
## [2.0.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.0.2...netlify-cms-backend-bitbucket@2.0.3) (2018-08-01)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
<a name="2.0.2"></a>
## [2.0.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket/compare/netlify-cms-backend-bitbucket@2.0.1...netlify-cms-backend-bitbucket@2.0.2) (2018-07-28)
**Note:** Version bump only for package netlify-cms-backend-bitbucket
<a name="2.0.1"></a>
## 2.0.1 (2018-07-26)
<a name="2.0.0"></a>
# 2.0.0 (2018-07-26)
### Bug Fixes
* **bitbucket:** fix rebasing mistakes in bitbucket backend and deps ([#1522](https://github.com/netlify/netlify-cms/issues/1522)) ([bdfd944](https://github.com/netlify/netlify-cms/commit/bdfd944))

View File

@ -1,13 +0,0 @@
# Bitbucket backend
An abstraction layer between the CMS and [Bitbucket](https://docs.microsoft.com/en-us/rest/api/azure/devops/git/)
## Code structure
`Implementation` for [File Management System API](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-util/README.md) based on `Api` and `LargeMedia(LFS)`. With [Editorial Workflow](https://www.netlifycms.org/docs/beta-features/#gitlab-and-bitbucket-editorial-workflow-support) uses pull requests comments to track unpublished entries statuses.
`Api` - A wrapper for Bitbucket REST API.
`AuthenticationPage` - uses [lib-auth](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-auth/README.md) to facilitate OAuth and implicit authentication.
Look at tests or types for more info.

View File

@ -1,39 +0,0 @@
{
"name": "netlify-cms-backend-bitbucket",
"description": "Bitbucket backend for Netlify CMS",
"version": "2.14.2",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbucket",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"module": "dist/esm/index.js",
"main": "dist/netlify-cms-backend-bitbucket.js",
"license": "MIT",
"keywords": [
"netlify",
"netlify-cms",
"backend",
"bitbucket"
],
"sideEffects": false,
"scripts": {
"develop": "yarn 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": {
"common-tags": "^1.8.0",
"js-base64": "^3.0.0",
"semaphore": "^1.1.0",
"what-the-diff": "^0.6.0"
},
"peerDependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"immutable": "^3.7.6",
"lodash": "^4.17.11",
"netlify-cms-lib-auth": "^2.3.0",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0"
}
}

View File

@ -1,35 +0,0 @@
import API from '../API';
global.fetch = jest.fn().mockRejectedValue(new Error('should not call fetch inside tests'));
describe('bitbucket API', () => {
beforeEach(() => {
jest.resetAllMocks();
});
test('should get preview statuses', async () => {
const api = new API({});
const pr = { id: 1 };
const statuses = [
{ key: 'deploy', state: 'SUCCESSFUL', url: 'deploy-url' },
{ key: 'build', state: 'FAILED' },
];
api.getBranchPullRequest = jest.fn(() => Promise.resolve(pr));
api.getPullRequestStatuses = jest.fn(() => Promise.resolve(statuses));
const collectionName = 'posts';
const slug = 'title';
await expect(api.getStatuses(collectionName, slug)).resolves.toEqual([
{ context: 'deploy', state: 'success', target_url: 'deploy-url' },
{ context: 'build', state: 'other' },
]);
expect(api.getBranchPullRequest).toHaveBeenCalledTimes(1);
expect(api.getBranchPullRequest).toHaveBeenCalledWith(`cms/posts/title`);
expect(api.getPullRequestStatuses).toHaveBeenCalledTimes(1);
expect(api.getPullRequestStatuses).toHaveBeenCalledWith(pr);
});
});

View File

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

View File

@ -1,725 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.13.4](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-git-gateway@2.13.3...netlify-cms-backend-git-gateway@2.13.4) (2022-09-22)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.13.3](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-git-gateway@2.13.2...netlify-cms-backend-git-gateway@2.13.3) (2022-09-21)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.13.2](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-git-gateway@2.13.1...netlify-cms-backend-git-gateway@2.13.2) (2022-09-20)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.13.1](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-git-gateway@2.13.0...netlify-cms-backend-git-gateway@2.13.1) (2022-03-08)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
# [2.13.0](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-git-gateway@2.12.2...netlify-cms-backend-git-gateway@2.13.0) (2021-12-28)
### Bug Fixes
* **netlify-cms-ui-default:** use grayDark for button ([#6069](https://github.com/netlify/netlify-cms/issues/6069)) ([ad85514](https://github.com/netlify/netlify-cms/commit/ad85514cba607f066ab7071bee5932b2192466ee)), closes [/github.com/netlify/netlify-cms/issues/1333#issuecomment-998115794](https://github.com//github.com/netlify/netlify-cms/issues/1333/issues/issuecomment-998115794)
### Features
* **backend-gitlab:** initial GraphQL support ([#6059](https://github.com/netlify/netlify-cms/issues/6059)) ([1523a41](https://github.com/netlify/netlify-cms/commit/1523a4140a3d2f4cc01a1548514ae17bc1ad504e))
* disable 'Save' button when there are no changes ([#5595](https://github.com/netlify/netlify-cms/issues/5595)) ([4b566a7](https://github.com/netlify/netlify-cms/commit/4b566a78f4282a6f04caf3deafaaac4d74acfd63))
## [2.12.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.12.1...netlify-cms-backend-git-gateway@2.12.2) (2021-06-01)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.12.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.12.0...netlify-cms-backend-git-gateway@2.12.1) (2021-05-31)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
# [2.12.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.11...netlify-cms-backend-git-gateway@2.12.0) (2021-05-04)
### Features
* added react 17 as peer dependency in packages ([#5316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/5316)) ([9e42380](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
## [2.11.11](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.10...netlify-cms-backend-git-gateway@2.11.11) (2021-02-25)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.11.10](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.9...netlify-cms-backend-git-gateway@2.11.10) (2021-02-23)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.11.9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.8...netlify-cms-backend-git-gateway@2.11.9) (2021-02-10)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.11.8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.7...netlify-cms-backend-git-gateway@2.11.8) (2020-12-15)
### Bug Fixes
* **deps:** update dependency ini to v2 ([#4722](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/4722)) ([e14ace3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/e14ace373b11510159a9b4d3f977d27ed886b288))
## [2.11.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.6...netlify-cms-backend-git-gateway@2.11.7) (2020-12-06)
### Bug Fixes
* **large-media:** mark pointer files as binary ([#4678](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/4678)) ([7697b90](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/7697b907d7bae750f4ec041a184188aa46995320))
## [2.11.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.5...netlify-cms-backend-git-gateway@2.11.6) (2020-10-12)
### Bug Fixes
* **deps:** update dependency jwt-decode to v3 ([#4408](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/4408)) ([03492e4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/03492e4e684ffce3a541ef15edb591d1fd5b5854))
## [2.11.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.4...netlify-cms-backend-git-gateway@2.11.5) (2020-09-20)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.11.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.11.3...netlify-cms-backend-git-gateway@2.11.4) (2020-09-15)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## 2.11.3 (2020-09-08)
### Reverts
* Revert "chore(release): publish" ([828bb16](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
## 2.11.2 (2020-08-20)
### Reverts
* Revert "chore(release): publish" ([8262487](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/82624879ccbcb16610090041db28f00714d924c8))
## 2.11.1 (2020-07-27)
### Reverts
* Revert "chore(release): publish" ([118d50a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/118d50a7a70295f25073e564b5161aa2b9883056))
# [2.11.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.10.5...netlify-cms-backend-git-gateway@2.11.0) (2020-06-18)
### Bug Fixes
* handle token expiry ([#3847](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3847)) ([285c940](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/285c940562548d7bc88de244123ba87ff66fba65))
### Features
* add backend status down indicator ([#3889](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3889)) ([a50edc7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
* **backend-gitgateway:** improve deploy preview visibility ([#3882](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3882)) ([afc9bf4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/afc9bf4f3fe14ccb60851fc24e68922a6e4a85a9))
## [2.10.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.10.4...netlify-cms-backend-git-gateway@2.10.5) (2020-05-19)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.10.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.10.3...netlify-cms-backend-git-gateway@2.10.4) (2020-05-04)
### Bug Fixes
* **git-gateway:** wait for identity widget to initialize ([#3660](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3660)) ([6c229c5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/6c229c5149e3beff05bcfb42ca286d3e9170e54e))
## [2.10.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.10.2...netlify-cms-backend-git-gateway@2.10.3) (2020-04-21)
### Bug Fixes
* **large-media:** match netlify.app as lfs host ([#3642](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3642)) ([9b79623](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/9b79623bc8b8fe212fb2d15dec8a75328cde9c64))
## [2.10.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.10.1...netlify-cms-backend-git-gateway@2.10.2) (2020-04-01)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.10.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.10.0...netlify-cms-backend-git-gateway@2.10.1) (2020-03-30)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
# [2.10.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.9.1...netlify-cms-backend-git-gateway@2.10.0) (2020-03-12)
### Features
* add media lib virtualization ([#3381](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3381)) ([92e7601](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/92e76011e7a9e8b5370088b0a2c065df66b5f7fb))
* **backend-github:** add pagination ([#3379](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3379)) ([39f1307](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/39f1307e3a36447da8c9b3ca79b1d7db52ea1a19))
## [2.9.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.9.0...netlify-cms-backend-git-gateway@2.9.1) (2020-03-03)
### Bug Fixes
* **locale:** Remove hard coded string literals ([#3333](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3333)) ([7c45a3c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/7c45a3cda983be427864a56e58791565eb9232e2))
# [2.9.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.8.1...netlify-cms-backend-git-gateway@2.9.0) (2020-02-25)
### Features
* **core:** align GitHub metadata handling with other backends ([#3316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3316)) ([7e0a8ad](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/7e0a8ad532012576dc5e40bd4e9d54522e307123)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3292)
## [2.8.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.8.0...netlify-cms-backend-git-gateway@2.8.1) (2020-02-22)
### Reverts
* Revert "feat(core): Align GitHub metadata handling with other backends (#3292)" ([5bdd3df](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/5bdd3df9ccbb5149c22d79987ebdcd6cab4b261f)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3292)
# [2.8.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.7.2...netlify-cms-backend-git-gateway@2.8.0) (2020-02-22)
### Features
* **core:** Align GitHub metadata handling with other backends ([#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3292)) ([8193b5a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/8193b5ace89d6f14a6c756235a50b186a763b6b1))
## [2.7.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.7.1...netlify-cms-backend-git-gateway@2.7.2) (2020-02-11)
### Bug Fixes
* stringify error message ([#3233](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3233)) ([249bd7e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/249bd7ec1ed2197106cbb01f8c05e1b8830aa5bc))
## [2.7.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.7.0...netlify-cms-backend-git-gateway@2.7.1) (2020-01-24)
### Bug Fixes
* **backend-git-gateway:** re-write GitHub pagination links ([#3135](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3135)) ([834f6b9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/834f6b9e457f3738ce0f240ddd4cc160aff9e2f5))
# [2.7.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.6.2...netlify-cms-backend-git-gateway@2.7.0) (2020-01-21)
### Bug Fixes
* **git-gateway-gitlab:** fix large media support for editorial workflow ([#3105](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3105)) ([038803c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/038803c9f249de386812652372c35c4c53935295))
### Features
* **backend-bitbucket:** Add Git-LFS support ([#3118](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3118)) ([a48c02d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/a48c02d852ca5e11055da3a14cefae8d17a68498))
## [2.6.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.6.1...netlify-cms-backend-git-gateway@2.6.2) (2020-01-16)
### Bug Fixes
* don't fail on malformed pointer files ([#3095](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3095)) ([9210843](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/92108431f0c3df3e99b5aa7f462006ec3fa7777e))
## [2.6.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.6.0...netlify-cms-backend-git-gateway@2.6.1) (2020-01-14)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
# [2.6.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.6.0-beta.0...netlify-cms-backend-git-gateway@2.6.0) (2020-01-07)
### Bug Fixes
* rebase open authoring branches ([#2975](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2975)) ([8c175f6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/8c175f6132fa18a13763cc563f7d3201c1e3580e))
### Features
* **backend-git-gateway:** handle identity disabled error message ([#3002](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/3002)) ([b5ffccd](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/b5ffccdac506db416c09aaebb38611783487c52a))
# [2.6.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.5.1...netlify-cms-backend-git-gateway@2.6.0-beta.0) (2019-12-18)
### Features
* bundle assets with content ([#2958](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2958)) ([2b41d8a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/2b41d8a838a9c8a6b21cde2ddd16b9288334e298))
## [2.5.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.5.0...netlify-cms-backend-git-gateway@2.5.1) (2019-11-18)
### Bug Fixes
* **git-gateway:** unpublished entries not loaded for git-gateway(GitHub) ([#2856](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2856)) ([4a2328b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/4a2328b2f10ea678184391e4caf235b41323cd3e))
# [2.5.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.6...netlify-cms-backend-git-gateway@2.5.0) (2019-11-07)
### Bug Fixes
* **backend-git-gateway:** omit /repos/ when no repo ([#2846](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2846)) ([da2dab3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/da2dab305ab7f0655791ef0fb5376e3d5e72897c))
### Features
* add go back to site button ([#2538](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2538)) ([f206e7e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/f206e7e5a13fb48ec6b27dce0dbb3a59b61de8f9))
* enable specifying custom open authoring commit message ([#2810](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2810)) ([2841ff9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/2841ff9ffe58afcf4dba45514a84a262ad370f1d))
## [2.4.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.5...netlify-cms-backend-git-gateway@2.4.6) (2019-09-26)
### Bug Fixes
* **git-gateway:** pass api URL instead of constructing it from repo value ([#2631](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2631)) ([922c0f3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/922c0f3))
## [2.4.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.4...netlify-cms-backend-git-gateway@2.4.5) (2019-07-24)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.4.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.3...netlify-cms-backend-git-gateway@2.4.4) (2019-06-26)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.4.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.2...netlify-cms-backend-git-gateway@2.4.3) (2019-06-18)
### Bug Fixes
* **core:** address new entries error for non-github backends ([#2390](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2390)) ([a5bd6b3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/a5bd6b3))
## [2.4.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.2-beta.0...netlify-cms-backend-git-gateway@2.4.2) (2019-04-10)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.4.2-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.1...netlify-cms-backend-git-gateway@2.4.2-beta.0) (2019-04-05)
### Bug Fixes
* **backend-git-gateway:** fix image display w/o large media ([#2271](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2271)) ([6c3506b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/6c3506b))
## [2.4.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.1-beta.1...netlify-cms-backend-git-gateway@2.4.1) (2019-03-29)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.4.1-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.1-beta.0...netlify-cms-backend-git-gateway@2.4.1-beta.1) (2019-03-26)
### Bug Fixes
* export on netlify-cms and maps on esm ([#2244](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2244)) ([6ffd13b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/6ffd13b))
## [2.4.1-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.4.0...netlify-cms-backend-git-gateway@2.4.1-beta.0) (2019-03-25)
### Bug Fixes
* update peer dep versions ([#2234](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2234)) ([7987091](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/7987091))
# [2.4.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.3.1-beta.0...netlify-cms-backend-git-gateway@2.4.0) (2019-03-22)
### Features
* add ES module builds ([#2215](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2215)) ([d142b32](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/d142b32))
## [2.3.1-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.3.0...netlify-cms-backend-git-gateway@2.3.1-beta.0) (2019-03-22)
### Bug Fixes
* **editorial-workflow:** fix LM pointers changing to binary files ([#2228](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2228)) ([d39a361](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/d39a361))
# [2.3.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.3.0-beta.0...netlify-cms-backend-git-gateway@2.3.0) (2019-03-22)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
# [2.3.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.2.5-beta.0...netlify-cms-backend-git-gateway@2.3.0-beta.0) (2019-03-21)
### Bug Fixes
* fix umd builds ([#2214](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2214)) ([e04f6be](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/e04f6be))
### Features
* provide usable UMD builds for all packages ([#2141](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2141)) ([82cc794](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/82cc794))
## [2.2.5-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.2.4...netlify-cms-backend-git-gateway@2.2.5-beta.0) (2019-03-15)
### Features
* upgrade to Emotion 10 ([#2166](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2166)) ([ccef446](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/ccef446))
## [2.2.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.2.3...netlify-cms-backend-git-gateway@2.2.4) (2019-03-11)
### Bug Fixes
* **backend-github:** make non-Large Media previews work with Git Gateway+Github ([#2151](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2151)) ([63582dc](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/63582dc))
## [2.2.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.2.2...netlify-cms-backend-git-gateway@2.2.3) (2019-03-08)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
## [2.2.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.2.1...netlify-cms-backend-git-gateway@2.2.2) (2019-02-28)
### Bug Fixes
* **git-gateway:** fix previews for GitHub images not in Large Media ([#2125](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2125)) ([d17f896](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/d17f896))
## [2.2.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.2.0...netlify-cms-backend-git-gateway@2.2.1) (2019-02-26)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
# [2.2.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.1.2...netlify-cms-backend-git-gateway@2.2.0) (2019-02-08)
### Features
* **workflow:** add deploy preview links ([#2028](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/2028)) ([15d221d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/15d221d))
## [2.1.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.1.1...netlify-cms-backend-git-gateway@2.1.2) (2018-12-11)
### Bug Fixes
* **netlify-cms-backend-git-gateway:** content-type may have charset ([#1951](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/1951)) ([c74dbae](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/c74dbae))
## [2.1.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.1.0...netlify-cms-backend-git-gateway@2.1.1) (2018-11-29)
### Bug Fixes
* **backend-git-gateway:** double slashes when gateway_url contained a backend ([#1712](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/1712)) ([6de47cd](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/6de47cd))
# [2.1.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.0.8...netlify-cms-backend-git-gateway@2.1.0) (2018-11-12)
### Bug Fixes
* **identity:** switch user name reference to full_name ([#1809](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/1809)) ([55d45a8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/55d45a8))
### Features
* allow custom logo on auth page ([#1818](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/1818)) ([c6ae1e8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/c6ae1e8))
<a name="2.0.8"></a>
## [2.0.8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.0.7...netlify-cms-backend-git-gateway@2.0.8) (2018-09-06)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
<a name="2.0.7"></a>
## [2.0.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.0.6...netlify-cms-backend-git-gateway@2.0.7) (2018-08-27)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
<a name="2.0.6"></a>
## [2.0.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.0.5...netlify-cms-backend-git-gateway@2.0.6) (2018-08-24)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
<a name="2.0.5"></a>
## [2.0.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.0.4...netlify-cms-backend-git-gateway@2.0.5) (2018-08-07)
### Bug Fixes
* **workflow:** fix workflow entries not appearing ([#1581](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/1581)) ([95c8de0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/95c8de0))
<a name="2.0.4"></a>
## [2.0.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.0.3...netlify-cms-backend-git-gateway@2.0.4) (2018-08-01)
**Note:** Version bump only for package netlify-cms-backend-git-gateway
<a name="2.0.3"></a>
## [2.0.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/compare/netlify-cms-backend-git-gateway@2.0.2...netlify-cms-backend-git-gateway@2.0.3) (2018-07-28)
### Bug Fixes
* **git-gateway:** correct `proxied` value for proxied backends ([#1540](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/issues/1540)) ([f7dba87](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway/commit/f7dba87))
<a name="2.0.2"></a>
## 2.0.2 (2018-07-27)
### Bug Fixes
* **git-gateway:** pass options through git-gateway backend ([#1532](https://github.com/netlify/netlify-cms/issues/1532)) ([4c5436a](https://github.com/netlify/netlify-cms/commit/4c5436a))
<a name="2.0.1"></a>
## 2.0.1 (2018-07-26)
<a name="2.0.0"></a>
# 2.0.0 (2018-07-26)
### Bug Fixes
* **bitbucket:** fix rebasing mistakes in bitbucket backend and deps ([#1522](https://github.com/netlify/netlify-cms/issues/1522)) ([bdfd944](https://github.com/netlify/netlify-cms/commit/bdfd944))

View File

@ -1,26 +0,0 @@
# Git Gateway
Netlify's [gateway](https://github.com/netlify/git-gateway) to hosted git APIs.
## Code structure
`Implementation` for [File Management System API](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-util/README.md) based on `Api`.
`Api` and `Implementation` from backend-[github](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/README.md)/[gitlab](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/README.md)/[bitbacket](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-bitbacket/README.md) extended with Netlify-specific `LargeMedia(LFS)` and `JWT` auth.
`AuthenticationPage` - uses [lib-auth](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-auth/README.md) and implements Netlify Identity authentication flow.
Look at tests or types for more info.
## Debugging
When debugging the CMS with Git Gateway you must:
1. Have a Netlify site with [Git Gateway](https://docs.netlify.com/visitor-access/git-gateway/) and [Netlify Identity](https://docs.netlify.com/visitor-access/identity/) enabled. An easy way to create such a site is to use a [template](https://www.netlifycms.org/docs/start-with-a-template/), for example the [Gatsby template](https://app.netlify.com/start/deploy?repository=https://github.com/AustinGreen/gatsby-starter-netlify-cms&stack=cms)
2. Tell the CMS the URL of your Netlify site using a local storage item. To do so:
1. Open `http://localhost:8080/` in the browser
2. Write the below command and press enter: `localStorage.setItem('netlifySiteURL', 'https://yourwebsiteurl.netlify.app/')`
3. To be sure, you can run this command as well: `localStorage.getItem('netlifySiteURL')`
4. Refresh the page
5. You should be able to log in via your Netlify Identity email/password

View File

@ -1,42 +0,0 @@
{
"name": "netlify-cms-backend-git-gateway",
"description": "Git Gateway backend for Netlify CMS",
"version": "2.13.4",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-git-gateway",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"module": "dist/esm/index.js",
"main": "dist/netlify-cms-backend-git-gateway.js",
"license": "MIT",
"keywords": [
"netlify",
"netlify-cms",
"backend",
"git-gateway",
"gateway"
],
"sideEffects": false,
"scripts": {
"develop": "yarn 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": {
"gotrue-js": "^0.9.24",
"ini": "^2.0.0",
"jwt-decode": "^3.0.0",
"minimatch": "^3.0.4"
},
"peerDependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"lodash": "^4.17.11",
"netlify-cms-backend-bitbucket": "^2.12.8",
"netlify-cms-backend-github": "^2.11.9",
"netlify-cms-backend-gitlab": "^2.9.9",
"netlify-cms-lib-auth": "^2.3.0",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0"
}
}

View File

@ -1,41 +0,0 @@
import React from 'react';
import { render } from '@testing-library/react';
window.netlifyIdentity = {
currentUser: jest.fn(),
on: jest.fn(),
close: jest.fn(),
};
describe('GitGatewayAuthenticationPage', () => {
const props = {
config: { logo_url: 'logo_url' },
t: jest.fn(key => key),
onLogin: jest.fn(),
inProgress: false,
};
beforeEach(() => {
jest.clearAllMocks();
jest.resetModules();
});
it('should render with identity error', () => {
const { default: GitGatewayAuthenticationPage } = require('../AuthenticationPage');
const { asFragment } = render(<GitGatewayAuthenticationPage {...props} />);
const errorCallback = window.netlifyIdentity.on.mock.calls.find(call => call[0] === 'error')[1];
errorCallback(
new Error('Failed to load settings from https://site.netlify.com/.netlify/identity'),
);
expect(asFragment()).toMatchSnapshot();
});
it('should render with no identity error', () => {
const { default: GitGatewayAuthenticationPage } = require('../AuthenticationPage');
const { asFragment } = render(<GitGatewayAuthenticationPage {...props} />);
expect(asFragment()).toMatchSnapshot();
});
});

View File

@ -1,97 +0,0 @@
import API from '../GitHubAPI';
describe('github API', () => {
describe('request', () => {
beforeEach(() => {
const fetch = jest.fn();
global.fetch = fetch;
});
afterEach(() => {
jest.resetAllMocks();
});
it('should fetch url with authorization header', async () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
tokenPromise: () => Promise.resolve('token'),
});
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue('some response'),
ok: true,
status: 200,
headers: { get: () => '' },
});
const result = await api.request('/some-path');
expect(result).toEqual('some response');
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('https://site.netlify.com/.netlify/git/github/some-path', {
cache: 'no-cache',
headers: {
Authorization: 'Bearer token',
'Content-Type': 'application/json; charset=utf-8',
},
signal: expect.any(AbortSignal),
});
});
it('should throw error on not ok response with message property', async () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
tokenPromise: () => Promise.resolve('token'),
});
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue({ message: 'some error' }),
ok: false,
status: 404,
headers: { get: () => '' },
});
await expect(api.request('some-path')).rejects.toThrow(
expect.objectContaining({
message: 'some error',
name: 'API_ERROR',
status: 404,
api: 'Git Gateway',
}),
);
});
it('should throw error on not ok response with msg property', async () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
tokenPromise: () => Promise.resolve('token'),
});
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue({ msg: 'some error' }),
ok: false,
status: 404,
headers: { get: () => '' },
});
await expect(api.request('some-path')).rejects.toThrow(
expect.objectContaining({
message: 'some error',
name: 'API_ERROR',
status: 404,
api: 'Git Gateway',
}),
);
});
});
describe('nextUrlProcessor', () => {
it('should re-write github url', () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
});
expect(api.nextUrlProcessor()('https://api.github.com/repositories/10000/pulls')).toEqual(
'https://site.netlify.com/.netlify/git/github/pulls',
);
});
});
});

View File

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

View File

@ -1,814 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.14.3](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-github@2.14.2...netlify-cms-backend-github@2.14.3) (2022-09-22)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.14.2](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-github@2.14.1...netlify-cms-backend-github@2.14.2) (2022-09-21)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.14.1](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-github@2.14.0...netlify-cms-backend-github@2.14.1) (2022-04-13)
**Note:** Version bump only for package netlify-cms-backend-github
# [2.14.0](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-github@2.13.5...netlify-cms-backend-github@2.14.0) (2021-10-18)
### Features
* display author of changes in workflow tab ([#5780](https://github.com/netlify/netlify-cms/issues/5780)) ([3f607e4](https://github.com/netlify/netlify-cms/commit/3f607e41d9c4d8fe5329a9ab6841cada7742825e))
## [2.13.5](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-github@2.13.4...netlify-cms-backend-github@2.13.5) (2021-10-15)
### Bug Fixes
* remove "Don't fork the repo"-Button - fixes [#5723](https://github.com/netlify/netlify-cms/issues/5723) ([#5872](https://github.com/netlify/netlify-cms/issues/5872)) ([05d8923](https://github.com/netlify/netlify-cms/commit/05d89230dca315ddcc734b1dc6223df1d8dc1ede))
## [2.13.4](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-github@2.13.3...netlify-cms-backend-github@2.13.4) (2021-07-20)
### Bug Fixes
* add updated_at to graphql query ([#5611](https://github.com/netlify/netlify-cms/issues/5611)) ([8989550](https://github.com/netlify/netlify-cms/commit/89895508b2ccc8f07019abb6bc2d0162c0d86266))
## [2.13.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.13.2...netlify-cms-backend-github@2.13.3) (2021-06-01)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.13.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.13.1...netlify-cms-backend-github@2.13.2) (2021-05-31)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.13.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.13.0...netlify-cms-backend-github@2.13.1) (2021-05-19)
**Note:** Version bump only for package netlify-cms-backend-github
# [2.13.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.12.0...netlify-cms-backend-github@2.13.0) (2021-05-04)
### Features
* added react 17 as peer dependency in packages ([#5316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/5316)) ([9e42380](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
# [2.12.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.11.9...netlify-cms-backend-github@2.12.0) (2021-04-04)
### Features
* **open-authoring:** add alwaysFork option ([#5204](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/5204)) ([7b19e30](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/7b19e30dd2a310dbc20ccb6fcca45d5cbde1014b))
## [2.11.9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.11.8...netlify-cms-backend-github@2.11.9) (2021-02-23)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.11.8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.11.7...netlify-cms-backend-github@2.11.8) (2021-02-10)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.11.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.11.6...netlify-cms-backend-github@2.11.7) (2020-12-06)
### Bug Fixes
* **large-media:** mark pointer files as binary ([#4678](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/4678)) ([7697b90](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/7697b907d7bae750f4ec041a184188aa46995320))
## [2.11.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.11.5...netlify-cms-backend-github@2.11.6) (2020-09-20)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.11.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.11.4...netlify-cms-backend-github@2.11.5) (2020-09-15)
**Note:** Version bump only for package netlify-cms-backend-github
## 2.11.4 (2020-09-08)
### Reverts
* Revert "chore(release): publish" ([828bb16](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
## 2.11.3 (2020-08-20)
### Reverts
* Revert "chore(release): publish" ([8262487](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/82624879ccbcb16610090041db28f00714d924c8))
## 2.11.2 (2020-07-27)
### Reverts
* Revert "chore(release): publish" ([118d50a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/118d50a7a70295f25073e564b5161aa2b9883056))
## [2.11.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.11.0...netlify-cms-backend-github@2.11.1) (2020-07-14)
### Bug Fixes
* **backend-github:** use workflow branch when listing files to move ([#4019](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/4019)) ([8720a42](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/8720a4233db16d91d6b86ee8653d05f8953cb430))
# [2.11.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.10.6...netlify-cms-backend-github@2.11.0) (2020-06-18)
### Bug Fixes
* handle token expiry ([#3847](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3847)) ([285c940](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/285c940562548d7bc88de244123ba87ff66fba65))
### Features
* add backend status down indicator ([#3889](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3889)) ([a50edc7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
* **backend-gitgateway:** improve deploy preview visibility ([#3882](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3882)) ([afc9bf4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/afc9bf4f3fe14ccb60851fc24e68922a6e4a85a9))
## [2.10.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.10.5...netlify-cms-backend-github@2.10.6) (2020-05-19)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.10.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.10.4...netlify-cms-backend-github@2.10.5) (2020-04-21)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.10.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.10.3...netlify-cms-backend-github@2.10.4) (2020-04-07)
### Bug Fixes
* **backend-github:** add fallback for diff errors/warnings ([#3558](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3558)) ([1705c79](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/1705c79a9297d844d5421d685a7785e1e210e39e))
## [2.10.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.10.2...netlify-cms-backend-github@2.10.3) (2020-04-01)
### Bug Fixes
* **open-authoring:** properly delete open authoring branches ([#3512](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3512)) ([cc89aa5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/cc89aa5c430a6bee51483cda91d0f92e7437f29e))
## [2.10.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.10.1...netlify-cms-backend-github@2.10.2) (2020-04-01)
### Bug Fixes
* **open-authoring:** prevent workflow view from breaking on entry error ([#3508](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3508)) ([cbb3927](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/cbb39271012fc3beecfdf180e573e343ee48fe26))
## [2.10.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.10.0...netlify-cms-backend-github@2.10.1) (2020-03-20)
### Bug Fixes
* missing workflow timestamp ([#3445](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3445)) ([9616cdb](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/9616cdb8bb0a564771e5755bcd3718a07f2e2072))
# [2.10.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.9.3...netlify-cms-backend-github@2.10.0) (2020-03-12)
### Bug Fixes
* **backend-github:** don't create new commits on empty diff when rebasing ([#3411](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3411)) ([70de9f6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/70de9f6b4b89dd8e23205929033745572562e8fc))
* update repo owner from GitHub API to match casing ([#3410](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3410)) ([c2e7a24](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/c2e7a24dc20dfea5b1289c5705095d2cf8b04c54))
### Features
* **backend-github:** add pagination ([#3379](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3379)) ([39f1307](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/39f1307e3a36447da8c9b3ca79b1d7db52ea1a19))
## [2.9.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.9.2...netlify-cms-backend-github@2.9.3) (2020-03-03)
### Bug Fixes
* **locale:** Remove hard coded string literals ([#3333](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3333)) ([7c45a3c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/7c45a3cda983be427864a56e58791565eb9232e2))
* **open-authoring:** use origin repo when calling compare API ([#3363](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3363)) ([e40b81a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/e40b81a5647d45487d6ddf17245beddd354e0f39))
## [2.9.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.9.1...netlify-cms-backend-github@2.9.2) (2020-02-27)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.9.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.9.0...netlify-cms-backend-github@2.9.1) (2020-02-25)
### Bug Fixes
* **backend-github:** fail workflow migrations gracefully ([#3325](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3325)) ([83e0383](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/83e0383b690fb452ea40cb165a56f65a695dc83c))
# [2.9.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.8.1...netlify-cms-backend-github@2.9.0) (2020-02-25)
### Bug Fixes
* **backend-github:** improve workflow migration edge cases/messaging ([#3319](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3319)) ([684b79e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/684b79e43bebb63ce1e844eae5c8c0e76087687b))
### Features
* **core:** align GitHub metadata handling with other backends ([#3316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3316)) ([7e0a8ad](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/7e0a8ad532012576dc5e40bd4e9d54522e307123)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3292)
## [2.8.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.8.0...netlify-cms-backend-github@2.8.1) (2020-02-22)
### Reverts
* Revert "feat(core): Align GitHub metadata handling with other backends (#3292)" ([5bdd3df](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/5bdd3df9ccbb5149c22d79987ebdcd6cab4b261f)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3292)
# [2.8.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.7.1...netlify-cms-backend-github@2.8.0) (2020-02-22)
### Features
* **core:** Align GitHub metadata handling with other backends ([#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3292)) ([8193b5a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/8193b5ace89d6f14a6c756235a50b186a763b6b1))
## [2.7.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.7.0...netlify-cms-backend-github@2.7.1) (2020-02-17)
**Note:** Version bump only for package netlify-cms-backend-github
# [2.7.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.6...netlify-cms-backend-github@2.7.0) (2020-02-10)
### Features
* field based media/public folders ([#3208](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3208)) ([97bc0c8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/97bc0c8dc489e736f89d748ba832d78400fe4332))
### Reverts
* Revert "chore(release): publish" ([a015d1d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/a015d1d92a4b1c0130c44fcef1c9ecdb157a0f07))
## [2.6.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.5...netlify-cms-backend-github@2.6.6) (2020-02-06)
### Bug Fixes
* **locale:** remove hard coded strings ([#3193](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3193)) ([fc91bf8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/fc91bf8781e65ce1dc946363dbb10419a145c66b))
## [2.6.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.4...netlify-cms-backend-github@2.6.5) (2020-01-24)
### Bug Fixes
* **backend-git-gateway:** re-write GitHub pagination links ([#3135](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3135)) ([834f6b9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/834f6b9e457f3738ce0f240ddd4cc160aff9e2f5))
## [2.6.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.3...netlify-cms-backend-github@2.6.4) (2020-01-16)
### Bug Fixes
* **backend-github-graphql:** handle trailing paths in collection folder ([#3099](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3099)) ([bc80804](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/bc808040661d345e65d49d64693cd6da3b6816fb))
## [2.6.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.2...netlify-cms-backend-github@2.6.3) (2020-01-14)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.6.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.1...netlify-cms-backend-github@2.6.2) (2020-01-14)
### Bug Fixes
* **backend-github-graphql:** return empty array on non existent folder ([#3079](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3079)) ([69b130a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/69b130a3f239590f828f0e4f6f6c0a872b17548b))
## [2.6.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.0...netlify-cms-backend-github@2.6.1) (2020-01-09)
### Bug Fixes
* trim '/' from folder ([#3052](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/3052)) ([4b6c8de](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/4b6c8de6b2e3de28f0989b9a012cb302d4de4358))
# [2.6.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.6.0-beta.0...netlify-cms-backend-github@2.6.0) (2020-01-07)
### Bug Fixes
* rebase open authoring branches ([#2975](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2975)) ([8c175f6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/8c175f6132fa18a13763cc563f7d3201c1e3580e))
# [2.6.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0...netlify-cms-backend-github@2.6.0-beta.0) (2019-12-18)
### Features
* bundle assets with content ([#2958](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2958)) ([2b41d8a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/2b41d8a838a9c8a6b21cde2ddd16b9288334e298))
# [2.5.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.8...netlify-cms-backend-github@2.5.0) (2019-12-18)
**Note:** Version bump only for package netlify-cms-backend-github
# [2.5.0-beta.8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.7...netlify-cms-backend-github@2.5.0-beta.8) (2019-12-16)
### Bug Fixes
* don't fail on deleting non existent branch ([1e77d4b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/1e77d4b7688de795ab1b01c6ce2483a0383bbfb6))
# [2.5.0-beta.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.6...netlify-cms-backend-github@2.5.0-beta.7) (2019-12-02)
### Features
* content in sub folders ([#2897](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2897)) ([afcfe5b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/afcfe5b6d5f32669e9061ec596bd35ad545d61a3))
# [2.5.0-beta.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.5...netlify-cms-backend-github@2.5.0-beta.6) (2019-11-26)
### Bug Fixes
* **backend-github:** prepend collection name ([#2878](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2878)) ([465f463](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/465f4639597f258d5aa2c1b65e9d2c16023ee7ae))
### Features
* workflow unpublished entry ([#2914](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2914)) ([41bb9aa](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/41bb9aac0dd6fd9f8ff157bb0b29c85aa87fe04d))
# [2.5.0-beta.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.4...netlify-cms-backend-github@2.5.0-beta.5) (2019-11-18)
### Bug Fixes
* **backend-github:** editorial workflow commits ([#2867](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2867)) ([86adca3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/86adca3a18f25ab74d1c6702bafab250f005ceec))
* make forkExists name matching case-insensitive ([#2869](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2869)) ([9978769](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/9978769ece9262265d3efa77357f9e8b46ad9a1e))
* **backend-github:** loaded entries limit ([#2873](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2873)) ([68a8c8a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/68a8c8a693646ebd33fae791aaaec47b050e0186))
* **git-gateway:** unpublished entries not loaded for git-gateway(GitHub) ([#2856](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2856)) ([4a2328b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/4a2328b2f10ea678184391e4caf235b41323cd3e))
### Features
* commit media with post ([#2851](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2851)) ([6515dee](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/6515dee8715d8571ea19484a7dfab7cfd0cc40be))
# [2.5.0-beta.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.3...netlify-cms-backend-github@2.5.0-beta.4) (2019-11-07)
### Bug Fixes
* **github-backend:** load media URLs via API ([#2817](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2817)) ([eaeaf44](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/eaeaf4483287a1f724ee60ef321ff749f1c20acf))
* change default open authoring scope, make it configurable ([#2821](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2821)) ([002cdd7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/002cdd77a856bde3672e75dde6d3a2b246e1035f))
* display UI to fork a repo only when fork doesn't exist ([#2802](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2802)) ([7f90d0e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/7f90d0e065315b9073d21fd733f42f3838ecfe09))
### Features
* add go back to site button ([#2538](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2538)) ([f206e7e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/f206e7e5a13fb48ec6b27dce0dbb3a59b61de8f9))
# [2.5.0-beta.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.2...netlify-cms-backend-github@2.5.0-beta.3) (2019-09-26)
### Bug Fixes
* **backend-github:** update Open Authoring branches with no PR ([#2618](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2618)) ([6817033](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/6817033))
* **git-gateway:** pass api URL instead of constructing it from repo value ([#2631](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2631)) ([922c0f3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/922c0f3))
* **github-backend:** handle race condition in editorial workflow ([#2658](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2658)) ([97f1f84](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/97f1f84))
# [2.5.0-beta.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.1...netlify-cms-backend-github@2.5.0-beta.2) (2019-09-04)
### Bug Fixes
* **github-graphql:** use getMediaDisplayURL to load media with auth header ([#2652](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2652)) ([e674e43](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/e674e43))
### Features
* **backend-github:** GitHub GraphQL API support ([#2456](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2456)) ([ece136c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/ece136c))
# [2.5.0-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.5.0-beta.0...netlify-cms-backend-github@2.5.0-beta.1) (2019-08-24)
**Note:** Version bump only for package netlify-cms-backend-github
# [2.5.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.4.2...netlify-cms-backend-github@2.5.0-beta.0) (2019-07-24)
### Features
* **backend-github:** Open Authoring ([#2430](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2430)) ([edf0a3a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/edf0a3a))
## [2.4.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.4.2-beta.0...netlify-cms-backend-github@2.4.2) (2019-04-10)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.4.2-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.4.1...netlify-cms-backend-github@2.4.2-beta.0) (2019-04-05)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.4.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.4.1-beta.1...netlify-cms-backend-github@2.4.1) (2019-03-29)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.4.1-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.4.1-beta.0...netlify-cms-backend-github@2.4.1-beta.1) (2019-03-26)
### Bug Fixes
* export on netlify-cms and maps on esm ([#2244](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2244)) ([6ffd13b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/6ffd13b))
## [2.4.1-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.4.0...netlify-cms-backend-github@2.4.1-beta.0) (2019-03-25)
### Bug Fixes
* update peer dep versions ([#2234](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2234)) ([7987091](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/7987091))
# [2.4.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.3.0...netlify-cms-backend-github@2.4.0) (2019-03-22)
### Features
* add ES module builds ([#2215](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2215)) ([d142b32](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/d142b32))
# [2.3.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.3.0-beta.0...netlify-cms-backend-github@2.3.0) (2019-03-22)
**Note:** Version bump only for package netlify-cms-backend-github
# [2.3.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.2.3-beta.0...netlify-cms-backend-github@2.3.0-beta.0) (2019-03-21)
### Bug Fixes
* fix umd builds ([#2214](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2214)) ([e04f6be](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/e04f6be))
### Features
* provide usable UMD builds for all packages ([#2141](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2141)) ([82cc794](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/82cc794))
## [2.2.3-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.2.2...netlify-cms-backend-github@2.2.3-beta.0) (2019-03-15)
### Features
* upgrade to Emotion 10 ([#2166](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2166)) ([ccef446](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/ccef446))
## [2.2.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.2.1...netlify-cms-backend-github@2.2.2) (2019-03-08)
**Note:** Version bump only for package netlify-cms-backend-github
## [2.2.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.2.0...netlify-cms-backend-github@2.2.1) (2019-02-26)
**Note:** Version bump only for package netlify-cms-backend-github
# [2.2.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.1.0...netlify-cms-backend-github@2.2.0) (2019-02-08)
### Features
* **workflow:** add deploy preview links ([#2028](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/2028)) ([15d221d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/15d221d))
# [2.1.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.9...netlify-cms-backend-github@2.1.0) (2018-11-12)
### Features
* allow custom logo on auth page ([#1818](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/1818)) ([c6ae1e8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/c6ae1e8))
<a name="2.0.9"></a>
## [2.0.9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.8...netlify-cms-backend-github@2.0.9) (2018-09-17)
**Note:** Version bump only for package netlify-cms-backend-github
<a name="2.0.8"></a>
## [2.0.8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.7...netlify-cms-backend-github@2.0.8) (2018-09-06)
**Note:** Version bump only for package netlify-cms-backend-github
<a name="2.0.7"></a>
## [2.0.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.6...netlify-cms-backend-github@2.0.7) (2018-08-27)
**Note:** Version bump only for package netlify-cms-backend-github
<a name="2.0.6"></a>
## [2.0.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.5...netlify-cms-backend-github@2.0.6) (2018-08-24)
**Note:** Version bump only for package netlify-cms-backend-github
<a name="2.0.5"></a>
## [2.0.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.4...netlify-cms-backend-github@2.0.5) (2018-08-07)
### Bug Fixes
* **backends:** fix commit message handling ([#1568](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/1568)) ([f7e7120](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/f7e7120))
<a name="2.0.4"></a>
## [2.0.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.3...netlify-cms-backend-github@2.0.4) (2018-08-01)
### Bug Fixes
* **workflow:** enable workflow per method ([#1569](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/1569)) ([90b8156](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/90b8156))
<a name="2.0.3"></a>
## [2.0.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.2...netlify-cms-backend-github@2.0.3) (2018-08-01)
### Bug Fixes
* **github:** fix image uploading ([#1561](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/1561)) ([ddc8f04](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/ddc8f04))
* **workflow:** fix status not set on new workflow entries ([#1558](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/issues/1558)) ([0aa085f](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/commit/0aa085f))
<a name="2.0.2"></a>
## [2.0.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github/compare/netlify-cms-backend-github@2.0.1...netlify-cms-backend-github@2.0.2) (2018-07-28)
**Note:** Version bump only for package netlify-cms-backend-github
<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 netlify-cms-backend-github

View File

@ -1,17 +0,0 @@
# GitHub backend
An abstraction layer between the CMS and [Github](https://docs.github.com/en/rest)
## Code structure
`Implementation` for [File Management System API](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-util/README.md) based on `Api`.
`Api` - A wrapper for GitHub REST API.
`GraphQLApi` - `Api` with `ApolloClient`. [Api docs](https://docs.github.com/en/graphql) and [netlify docs](https://www.netlifycms.org/docs/beta-features/#github-graphql-api).
`AuthenticationPage` - uses [lib-auth](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-auth/README.md) to facilitate OAuth and implicit authentication.
`scripts` - use `createFragmentTypes.js` to create GitHub GraphQL API fragment types.
Look at tests or types for more info.

View File

@ -1,44 +0,0 @@
{
"name": "netlify-cms-backend-github",
"description": "GitHub backend for Netlify CMS",
"version": "2.14.3",
"license": "MIT",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-github",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"module": "dist/esm/index.js",
"main": "dist/netlify-cms-backend-github.js",
"keywords": [
"netlify",
"netlify-cms",
"backend",
"github"
],
"sideEffects": false,
"scripts": {
"develop": "yarn 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\"",
"createFragmentTypes": "node scripts/createFragmentTypes.js"
},
"dependencies": {
"apollo-cache-inmemory": "^1.6.2",
"apollo-client": "^2.6.3",
"apollo-link-context": "^1.0.18",
"apollo-link-http": "^1.5.15",
"common-tags": "^1.8.0",
"graphql": "^15.0.0",
"graphql-tag": "^2.10.1",
"js-base64": "^3.0.0",
"semaphore": "^1.1.0"
},
"peerDependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"lodash": "^4.17.11",
"netlify-cms-lib-auth": "^2.3.0",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0"
}
}

View File

@ -1,833 +0,0 @@
import { Base64 } from 'js-base64';
import API from '../API';
global.fetch = jest.fn().mockRejectedValue(new Error('should not call fetch inside tests'));
describe('github API', () => {
beforeEach(() => {
jest.resetAllMocks();
});
function mockAPI(api, responses) {
api.request = jest.fn().mockImplementation((path, options = {}) => {
const normalizedPath = path.indexOf('?') !== -1 ? path.slice(0, path.indexOf('?')) : path;
const response = responses[normalizedPath];
return typeof response === 'function'
? Promise.resolve(response(options))
: Promise.reject(new Error(`No response for path '${normalizedPath}'`));
});
}
describe('editorialWorkflowGit', () => {
it('should create PR with correct base branch name when publishing with editorial workflow', () => {
let prBaseBranch = null;
let labels = null;
const api = new API({
branch: 'gh-pages',
repo: 'owner/my-repo',
initialWorkflowStatus: 'draft',
});
const responses = {
'/repos/owner/my-repo/branches/gh-pages': () => ({ commit: { sha: 'def' } }),
'/repos/owner/my-repo/git/trees/def': () => ({ tree: [] }),
'/repos/owner/my-repo/git/trees': () => ({}),
'/repos/owner/my-repo/git/commits': () => ({}),
'/repos/owner/my-repo/git/refs': () => ({}),
'/repos/owner/my-repo/pulls': req => {
prBaseBranch = JSON.parse(req.body).base;
return { head: { sha: 'cbd' }, labels: [], number: 1 };
},
'/repos/owner/my-repo/issues/1/labels': req => {
labels = JSON.parse(req.body).labels;
return {};
},
};
mockAPI(api, responses);
return expect(
api.editorialWorkflowGit([], { slug: 'entry', sha: 'abc' }, null, {}).then(() => ({
prBaseBranch,
labels,
})),
).resolves.toEqual({ prBaseBranch: 'gh-pages', labels: ['netlify-cms/draft'] });
});
it('should create PR with correct base branch name with custom prefix when publishing with editorial workflow', () => {
let prBaseBranch = null;
let labels = null;
const api = new API({
branch: 'gh-pages',
repo: 'owner/my-repo',
initialWorkflowStatus: 'draft',
cmsLabelPrefix: 'other/',
});
const responses = {
'/repos/owner/my-repo/branches/gh-pages': () => ({ commit: { sha: 'def' } }),
'/repos/owner/my-repo/git/trees/def': () => ({ tree: [] }),
'/repos/owner/my-repo/git/trees': () => ({}),
'/repos/owner/my-repo/git/commits': () => ({}),
'/repos/owner/my-repo/git/refs': () => ({}),
'/repos/owner/my-repo/pulls': req => {
prBaseBranch = JSON.parse(req.body).base;
return { head: { sha: 'cbd' }, labels: [], number: 1 };
},
'/repos/owner/my-repo/issues/1/labels': req => {
labels = JSON.parse(req.body).labels;
return {};
},
};
mockAPI(api, responses);
return expect(
api.editorialWorkflowGit([], { slug: 'entry', sha: 'abc' }, null, {}).then(() => ({
prBaseBranch,
labels,
})),
).resolves.toEqual({ prBaseBranch: 'gh-pages', labels: ['other/draft'] });
});
});
describe('updateTree', () => {
it('should create tree with nested paths', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
api.createTree = jest.fn().mockImplementation(() => Promise.resolve({ sha: 'newTreeSha' }));
const files = [
{ path: '/static/media/new-image.jpeg', sha: null },
{ path: 'content/posts/new-post.md', sha: 'new-post.md' },
];
const baseTreeSha = 'baseTreeSha';
await expect(api.updateTree(baseTreeSha, files)).resolves.toEqual({
sha: 'newTreeSha',
parentSha: baseTreeSha,
});
expect(api.createTree).toHaveBeenCalledTimes(1);
expect(api.createTree).toHaveBeenCalledWith(baseTreeSha, [
{
path: 'static/media/new-image.jpeg',
mode: '100644',
type: 'blob',
sha: null,
},
{
path: 'content/posts/new-post.md',
mode: '100644',
type: 'blob',
sha: 'new-post.md',
},
]);
});
});
describe('request', () => {
beforeEach(() => {
const fetch = jest.fn();
global.fetch = fetch;
});
afterEach(() => {
jest.resetAllMocks();
});
it('should fetch url with authorization header', async () => {
const api = new API({ branch: 'gh-pages', repo: 'my-repo', token: 'token' });
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue('some response'),
ok: true,
status: 200,
headers: { get: () => '' },
});
const result = await api.request('/some-path');
expect(result).toEqual('some response');
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('https://api.github.com/some-path', {
cache: 'no-cache',
headers: {
Authorization: 'token token',
'Content-Type': 'application/json; charset=utf-8',
},
signal: expect.any(AbortSignal),
});
});
it('should throw error on not ok response', async () => {
const api = new API({ branch: 'gh-pages', repo: 'my-repo', token: 'token' });
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue({ message: 'some error' }),
ok: false,
status: 404,
headers: { get: () => '' },
});
await expect(api.request('some-path')).rejects.toThrow(
expect.objectContaining({
message: 'some error',
name: 'API_ERROR',
status: 404,
api: 'GitHub',
}),
);
});
it('should allow overriding requestHeaders to return a promise ', async () => {
const api = new API({ branch: 'gh-pages', repo: 'my-repo', token: 'token' });
api.requestHeaders = jest.fn().mockResolvedValue({
Authorization: 'promise-token',
'Content-Type': 'application/json; charset=utf-8',
});
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue('some response'),
ok: true,
status: 200,
headers: { get: () => '' },
});
const result = await api.request('/some-path');
expect(result).toEqual('some response');
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('https://api.github.com/some-path', {
cache: 'no-cache',
headers: {
Authorization: 'promise-token',
'Content-Type': 'application/json; charset=utf-8',
},
signal: expect.any(AbortSignal),
});
});
});
describe('persistFiles', () => {
it('should update tree, commit and patch branch when useWorkflow is false', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const responses = {
// upload the file
'/repos/owner/repo/git/blobs': () => ({ sha: 'new-file-sha' }),
// get the branch
'/repos/owner/repo/branches/master': () => ({ commit: { sha: 'root' } }),
// create new tree
'/repos/owner/repo/git/trees': options => {
const data = JSON.parse(options.body);
return { sha: data.base_tree };
},
// update the commit with the tree
'/repos/owner/repo/git/commits': () => ({ sha: 'commit-sha' }),
// patch the branch
'/repos/owner/repo/git/refs/heads/master': () => ({}),
};
mockAPI(api, responses);
const entry = {
dataFiles: [
{
slug: 'entry',
sha: 'abc',
path: 'content/posts/new-post.md',
raw: 'content',
},
],
assets: [],
};
await api.persistFiles(entry.dataFiles, entry.assets, { commitMessage: 'commitMessage' });
expect(api.request).toHaveBeenCalledTimes(5);
expect(api.request.mock.calls[0]).toEqual([
'/repos/owner/repo/git/blobs',
{
method: 'POST',
body: JSON.stringify({
content: Base64.encode(entry.dataFiles[0].raw),
encoding: 'base64',
}),
},
]);
expect(api.request.mock.calls[1]).toEqual(['/repos/owner/repo/branches/master']);
expect(api.request.mock.calls[2]).toEqual([
'/repos/owner/repo/git/trees',
{
body: JSON.stringify({
base_tree: 'root',
tree: [
{
path: 'content/posts/new-post.md',
mode: '100644',
type: 'blob',
sha: 'new-file-sha',
},
],
}),
method: 'POST',
},
]);
expect(api.request.mock.calls[3]).toEqual([
'/repos/owner/repo/git/commits',
{
body: JSON.stringify({
message: 'commitMessage',
tree: 'root',
parents: ['root'],
}),
method: 'POST',
},
]);
expect(api.request.mock.calls[4]).toEqual([
'/repos/owner/repo/git/refs/heads/master',
{
body: JSON.stringify({
sha: 'commit-sha',
force: false,
}),
method: 'PATCH',
},
]);
});
it('should call editorialWorkflowGit when useWorkflow is true', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
api.uploadBlob = jest.fn();
api.editorialWorkflowGit = jest.fn();
const entry = {
dataFiles: [
{
slug: 'entry',
sha: 'abc',
path: 'content/posts/new-post.md',
raw: 'content',
},
],
assets: [
{
path: '/static/media/image-1.png',
sha: 'image-1.png',
},
{
path: '/static/media/image-2.png',
sha: 'image-2.png',
},
],
};
await api.persistFiles(entry.dataFiles, entry.assets, { useWorkflow: true });
expect(api.uploadBlob).toHaveBeenCalledTimes(3);
expect(api.uploadBlob).toHaveBeenCalledWith(entry.dataFiles[0]);
expect(api.uploadBlob).toHaveBeenCalledWith(entry.assets[0]);
expect(api.uploadBlob).toHaveBeenCalledWith(entry.assets[1]);
expect(api.editorialWorkflowGit).toHaveBeenCalledTimes(1);
expect(api.editorialWorkflowGit).toHaveBeenCalledWith(
entry.assets.concat(entry.dataFiles),
entry.dataFiles[0].slug,
[
{ path: 'static/media/image-1.png', sha: 'image-1.png' },
{ path: 'static/media/image-2.png', sha: 'image-2.png' },
],
{ useWorkflow: true },
);
});
});
describe('migratePullRequest', () => {
it('should migrate to pull request labels when no version', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const pr = {
head: { ref: 'cms/2019-11-11-post-title' },
title: 'pr title',
number: 1,
labels: [],
};
const metadata = { type: 'PR' };
api.retrieveMetadataOld = jest.fn().mockResolvedValue(metadata);
const newBranch = 'cms/posts/2019-11-11-post-title';
const migrateToVersion1Result = {
metadata: { ...metadata, branch: newBranch, version: '1' },
pullRequest: { ...pr, number: 2 },
};
api.migrateToVersion1 = jest.fn().mockResolvedValue(migrateToVersion1Result);
api.migrateToPullRequestLabels = jest.fn();
await api.migratePullRequest(pr);
expect(api.migrateToVersion1).toHaveBeenCalledTimes(1);
expect(api.migrateToVersion1).toHaveBeenCalledWith(pr, metadata);
expect(api.migrateToPullRequestLabels).toHaveBeenCalledTimes(1);
expect(api.migrateToPullRequestLabels).toHaveBeenCalledWith(
migrateToVersion1Result.pullRequest,
migrateToVersion1Result.metadata,
);
expect(api.retrieveMetadataOld).toHaveBeenCalledTimes(1);
expect(api.retrieveMetadataOld).toHaveBeenCalledWith('2019-11-11-post-title');
});
it('should migrate to pull request labels when version is 1', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
api.migrateToVersion1 = jest.fn();
const pr = {
head: { ref: 'cms/posts/2019-11-11-post-title' },
title: 'pr title',
number: 1,
labels: [],
};
const metadata = { type: 'PR', version: '1' };
api.retrieveMetadataOld = jest.fn().mockResolvedValue(metadata);
api.migrateToPullRequestLabels = jest.fn().mockResolvedValue(pr, metadata);
await api.migratePullRequest(pr);
expect(api.migrateToVersion1).toHaveBeenCalledTimes(0);
expect(api.migrateToPullRequestLabels).toHaveBeenCalledTimes(1);
expect(api.migrateToPullRequestLabels).toHaveBeenCalledWith(pr, metadata);
expect(api.retrieveMetadataOld).toHaveBeenCalledTimes(1);
expect(api.retrieveMetadataOld).toHaveBeenCalledWith('posts/2019-11-11-post-title');
});
});
describe('migrateToVersion1', () => {
it('should migrate to version 1', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const pr = {
head: { ref: 'cms/2019-11-11-post-title', sha: 'pr_head' },
title: 'pr title',
number: 1,
labels: [],
};
const newBranch = { ref: 'refs/heads/cms/posts/2019-11-11-post-title' };
api.createBranch = jest.fn().mockResolvedValue(newBranch);
api.getBranch = jest.fn().mockRejectedValue(new Error('Branch not found'));
const newPr = { ...pr, number: 2 };
api.createPR = jest.fn().mockResolvedValue(newPr);
api.getPullRequests = jest.fn().mockResolvedValue([]);
api.storeMetadata = jest.fn();
api.closePR = jest.fn();
api.deleteBranch = jest.fn();
api.deleteMetadata = jest.fn();
const branch = 'cms/2019-11-11-post-title';
const metadata = {
branch,
type: 'PR',
pr: { head: pr.head.sha },
commitMessage: 'commitMessage',
collection: 'posts',
};
const expectedMetadata = {
type: 'PR',
pr: { head: newPr.head.sha, number: 2 },
commitMessage: 'commitMessage',
collection: 'posts',
branch: 'cms/posts/2019-11-11-post-title',
version: '1',
};
await expect(api.migrateToVersion1(pr, metadata)).resolves.toEqual({
metadata: expectedMetadata,
pullRequest: newPr,
});
expect(api.getBranch).toHaveBeenCalledTimes(1);
expect(api.getBranch).toHaveBeenCalledWith('cms/posts/2019-11-11-post-title');
expect(api.createBranch).toHaveBeenCalledTimes(1);
expect(api.createBranch).toHaveBeenCalledWith('cms/posts/2019-11-11-post-title', 'pr_head');
expect(api.getPullRequests).toHaveBeenCalledTimes(1);
expect(api.getPullRequests).toHaveBeenCalledWith(
'cms/posts/2019-11-11-post-title',
'all',
expect.any(Function),
);
expect(api.createPR).toHaveBeenCalledTimes(1);
expect(api.createPR).toHaveBeenCalledWith('pr title', 'cms/posts/2019-11-11-post-title');
expect(api.storeMetadata).toHaveBeenCalledTimes(1);
expect(api.storeMetadata).toHaveBeenCalledWith(
'posts/2019-11-11-post-title',
expectedMetadata,
);
expect(api.closePR).toHaveBeenCalledTimes(1);
expect(api.closePR).toHaveBeenCalledWith(pr.number);
expect(api.deleteBranch).toHaveBeenCalledTimes(1);
expect(api.deleteBranch).toHaveBeenCalledWith('cms/2019-11-11-post-title');
expect(api.deleteMetadata).toHaveBeenCalledTimes(1);
expect(api.deleteMetadata).toHaveBeenCalledWith('2019-11-11-post-title');
});
it('should not create new branch if exists', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const pr = {
head: { ref: 'cms/2019-11-11-post-title', sha: 'pr_head' },
title: 'pr title',
number: 1,
labels: [],
};
const newBranch = { ref: 'refs/heads/cms/posts/2019-11-11-post-title' };
api.createBranch = jest.fn();
api.getBranch = jest.fn().mockResolvedValue(newBranch);
const newPr = { ...pr, number: 2 };
api.createPR = jest.fn().mockResolvedValue(newPr);
api.getPullRequests = jest.fn().mockResolvedValue([]);
api.storeMetadata = jest.fn();
api.closePR = jest.fn();
api.deleteBranch = jest.fn();
api.deleteMetadata = jest.fn();
const branch = 'cms/2019-11-11-post-title';
const metadata = {
branch,
type: 'PR',
pr: { head: pr.head.sha },
commitMessage: 'commitMessage',
collection: 'posts',
};
const expectedMetadata = {
type: 'PR',
pr: { head: newPr.head.sha, number: 2 },
commitMessage: 'commitMessage',
collection: 'posts',
branch: 'cms/posts/2019-11-11-post-title',
version: '1',
};
await expect(api.migrateToVersion1(pr, metadata)).resolves.toEqual({
metadata: expectedMetadata,
pullRequest: newPr,
});
expect(api.getBranch).toHaveBeenCalledTimes(1);
expect(api.getBranch).toHaveBeenCalledWith('cms/posts/2019-11-11-post-title');
expect(api.createBranch).toHaveBeenCalledTimes(0);
expect(api.getPullRequests).toHaveBeenCalledTimes(1);
expect(api.getPullRequests).toHaveBeenCalledWith(
'cms/posts/2019-11-11-post-title',
'all',
expect.any(Function),
);
expect(api.createPR).toHaveBeenCalledTimes(1);
expect(api.createPR).toHaveBeenCalledWith('pr title', 'cms/posts/2019-11-11-post-title');
expect(api.storeMetadata).toHaveBeenCalledTimes(1);
expect(api.storeMetadata).toHaveBeenCalledWith(
'posts/2019-11-11-post-title',
expectedMetadata,
);
expect(api.closePR).toHaveBeenCalledTimes(1);
expect(api.closePR).toHaveBeenCalledWith(pr.number);
expect(api.deleteBranch).toHaveBeenCalledTimes(1);
expect(api.deleteBranch).toHaveBeenCalledWith('cms/2019-11-11-post-title');
expect(api.deleteMetadata).toHaveBeenCalledTimes(1);
expect(api.deleteMetadata).toHaveBeenCalledWith('2019-11-11-post-title');
});
it('should not create new pr if exists', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const pr = {
head: { ref: 'cms/2019-11-11-post-title', sha: 'pr_head' },
title: 'pr title',
number: 1,
labels: [],
};
const newBranch = { ref: 'refs/heads/cms/posts/2019-11-11-post-title' };
api.createBranch = jest.fn();
api.getBranch = jest.fn().mockResolvedValue(newBranch);
const newPr = { ...pr, number: 2 };
api.createPR = jest.fn();
api.getPullRequests = jest.fn().mockResolvedValue([newPr]);
api.storeMetadata = jest.fn();
api.closePR = jest.fn();
api.deleteBranch = jest.fn();
api.deleteMetadata = jest.fn();
const branch = 'cms/2019-11-11-post-title';
const metadata = {
branch,
type: 'PR',
pr: { head: pr.head.sha },
commitMessage: 'commitMessage',
collection: 'posts',
};
const expectedMetadata = {
type: 'PR',
pr: { head: newPr.head.sha, number: 2 },
commitMessage: 'commitMessage',
collection: 'posts',
branch: 'cms/posts/2019-11-11-post-title',
version: '1',
};
await expect(api.migrateToVersion1(pr, metadata)).resolves.toEqual({
metadata: expectedMetadata,
pullRequest: newPr,
});
expect(api.getBranch).toHaveBeenCalledTimes(1);
expect(api.getBranch).toHaveBeenCalledWith('cms/posts/2019-11-11-post-title');
expect(api.createBranch).toHaveBeenCalledTimes(0);
expect(api.getPullRequests).toHaveBeenCalledTimes(1);
expect(api.getPullRequests).toHaveBeenCalledWith(
'cms/posts/2019-11-11-post-title',
'all',
expect.any(Function),
);
expect(api.createPR).toHaveBeenCalledTimes(0);
expect(api.storeMetadata).toHaveBeenCalledTimes(1);
expect(api.storeMetadata).toHaveBeenCalledWith(
'posts/2019-11-11-post-title',
expectedMetadata,
);
expect(api.closePR).toHaveBeenCalledTimes(1);
expect(api.closePR).toHaveBeenCalledWith(pr.number);
expect(api.deleteBranch).toHaveBeenCalledTimes(1);
expect(api.deleteBranch).toHaveBeenCalledWith('cms/2019-11-11-post-title');
expect(api.deleteMetadata).toHaveBeenCalledTimes(1);
expect(api.deleteMetadata).toHaveBeenCalledWith('2019-11-11-post-title');
});
});
describe('migrateToPullRequestLabels', () => {
it('should migrate to pull request labels', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const pr = {
head: { ref: 'cms/posts/2019-11-11-post-title', sha: 'pr_head' },
title: 'pr title',
number: 1,
labels: [],
};
api.setPullRequestStatus = jest.fn();
api.deleteMetadata = jest.fn();
const metadata = {
branch: pr.head.ref,
type: 'PR',
pr: { head: pr.head.sha },
commitMessage: 'commitMessage',
collection: 'posts',
status: 'pending_review',
};
await api.migrateToPullRequestLabels(pr, metadata);
expect(api.setPullRequestStatus).toHaveBeenCalledTimes(1);
expect(api.setPullRequestStatus).toHaveBeenCalledWith(pr, 'pending_review');
expect(api.deleteMetadata).toHaveBeenCalledTimes(1);
expect(api.deleteMetadata).toHaveBeenCalledWith('posts/2019-11-11-post-title');
});
});
describe('rebaseSingleCommit', () => {
it('should create updated tree and commit', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
api.getDifferences = jest.fn().mockResolvedValueOnce({
files: [
{ filename: 'removed.md', status: 'removed', sha: 'removed_sha' },
{
filename: 'renamed.md',
status: 'renamed',
previous_filename: 'previous_filename.md',
sha: 'renamed_sha',
},
{ filename: 'added.md', status: 'added', sha: 'added_sha' },
],
});
const newTree = { sha: 'new_tree_sha' };
api.updateTree = jest.fn().mockResolvedValueOnce(newTree);
const newCommit = { sha: 'newCommit' };
api.createCommit = jest.fn().mockResolvedValueOnce(newCommit);
const baseCommit = { sha: 'base_commit_sha' };
const commit = {
sha: 'sha',
parents: [{ sha: 'parent_sha' }],
commit: {
message: 'message',
author: { name: 'author' },
committer: { name: 'committer' },
},
};
await expect(api.rebaseSingleCommit(baseCommit, commit)).resolves.toBe(newCommit);
expect(api.getDifferences).toHaveBeenCalledTimes(1);
expect(api.getDifferences).toHaveBeenCalledWith('parent_sha', 'sha');
expect(api.updateTree).toHaveBeenCalledTimes(1);
expect(api.updateTree).toHaveBeenCalledWith('base_commit_sha', [
{ path: 'removed.md', sha: null },
{ path: 'previous_filename.md', sha: null },
{ path: 'renamed.md', sha: 'renamed_sha' },
{ path: 'added.md', sha: 'added_sha' },
]);
expect(api.createCommit).toHaveBeenCalledTimes(1);
expect(api.createCommit).toHaveBeenCalledWith(
'message',
newTree.sha,
[baseCommit.sha],
{ name: 'author' },
{ name: 'committer' },
);
});
});
describe('listFiles', () => {
it('should get files by depth', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const tree = [
{
path: 'post.md',
type: 'blob',
},
{
path: 'dir1',
type: 'tree',
},
{
path: 'dir1/nested-post.md',
type: 'blob',
},
{
path: 'dir1/dir2',
type: 'tree',
},
{
path: 'dir1/dir2/nested-post.md',
type: 'blob',
},
];
api.request = jest.fn().mockResolvedValue({ tree });
await expect(api.listFiles('posts', { depth: 1 })).resolves.toEqual([
{
path: 'posts/post.md',
type: 'blob',
name: 'post.md',
},
]);
expect(api.request).toHaveBeenCalledTimes(1);
expect(api.request).toHaveBeenCalledWith('/repos/owner/repo/git/trees/master:posts', {
params: {},
});
jest.clearAllMocks();
await expect(api.listFiles('posts', { depth: 2 })).resolves.toEqual([
{
path: 'posts/post.md',
type: 'blob',
name: 'post.md',
},
{
path: 'posts/dir1/nested-post.md',
type: 'blob',
name: 'nested-post.md',
},
]);
expect(api.request).toHaveBeenCalledTimes(1);
expect(api.request).toHaveBeenCalledWith('/repos/owner/repo/git/trees/master:posts', {
params: { recursive: 1 },
});
jest.clearAllMocks();
await expect(api.listFiles('posts', { depth: 3 })).resolves.toEqual([
{
path: 'posts/post.md',
type: 'blob',
name: 'post.md',
},
{
path: 'posts/dir1/nested-post.md',
type: 'blob',
name: 'nested-post.md',
},
{
path: 'posts/dir1/dir2/nested-post.md',
type: 'blob',
name: 'nested-post.md',
},
]);
expect(api.request).toHaveBeenCalledTimes(1);
expect(api.request).toHaveBeenCalledWith('/repos/owner/repo/git/trees/master:posts', {
params: { recursive: 1 },
});
});
});
test('should get preview statuses', async () => {
const api = new API({ repo: 'repo' });
const statuses = [
{ context: 'deploy', state: 'success', target_url: 'deploy-url' },
{ context: 'build', state: 'error' },
];
api.request = jest.fn(() => Promise.resolve({ statuses }));
const sha = 'sha';
api.getBranchPullRequest = jest.fn(() => Promise.resolve({ head: { sha } }));
const collection = 'collection';
const slug = 'slug';
await expect(api.getStatuses(collection, slug)).resolves.toEqual([
{ context: 'deploy', state: 'success', target_url: 'deploy-url' },
{ context: 'build', state: 'other' },
]);
expect(api.getBranchPullRequest).toHaveBeenCalledTimes(1);
expect(api.getBranchPullRequest).toHaveBeenCalledWith('cms/collection/slug');
expect(api.request).toHaveBeenCalledTimes(1);
expect(api.request).toHaveBeenCalledWith(`/repos/repo/commits/${sha}/status`);
});
});

View File

@ -1,69 +0,0 @@
import GraphQLAPI from '../GraphQLAPI';
global.fetch = jest.fn().mockRejectedValue(new Error('should not call fetch inside tests'));
describe('github GraphQL API', () => {
beforeEach(() => {
jest.resetAllMocks();
});
describe('editorialWorkflowGit', () => {
it('should should flatten nested tree into a list of files', () => {
const api = new GraphQLAPI({ branch: 'gh-pages', repo: 'owner/my-repo' });
const entries = [
{
name: 'post-1.md',
sha: 'sha-1',
type: 'blob',
blob: { size: 1 },
},
{
name: 'post-2.md',
sha: 'sha-2',
type: 'blob',
blob: { size: 2 },
},
{
name: '2019',
sha: 'dir-sha',
type: 'tree',
object: {
entries: [
{
name: 'nested-post.md',
sha: 'nested-post-sha',
type: 'blob',
blob: { size: 3 },
},
],
},
},
];
const path = 'posts';
expect(api.getAllFiles(entries, path)).toEqual([
{
name: 'post-1.md',
id: 'sha-1',
type: 'blob',
size: 1,
path: 'posts/post-1.md',
},
{
name: 'post-2.md',
id: 'sha-2',
type: 'blob',
size: 2,
path: 'posts/post-2.md',
},
{
name: 'nested-post.md',
id: 'nested-post-sha',
type: 'blob',
size: 3,
path: 'posts/2019/nested-post.md',
},
]);
});
});
});

View File

@ -1,361 +0,0 @@
import { Cursor, CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util';
import GitHubImplementation from '../implementation';
jest.spyOn(console, 'error').mockImplementation(() => {});
describe('github backend implementation', () => {
const config = {
backend: {
repo: 'owner/repo',
open_authoring: false,
api_root: 'https://api.github.com',
},
};
const createObjectURL = jest.fn();
global.URL = {
createObjectURL,
};
createObjectURL.mockReturnValue('displayURL');
beforeEach(() => {
jest.clearAllMocks();
});
describe('forkExists', () => {
it('should return true when repo is fork and parent matches originRepo', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.currentUser = jest.fn().mockResolvedValue({ login: 'login' });
global.fetch = jest.fn().mockResolvedValue({
// matching should be case-insensitive
json: () => ({ fork: true, parent: { full_name: 'OWNER/REPO' } }),
});
await expect(gitHubImplementation.forkExists({ token: 'token' })).resolves.toBe(true);
expect(gitHubImplementation.currentUser).toHaveBeenCalledTimes(1);
expect(gitHubImplementation.currentUser).toHaveBeenCalledWith({ token: 'token' });
expect(global.fetch).toHaveBeenCalledTimes(1);
expect(global.fetch).toHaveBeenCalledWith('https://api.github.com/repos/login/repo', {
method: 'GET',
headers: {
Authorization: 'token token',
},
signal: expect.any(AbortSignal),
});
});
it('should return false when repo is not a fork', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.currentUser = jest.fn().mockResolvedValue({ login: 'login' });
global.fetch = jest.fn().mockResolvedValue({
// matching should be case-insensitive
json: () => ({ fork: false }),
});
expect.assertions(1);
await expect(gitHubImplementation.forkExists({ token: 'token' })).resolves.toBe(false);
});
it("should return false when parent doesn't match originRepo", async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.currentUser = jest.fn().mockResolvedValue({ login: 'login' });
global.fetch = jest.fn().mockResolvedValue({
json: () => ({ fork: true, parent: { full_name: 'owner/other_repo' } }),
});
expect.assertions(1);
await expect(gitHubImplementation.forkExists({ token: 'token' })).resolves.toBe(false);
});
});
describe('persistMedia', () => {
const persistFiles = jest.fn();
const mockAPI = {
persistFiles,
};
persistFiles.mockImplementation((_, files) => {
files.forEach((file, index) => {
file.sha = index;
});
});
it('should persist media file', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
const mediaFile = {
fileObj: { size: 100, name: 'image.png' },
path: '/media/image.png',
};
expect.assertions(5);
await expect(gitHubImplementation.persistMedia(mediaFile, {})).resolves.toEqual({
id: 0,
name: 'image.png',
size: 100,
displayURL: 'displayURL',
path: 'media/image.png',
});
expect(persistFiles).toHaveBeenCalledTimes(1);
expect(persistFiles).toHaveBeenCalledWith([], [mediaFile], {});
expect(createObjectURL).toHaveBeenCalledTimes(1);
expect(createObjectURL).toHaveBeenCalledWith(mediaFile.fileObj);
});
it('should log and throw error on "persistFiles" error', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
const error = new Error('failed to persist files');
persistFiles.mockRejectedValue(error);
const mediaFile = {
value: 'image.png',
fileObj: { size: 100 },
path: '/media/image.png',
};
expect.assertions(5);
await expect(gitHubImplementation.persistMedia(mediaFile)).rejects.toThrowError(error);
expect(persistFiles).toHaveBeenCalledTimes(1);
expect(createObjectURL).toHaveBeenCalledTimes(0);
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error).toHaveBeenCalledWith(error);
});
});
describe('unpublishedEntry', () => {
const generateContentKey = jest.fn();
const retrieveUnpublishedEntryData = jest.fn();
const mockAPI = {
generateContentKey,
retrieveUnpublishedEntryData,
};
it('should return unpublished entry data', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
gitHubImplementation.loadEntryMediaFiles = jest
.fn()
.mockResolvedValue([{ path: 'image.png', id: 'sha' }]);
generateContentKey.mockReturnValue('contentKey');
const data = {
collection: 'collection',
slug: 'slug',
status: 'draft',
diffs: [],
updatedAt: 'updatedAt',
};
retrieveUnpublishedEntryData.mockResolvedValue(data);
const collection = 'posts';
const slug = 'slug';
await expect(gitHubImplementation.unpublishedEntry({ collection, slug })).resolves.toEqual(
data,
);
expect(generateContentKey).toHaveBeenCalledTimes(1);
expect(generateContentKey).toHaveBeenCalledWith('posts', 'slug');
expect(retrieveUnpublishedEntryData).toHaveBeenCalledTimes(1);
expect(retrieveUnpublishedEntryData).toHaveBeenCalledWith('contentKey');
});
});
describe('entriesByFolder', () => {
const listFiles = jest.fn();
const readFile = jest.fn();
const readFileMetadata = jest.fn(() => Promise.resolve({ author: '', updatedOn: '' }));
const mockAPI = {
listFiles,
readFile,
readFileMetadata,
originRepoURL: 'originRepoURL',
};
it('should return entries and cursor', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
const files = [];
const count = 1501;
for (let i = 0; i < count; i++) {
const id = `${i}`.padStart(`${count}`.length, '0');
files.push({
id,
path: `posts/post-${id}.md`,
});
}
listFiles.mockResolvedValue(files);
readFile.mockImplementation((path, id) => Promise.resolve(`${id}`));
const expectedEntries = files
.slice(0, 20)
.map(({ id, path }) => ({ data: id, file: { path, id, author: '', updatedOn: '' } }));
const expectedCursor = Cursor.create({
actions: ['next', 'last'],
meta: { page: 1, count, pageSize: 20, pageCount: 76 },
data: { files },
});
expectedEntries[CURSOR_COMPATIBILITY_SYMBOL] = expectedCursor;
const result = await gitHubImplementation.entriesByFolder('posts', 'md', 1);
expect(result).toEqual(expectedEntries);
expect(listFiles).toHaveBeenCalledTimes(1);
expect(listFiles).toHaveBeenCalledWith('posts', { depth: 1, repoURL: 'originRepoURL' });
expect(readFile).toHaveBeenCalledTimes(20);
});
});
describe('traverseCursor', () => {
const listFiles = jest.fn();
const readFile = jest.fn((path, id) => Promise.resolve(`${id}`));
const readFileMetadata = jest.fn(() => Promise.resolve({}));
const mockAPI = {
listFiles,
readFile,
originRepoURL: 'originRepoURL',
readFileMetadata,
};
const files = [];
const count = 1501;
for (let i = 0; i < count; i++) {
const id = `${i}`.padStart(`${count}`.length, '0');
files.push({
id,
path: `posts/post-${id}.md`,
});
}
it('should handle next action', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
const cursor = Cursor.create({
actions: ['next', 'last'],
meta: { page: 1, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const expectedEntries = files
.slice(20, 40)
.map(({ id, path }) => ({ data: id, file: { path, id } }));
const expectedCursor = Cursor.create({
actions: ['prev', 'first', 'next', 'last'],
meta: { page: 2, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const result = await gitHubImplementation.traverseCursor(cursor, 'next');
expect(result).toEqual({
entries: expectedEntries,
cursor: expectedCursor,
});
});
it('should handle prev action', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
const cursor = Cursor.create({
actions: ['prev', 'first', 'next', 'last'],
meta: { page: 2, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const expectedEntries = files
.slice(0, 20)
.map(({ id, path }) => ({ data: id, file: { path, id } }));
const expectedCursor = Cursor.create({
actions: ['next', 'last'],
meta: { page: 1, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const result = await gitHubImplementation.traverseCursor(cursor, 'prev');
expect(result).toEqual({
entries: expectedEntries,
cursor: expectedCursor,
});
});
it('should handle last action', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
const cursor = Cursor.create({
actions: ['next', 'last'],
meta: { page: 1, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const expectedEntries = files
.slice(1500)
.map(({ id, path }) => ({ data: id, file: { path, id } }));
const expectedCursor = Cursor.create({
actions: ['prev', 'first'],
meta: { page: 76, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const result = await gitHubImplementation.traverseCursor(cursor, 'last');
expect(result).toEqual({
entries: expectedEntries,
cursor: expectedCursor,
});
});
it('should handle first action', async () => {
const gitHubImplementation = new GitHubImplementation(config);
gitHubImplementation.api = mockAPI;
const cursor = Cursor.create({
actions: ['prev', 'first'],
meta: { page: 76, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const expectedEntries = files
.slice(0, 20)
.map(({ id, path }) => ({ data: id, file: { path, id } }));
const expectedCursor = Cursor.create({
actions: ['next', 'last'],
meta: { page: 1, count, pageSize: 20, pageCount: 76 },
data: { files },
});
const result = await gitHubImplementation.traverseCursor(cursor, 'first');
expect(result).toEqual({
entries: expectedEntries,
cursor: expectedCursor,
});
});
});
});

File diff suppressed because one or more lines are too long

View File

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

View File

@ -1,593 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.13.2](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-gitlab@2.13.1...netlify-cms-backend-gitlab@2.13.2) (2022-09-22)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.13.1](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-gitlab@2.13.0...netlify-cms-backend-gitlab@2.13.1) (2022-09-21)
**Note:** Version bump only for package netlify-cms-backend-gitlab
# [2.13.0](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-gitlab@2.12.0...netlify-cms-backend-gitlab@2.13.0) (2021-12-28)
### Features
* **backend-gitlab:** initial GraphQL support ([#6059](https://github.com/netlify/netlify-cms/issues/6059)) ([1523a41](https://github.com/netlify/netlify-cms/commit/1523a4140a3d2f4cc01a1548514ae17bc1ad504e))
# [2.12.0](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-gitlab@2.11.4...netlify-cms-backend-gitlab@2.12.0) (2021-10-18)
### Features
* display author of changes in workflow tab ([#5780](https://github.com/netlify/netlify-cms/issues/5780)) ([3f607e4](https://github.com/netlify/netlify-cms/commit/3f607e41d9c4d8fe5329a9ab6841cada7742825e))
## [2.11.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.11.3...netlify-cms-backend-gitlab@2.11.4) (2021-06-01)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.11.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.11.2...netlify-cms-backend-gitlab@2.11.3) (2021-05-31)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.11.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.11.1...netlify-cms-backend-gitlab@2.11.2) (2021-05-19)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.11.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.11.0...netlify-cms-backend-gitlab@2.11.1) (2021-05-04)
### Bug Fixes
* **backend-gitlab:** increase merge requests fetched to 100 ([#5320](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/5320)) ([0a1b00d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/0a1b00d8b29a065b7d72fbb1744eb787da3b916e))
# [2.11.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.10.0...netlify-cms-backend-gitlab@2.11.0) (2021-05-04)
### Features
* added react 17 as peer dependency in packages ([#5316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/5316)) ([9e42380](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
# [2.10.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.9.9...netlify-cms-backend-gitlab@2.10.0) (2021-04-14)
### Features
* Adds PKCE authentication for GitLab closes [#5236](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/5236) ([#5239](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/5239)) ([829409e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/829409e0bc03b4591ee6b59d9895adc4e7190037))
## [2.9.9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.9.8...netlify-cms-backend-gitlab@2.9.9) (2021-02-23)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.9.8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.9.7...netlify-cms-backend-gitlab@2.9.8) (2021-02-10)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.9.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.9.6...netlify-cms-backend-gitlab@2.9.7) (2021-02-01)
### Bug Fixes
* **backend-gitlab:** increase rebase timeout ([#4905](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/4905)) ([d9d6860](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/d9d686025fe848fe460917cdef1934dea3295c9d))
## [2.9.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.9.5...netlify-cms-backend-gitlab@2.9.6) (2021-01-05)
### Bug Fixes
* **backend-gitlab:** skip creating a CI pipeline when rebasing merge request ([#4802](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/4802)) ([ce11dd2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/ce11dd23753fd7bb502c299058b83701f20058b2)), closes [#4786](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/4786)
## [2.9.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.9.4...netlify-cms-backend-gitlab@2.9.5) (2020-09-20)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.9.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.9.3...netlify-cms-backend-gitlab@2.9.4) (2020-09-15)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## 2.9.3 (2020-09-08)
### Reverts
* Revert "chore(release): publish" ([828bb16](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
## 2.9.2 (2020-08-20)
### Reverts
* Revert "chore(release): publish" ([8262487](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/82624879ccbcb16610090041db28f00714d924c8))
## 2.9.1 (2020-07-27)
### Reverts
* Revert "chore(release): publish" ([118d50a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/118d50a7a70295f25073e564b5161aa2b9883056))
# [2.9.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.8.4...netlify-cms-backend-gitlab@2.9.0) (2020-06-18)
### Bug Fixes
* handle token expiry ([#3847](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3847)) ([285c940](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/285c940562548d7bc88de244123ba87ff66fba65))
### Features
* add backend status down indicator ([#3889](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3889)) ([a50edc7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
* **backend-gitgateway:** improve deploy preview visibility ([#3882](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3882)) ([afc9bf4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/afc9bf4f3fe14ccb60851fc24e68922a6e4a85a9))
## [2.8.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.8.3...netlify-cms-backend-gitlab@2.8.4) (2020-04-21)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.8.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.8.2...netlify-cms-backend-gitlab@2.8.3) (2020-04-01)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.8.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.8.1...netlify-cms-backend-gitlab@2.8.2) (2020-03-20)
### Bug Fixes
* missing workflow timestamp ([#3445](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3445)) ([9616cdb](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/9616cdb8bb0a564771e5755bcd3718a07f2e2072))
## [2.8.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.8.0...netlify-cms-backend-gitlab@2.8.1) (2020-03-03)
### Bug Fixes
* **locale:** Remove hard coded string literals ([#3333](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3333)) ([7c45a3c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/7c45a3cda983be427864a56e58791565eb9232e2))
# [2.8.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.7.1...netlify-cms-backend-gitlab@2.8.0) (2020-02-25)
### Features
* **core:** align GitHub metadata handling with other backends ([#3316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3316)) ([7e0a8ad](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/7e0a8ad532012576dc5e40bd4e9d54522e307123)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3292)
## [2.7.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.7.0...netlify-cms-backend-gitlab@2.7.1) (2020-02-22)
### Reverts
* Revert "feat(core): Align GitHub metadata handling with other backends (#3292)" ([5bdd3df](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/5bdd3df9ccbb5149c22d79987ebdcd6cab4b261f)), closes [#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3292)
# [2.7.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.6.0...netlify-cms-backend-gitlab@2.7.0) (2020-02-22)
### Features
* **core:** Align GitHub metadata handling with other backends ([#3292](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3292)) ([8193b5a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/8193b5ace89d6f14a6c756235a50b186a763b6b1))
# [2.6.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.5.3...netlify-cms-backend-gitlab@2.6.0) (2020-02-10)
### Bug Fixes
* filter paginated results ([#3216](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3216)) ([0a482b1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/0a482b10049bcfa022b81165cabf4512d77e0b88))
* workflow file collection ([#3207](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3207)) ([d22f7e6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/d22f7e680e7064e8607cf8b420571fa40a6c314e))
### Features
* field based media/public folders ([#3208](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3208)) ([97bc0c8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/97bc0c8dc489e736f89d748ba832d78400fe4332))
### Reverts
* Revert "chore(release): publish" ([a015d1d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/a015d1d92a4b1c0130c44fcef1c9ecdb157a0f07))
## [2.5.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.5.2...netlify-cms-backend-gitlab@2.5.3) (2020-02-06)
### Bug Fixes
* **locale:** remove hard coded strings ([#3193](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3193)) ([fc91bf8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/fc91bf8781e65ce1dc946363dbb10419a145c66b))
## [2.5.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.5.1...netlify-cms-backend-gitlab@2.5.2) (2020-01-21)
### Bug Fixes
* **backend-gitlab:** check for shared group permissions ([#3122](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3122)) ([f1739e9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/f1739e978f9dee1de42dd5479ec80a5d991a9bfe))
* **git-gateway-gitlab:** fix large media support for editorial workflow ([#3105](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/3105)) ([038803c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/038803c9f249de386812652372c35c4c53935295))
## [2.5.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.5.0...netlify-cms-backend-gitlab@2.5.1) (2020-01-14)
**Note:** Version bump only for package netlify-cms-backend-gitlab
# [2.5.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.5.0-beta.0...netlify-cms-backend-gitlab@2.5.0) (2020-01-07)
**Note:** Version bump only for package netlify-cms-backend-gitlab
# [2.5.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.4.0...netlify-cms-backend-gitlab@2.5.0-beta.0) (2019-12-18)
### Features
* bundle assets with content ([#2958](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2958)) ([2b41d8a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/2b41d8a838a9c8a6b21cde2ddd16b9288334e298))
# [2.4.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.4.0-beta.1...netlify-cms-backend-gitlab@2.4.0) (2019-12-18)
**Note:** Version bump only for package netlify-cms-backend-gitlab
# [2.4.0-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.4.0-beta.0...netlify-cms-backend-gitlab@2.4.0-beta.1) (2019-12-02)
### Features
* content in sub folders ([#2897](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2897)) ([afcfe5b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/afcfe5b6d5f32669e9061ec596bd35ad545d61a3))
# [2.4.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.3-beta.1...netlify-cms-backend-gitlab@2.4.0-beta.0) (2019-11-07)
### Features
* add go back to site button ([#2538](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2538)) ([f206e7e](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/f206e7e5a13fb48ec6b27dce0dbb3a59b61de8f9))
* enable specifying custom open authoring commit message ([#2810](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2810)) ([2841ff9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/2841ff9ffe58afcf4dba45514a84a262ad370f1d))
## [2.3.3-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.3-beta.0...netlify-cms-backend-gitlab@2.3.3-beta.1) (2019-09-26)
### Bug Fixes
* **backend-gitlab:** exclude directories in paginated results ([#2668](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2668)) ([3903acb](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/3903acb))
## [2.3.3-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.2...netlify-cms-backend-gitlab@2.3.3-beta.0) (2019-08-24)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.3.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.2-beta.0...netlify-cms-backend-gitlab@2.3.2) (2019-04-10)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.3.2-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.1...netlify-cms-backend-gitlab@2.3.2-beta.0) (2019-04-05)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.3.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.1-beta.1...netlify-cms-backend-gitlab@2.3.1) (2019-03-29)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.3.1-beta.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.1-beta.0...netlify-cms-backend-gitlab@2.3.1-beta.1) (2019-03-26)
### Bug Fixes
* export on netlify-cms and maps on esm ([#2244](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2244)) ([6ffd13b](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/6ffd13b))
## [2.3.1-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.3.0...netlify-cms-backend-gitlab@2.3.1-beta.0) (2019-03-25)
### Bug Fixes
* update peer dep versions ([#2234](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2234)) ([7987091](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/7987091))
# [2.3.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.2.0...netlify-cms-backend-gitlab@2.3.0) (2019-03-22)
### Features
* add ES module builds ([#2215](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2215)) ([d142b32](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/d142b32))
# [2.2.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.2.0-beta.0...netlify-cms-backend-gitlab@2.2.0) (2019-03-22)
**Note:** Version bump only for package netlify-cms-backend-gitlab
# [2.2.0-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.1.4-beta.0...netlify-cms-backend-gitlab@2.2.0-beta.0) (2019-03-21)
### Bug Fixes
* fix umd builds ([#2214](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2214)) ([e04f6be](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/e04f6be))
### Features
* provide usable UMD builds for all packages ([#2141](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2141)) ([82cc794](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/82cc794))
## [2.1.4-beta.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.1.3...netlify-cms-backend-gitlab@2.1.4-beta.0) (2019-03-15)
### Features
* upgrade to Emotion 10 ([#2166](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/2166)) ([ccef446](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/ccef446))
## [2.1.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.1.2...netlify-cms-backend-gitlab@2.1.3) (2019-03-08)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.1.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.1.1...netlify-cms-backend-gitlab@2.1.2) (2019-02-26)
**Note:** Version bump only for package netlify-cms-backend-gitlab
## [2.1.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.1.0...netlify-cms-backend-gitlab@2.1.1) (2018-12-11)
### Bug Fixes
* **backend-gitlab:** show svg previews ([#1946](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/1946)) ([c3adebe](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/c3adebe))
# [2.1.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.0.6...netlify-cms-backend-gitlab@2.1.0) (2018-11-12)
### Bug Fixes
* **backend-gitlab:** support folder names with whitespace ([#1799](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/1799)) ([a9f69f9](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/a9f69f9))
### Features
* allow custom logo on auth page ([#1818](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/1818)) ([c6ae1e8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/c6ae1e8))
<a name="2.0.6"></a>
## [2.0.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.0.5...netlify-cms-backend-gitlab@2.0.6) (2018-08-27)
**Note:** Version bump only for package netlify-cms-backend-gitlab
<a name="2.0.5"></a>
## [2.0.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.0.4...netlify-cms-backend-gitlab@2.0.5) (2018-08-24)
### Bug Fixes
* **gitlab:** fetch media library images through API ([#1433](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/1433)) ([83d2adc](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/83d2adc))
<a name="2.0.4"></a>
## [2.0.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.0.3...netlify-cms-backend-gitlab@2.0.4) (2018-08-07)
### Bug Fixes
* **backends:** fix commit message handling ([#1568](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/1568)) ([f7e7120](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/f7e7120))
<a name="2.0.3"></a>
## [2.0.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.0.2...netlify-cms-backend-gitlab@2.0.3) (2018-08-01)
### Bug Fixes
* **gitlab:** fix uploads ([#1566](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/issues/1566)) ([d59c990](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/commit/d59c990))
<a name="2.0.2"></a>
## [2.0.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab/compare/netlify-cms-backend-gitlab@2.0.1...netlify-cms-backend-gitlab@2.0.2) (2018-07-28)
**Note:** Version bump only for package netlify-cms-backend-gitlab
<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 netlify-cms-backend-gitlab

View File

@ -1,13 +0,0 @@
# GitLab backend
An abstraction layer between the CMS and [GitLab](https://docs.gitlab.com/ee/api/README.html)
## Code structure
`Implementation` for [File Management System API](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-util/README.md) based on `Api`. With [Editorial Workflow](https://www.netlifycms.org/docs/beta-features/#gitlab-and-bitbucket-editorial-workflow-support) uses merge requests labels to track unpublished entries statuses.
`Api` - A wrapper for GitLab REST API.
`AuthenticationPage` - A component uses [lib-auth](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-auth/README.md) to facilitate OAuth, PKCE and implicit authentication.
Look at tests or types for more info.

View File

@ -1,41 +0,0 @@
{
"name": "netlify-cms-backend-gitlab",
"description": "GitLab backend for Netlify CMS",
"version": "2.13.2",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-gitlab",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"license": "MIT",
"module": "dist/esm/index.js",
"main": "dist/netlify-cms-backend-gitlab.js",
"keywords": [
"netlify",
"netlify-cms",
"backend",
"gitlab"
],
"sideEffects": false,
"scripts": {
"develop": "yarn 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": {
"apollo-cache-inmemory": "^1.6.2",
"apollo-client": "^2.6.3",
"apollo-link-context": "^1.0.18",
"apollo-link-http": "^1.5.15",
"js-base64": "^3.0.0",
"semaphore": "^1.1.0"
},
"peerDependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"immutable": "^3.7.6",
"lodash": "^4.17.11",
"netlify-cms-lib-auth": "^2.3.0",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0"
}
}

View File

@ -1,187 +0,0 @@
import API, { getMaxAccess } from '../API';
global.fetch = jest.fn().mockRejectedValue(new Error('should not call fetch inside tests'));
jest.spyOn(console, 'log').mockImplementation(() => undefined);
describe('GitLab API', () => {
beforeEach(() => {
jest.resetAllMocks();
});
describe('hasWriteAccess', () => {
test('should return true on project access_level >= 30', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest
.fn()
.mockResolvedValueOnce({ permissions: { project_access: { access_level: 30 } } });
await expect(api.hasWriteAccess()).resolves.toBe(true);
});
test('should return false on project access_level < 30', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest
.fn()
.mockResolvedValueOnce({ permissions: { project_access: { access_level: 10 } } });
await expect(api.hasWriteAccess()).resolves.toBe(false);
});
test('should return true on group access_level >= 30', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest
.fn()
.mockResolvedValueOnce({ permissions: { group_access: { access_level: 30 } } });
await expect(api.hasWriteAccess()).resolves.toBe(true);
});
test('should return false on group access_level < 30', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest
.fn()
.mockResolvedValueOnce({ permissions: { group_access: { access_level: 10 } } });
await expect(api.hasWriteAccess()).resolves.toBe(false);
});
test('should return true on shared group access_level >= 40', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest.fn().mockResolvedValueOnce({
permissions: { project_access: null, group_access: null },
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 40 }],
});
await expect(api.hasWriteAccess()).resolves.toBe(true);
expect(api.requestJSON).toHaveBeenCalledTimes(1);
});
test('should return true on shared group access_level >= 30, developers can merge and push', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest.fn();
api.requestJSON.mockResolvedValueOnce({
permissions: { project_access: null, group_access: null },
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
});
api.requestJSON.mockResolvedValueOnce({
developers_can_merge: true,
developers_can_push: true,
});
await expect(api.hasWriteAccess()).resolves.toBe(true);
});
test('should return false on shared group access_level < 30,', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest.fn();
api.requestJSON.mockResolvedValueOnce({
permissions: { project_access: null, group_access: null },
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 20 }],
});
api.requestJSON.mockResolvedValueOnce({
developers_can_merge: true,
developers_can_push: true,
});
await expect(api.hasWriteAccess()).resolves.toBe(false);
});
test("should return false on shared group access_level >= 30, developers can't merge", async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest.fn();
api.requestJSON.mockResolvedValueOnce({
permissions: { project_access: null, group_access: null },
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
});
api.requestJSON.mockResolvedValueOnce({
developers_can_merge: false,
developers_can_push: true,
});
await expect(api.hasWriteAccess()).resolves.toBe(false);
});
test("should return false on shared group access_level >= 30, developers can't push", async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest.fn();
api.requestJSON.mockResolvedValueOnce({
permissions: { project_access: null, group_access: null },
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
});
api.requestJSON.mockResolvedValueOnce({
developers_can_merge: true,
developers_can_push: false,
});
await expect(api.hasWriteAccess()).resolves.toBe(false);
});
test('should return false on shared group access_level >= 30, error getting branch', async () => {
const api = new API({ repo: 'repo' });
api.requestJSON = jest.fn();
api.requestJSON.mockResolvedValueOnce({
permissions: { project_access: null, group_access: null },
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
});
const error = new Error('Not Found');
api.requestJSON.mockRejectedValue(error);
await expect(api.hasWriteAccess()).resolves.toBe(false);
expect(console.log).toHaveBeenCalledTimes(1);
expect(console.log).toHaveBeenCalledWith('Failed getting default branch', error);
});
});
describe('getStatuses', () => {
test('should get preview statuses', async () => {
const api = new API({ repo: 'repo' });
const mr = { sha: 'sha' };
const statuses = [
{ name: 'deploy', status: 'success', target_url: 'deploy-url' },
{ name: 'build', status: 'pending' },
];
api.getBranchMergeRequest = jest.fn(() => Promise.resolve(mr));
api.getMergeRequestStatues = jest.fn(() => Promise.resolve(statuses));
const collectionName = 'posts';
const slug = 'title';
await expect(api.getStatuses(collectionName, slug)).resolves.toEqual([
{ context: 'deploy', state: 'success', target_url: 'deploy-url' },
{ context: 'build', state: 'other' },
]);
expect(api.getBranchMergeRequest).toHaveBeenCalledTimes(1);
expect(api.getBranchMergeRequest).toHaveBeenCalledWith('cms/posts/title');
expect(api.getMergeRequestStatues).toHaveBeenCalledTimes(1);
expect(api.getMergeRequestStatues).toHaveBeenCalledWith(mr, 'cms/posts/title');
});
});
describe('getMaxAccess', () => {
it('should return group with max access level', () => {
const groups = [
{ group_access_level: 10 },
{ group_access_level: 5 },
{ group_access_level: 100 },
{ group_access_level: 1 },
];
expect(getMaxAccess(groups)).toBe(groups[2]);
});
});
});

View File

@ -1,542 +0,0 @@
jest.mock('netlify-cms-core/src/backend');
import { fromJS } from 'immutable';
import { oneLine, stripIndent } from 'common-tags';
import nock from 'nock';
import { Cursor } from 'netlify-cms-lib-util';
import Gitlab from '../implementation';
import AuthenticationPage from '../AuthenticationPage';
const { Backend, LocalStorageAuthStore } = jest.requireActual('netlify-cms-core/src/backend');
function generateEntries(path, length) {
const entries = Array.from({ length }, (val, idx) => {
const count = idx + 1;
const id = `00${count}`.slice(-3);
const fileName = `test${id}.md`;
return { id, fileName, filePath: `${path}/${fileName}` };
});
return {
tree: entries.map(({ id, fileName, filePath }) => ({
id: `d8345753a1d935fa47a26317a503e73e1192d${id}`,
name: fileName,
type: 'blob',
path: filePath,
mode: '100644',
})),
files: entries.reduce(
(acc, { id, filePath }) => ({
...acc,
[filePath]: stripIndent`
---
title: test ${id}
---
# test ${id}
`,
}),
{},
),
};
}
const manyEntries = generateEntries('many-entries', 500);
const mockRepo = {
tree: {
'/': [
{
id: '5d0620ebdbc92068a3e866866e928cc373f18429',
name: 'content',
type: 'tree',
path: 'content',
mode: '040000',
},
],
content: [
{
id: 'b1a200e48be54fde12b636f9563d659d44c206a5',
name: 'test1.md',
type: 'blob',
path: 'content/test1.md',
mode: '100644',
},
{
id: 'd8345753a1d935fa47a26317a503e73e1192d623',
name: 'test2.md',
type: 'blob',
path: 'content/test2.md',
mode: '100644',
},
],
'many-entries': manyEntries.tree,
},
files: {
'content/test1.md': stripIndent`
---
title: test
---
# test
`,
'content/test2.md': stripIndent`
---
title: test2
---
# test 2
`,
...manyEntries.files,
},
};
const resp = {
user: {
success: {
id: 1,
},
},
branch: {
success: {
name: 'master',
commit: {
id: 1,
},
},
},
project: {
success: {
permissions: {
project_access: {
access_level: 30,
},
},
},
readOnly: {
permissions: {
project_access: {
access_level: 10,
},
},
},
},
};
describe('gitlab backend', () => {
let authStore;
let backend;
const repo = 'foo/bar';
const defaultConfig = {
backend: {
name: 'gitlab',
repo,
},
};
const collectionContentConfig = {
name: 'foo',
folder: 'content',
fields: [{ name: 'title' }],
// TODO: folder_based_collection is an internal string, we should not
// be depending on it here
type: 'folder_based_collection',
};
const collectionManyEntriesConfig = {
name: 'foo',
folder: 'many-entries',
fields: [{ name: 'title' }],
// TODO: folder_based_collection is an internal string, we should not
// be depending on it here
type: 'folder_based_collection',
};
const collectionFilesConfig = {
name: 'foo',
files: [
{
label: 'foo',
name: 'foo',
file: 'content/test1.md',
fields: [{ name: 'title' }],
},
{
label: 'bar',
name: 'bar',
file: 'content/test2.md',
fields: [{ name: 'title' }],
},
],
type: 'file_based_collection',
};
const mockCredentials = { token: 'MOCK_TOKEN' };
const expectedRepo = encodeURIComponent(repo);
const expectedRepoUrl = `/projects/${expectedRepo}`;
function resolveBackend(config = {}) {
authStore = new LocalStorageAuthStore();
return new Backend(
{
init: (...args) => new Gitlab(...args),
},
{
backendName: 'gitlab',
config,
authStore,
},
);
}
function mockApi(backend) {
return nock(backend.implementation.apiRoot);
}
function interceptAuth(backend, { userResponse, projectResponse } = {}) {
const api = mockApi(backend);
api
.get('/user')
.query(true)
.reply(200, userResponse || resp.user.success);
api
.get(expectedRepoUrl)
.query(true)
.reply(200, projectResponse || resp.project.success);
}
function interceptBranch(backend, { branch = 'master' } = {}) {
const api = mockApi(backend);
api
.get(`${expectedRepoUrl}/repository/branches/${encodeURIComponent(branch)}`)
.query(true)
.reply(200, resp.branch.success);
}
function parseQuery(uri) {
const query = uri.split('?')[1];
if (!query) {
return {};
}
return query.split('&').reduce((acc, q) => {
const [key, value] = q.split('=');
acc[key] = value;
return acc;
}, {});
}
function createHeaders(backend, { basePath, path, page, perPage, pageCount, totalCount }) {
const pageNum = parseInt(page, 10);
const pageCountNum = parseInt(pageCount, 10);
const url = `${backend.implementation.apiRoot}${basePath}`;
function link(linkPage) {
return `<${url}?id=${expectedRepo}&page=${linkPage}&path=${path}&per_page=${perPage}&recursive=false>`;
}
const linkHeader = oneLine`
${link(1)}; rel="first",
${link(pageCount)}; rel="last",
${pageNum === 1 ? '' : `${link(pageNum - 1)}; rel="prev",`}
${pageNum === pageCountNum ? '' : `${link(pageNum + 1)}; rel="next",`}
`.slice(0, -1);
return {
'X-Page': page,
'X-Total-Pages': pageCount,
'X-Per-Page': perPage,
'X-Total': totalCount,
Link: linkHeader,
};
}
function interceptCollection(
backend,
collection,
{ verb = 'get', repeat = 1, page: expectedPage } = {},
) {
const api = mockApi(backend);
const url = `${expectedRepoUrl}/repository/tree`;
const { folder } = collection;
const tree = mockRepo.tree[folder];
api[verb](url)
.query(({ path, page }) => {
if (path !== folder) {
return false;
}
if (expectedPage && page && parseInt(page, 10) !== parseInt(expectedPage, 10)) {
return false;
}
return true;
})
.times(repeat)
.reply(uri => {
const { page = 1, per_page = 20 } = parseQuery(uri);
const pageCount = tree.length <= per_page ? 1 : Math.round(tree.length / per_page);
const pageLastIndex = page * per_page;
const pageFirstIndex = pageLastIndex - per_page;
const resp = tree.slice(pageFirstIndex, pageLastIndex);
return [
200,
verb === 'head' ? null : resp,
createHeaders(backend, {
basePath: url,
path: folder,
page,
perPage: per_page,
pageCount,
totalCount: tree.length,
}),
];
});
}
function interceptFiles(backend, path) {
const api = mockApi(backend);
const url = `${expectedRepoUrl}/repository/files/${encodeURIComponent(path)}/raw`;
api.get(url).query(true).reply(200, mockRepo.files[path]);
api
.get(`${expectedRepoUrl}/repository/commits`)
.query(({ path }) => path === path)
.reply(200, [
{
author_name: 'author_name',
author_email: 'author_email',
authored_date: 'authored_date',
},
]);
}
function sharedSetup() {
beforeEach(async () => {
backend = resolveBackend(defaultConfig);
interceptAuth(backend);
await backend.authenticate(mockCredentials);
interceptCollection(backend, collectionManyEntriesConfig, { verb: 'head' });
interceptCollection(backend, collectionContentConfig, { verb: 'head' });
});
}
it('throws if configuration does not include repo', () => {
expect(() => resolveBackend({ backend: {} })).toThrowErrorMatchingInlineSnapshot(
`"The GitLab backend needs a \\"repo\\" in the backend configuration."`,
);
});
describe('authComponent', () => {
it('returns authentication page component', () => {
backend = resolveBackend(defaultConfig);
expect(backend.authComponent()).toEqual(AuthenticationPage);
});
});
describe('authenticate', () => {
it('throws if user does not have access to project', async () => {
backend = resolveBackend(defaultConfig);
interceptAuth(backend, { projectResponse: resp.project.readOnly });
await expect(
backend.authenticate(mockCredentials),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Your GitLab user account does not have access to this repo."`,
);
});
it('stores and returns user object on success', async () => {
const backendName = defaultConfig.backend.name;
backend = resolveBackend(defaultConfig);
interceptAuth(backend);
const user = await backend.authenticate(mockCredentials);
expect(authStore.retrieve()).toEqual(user);
expect(user).toEqual({ ...resp.user.success, ...mockCredentials, backendName });
});
});
describe('currentUser', () => {
it('returns null if no user', async () => {
backend = resolveBackend(defaultConfig);
const user = await backend.currentUser();
expect(user).toEqual(null);
});
it('returns the stored user if exists', async () => {
const backendName = defaultConfig.backend.name;
backend = resolveBackend(defaultConfig);
interceptAuth(backend);
await backend.authenticate(mockCredentials);
const user = await backend.currentUser();
expect(user).toEqual({ ...resp.user.success, ...mockCredentials, backendName });
});
});
describe('getToken', () => {
it('returns the token for the current user', async () => {
backend = resolveBackend(defaultConfig);
interceptAuth(backend);
await backend.authenticate(mockCredentials);
const token = await backend.getToken();
expect(token).toEqual(mockCredentials.token);
});
});
describe('logout', () => {
it('sets token to null', async () => {
backend = resolveBackend(defaultConfig);
interceptAuth(backend);
await backend.authenticate(mockCredentials);
await backend.logout();
const token = await backend.getToken();
expect(token).toEqual(null);
});
});
describe('getEntry', () => {
sharedSetup();
it('returns an entry from folder collection', async () => {
const entryTree = mockRepo.tree[collectionContentConfig.folder][0];
const slug = entryTree.path.split('/').pop().replace('.md', '');
interceptFiles(backend, entryTree.path);
interceptCollection(backend, collectionContentConfig);
const entry = await backend.getEntry(
{
config: {},
integrations: fromJS([]),
entryDraft: fromJS({}),
mediaLibrary: fromJS({}),
},
fromJS(collectionContentConfig),
slug,
);
expect(entry).toEqual(expect.objectContaining({ path: entryTree.path }));
});
});
describe('listEntries', () => {
sharedSetup();
it('returns entries from folder collection', async () => {
const tree = mockRepo.tree[collectionContentConfig.folder];
tree.forEach(file => interceptFiles(backend, file.path));
interceptCollection(backend, collectionContentConfig);
const entries = await backend.listEntries(fromJS(collectionContentConfig));
expect(entries).toEqual({
cursor: expect.any(Cursor),
pagination: 1,
entries: expect.arrayContaining(
tree.map(file => expect.objectContaining({ path: file.path })),
),
});
expect(entries.entries).toHaveLength(2);
});
it('returns all entries from folder collection', async () => {
const tree = mockRepo.tree[collectionManyEntriesConfig.folder];
interceptBranch(backend);
tree.forEach(file => interceptFiles(backend, file.path));
interceptCollection(backend, collectionManyEntriesConfig, { repeat: 5 });
const entries = await backend.listAllEntries(fromJS(collectionManyEntriesConfig));
expect(entries).toEqual(
expect.arrayContaining(tree.map(file => expect.objectContaining({ path: file.path }))),
);
expect(entries).toHaveLength(500);
}, 7000);
it('returns entries from file collection', async () => {
const { files } = collectionFilesConfig;
files.forEach(file => interceptFiles(backend, file.file));
const entries = await backend.listEntries(fromJS(collectionFilesConfig));
expect(entries).toEqual({
cursor: expect.any(Cursor),
entries: expect.arrayContaining(
files.map(file => expect.objectContaining({ path: file.file })),
),
});
expect(entries.entries).toHaveLength(2);
});
it('returns first page from paginated folder collection tree', async () => {
const tree = mockRepo.tree[collectionManyEntriesConfig.folder];
const pageTree = tree.slice(0, 20);
pageTree.forEach(file => interceptFiles(backend, file.path));
interceptCollection(backend, collectionManyEntriesConfig, { page: 1 });
const entries = await backend.listEntries(fromJS(collectionManyEntriesConfig));
expect(entries.entries).toEqual(
expect.arrayContaining(pageTree.map(file => expect.objectContaining({ path: file.path }))),
);
expect(entries.entries).toHaveLength(20);
});
});
describe('traverseCursor', () => {
sharedSetup();
it('returns complete last page of paginated tree', async () => {
const tree = mockRepo.tree[collectionManyEntriesConfig.folder];
tree.slice(0, 20).forEach(file => interceptFiles(backend, file.path));
interceptCollection(backend, collectionManyEntriesConfig, { page: 1 });
const entries = await backend.listEntries(fromJS(collectionManyEntriesConfig));
const nextPageTree = tree.slice(20, 40);
nextPageTree.forEach(file => interceptFiles(backend, file.path));
interceptCollection(backend, collectionManyEntriesConfig, { page: 2 });
const nextPage = await backend.traverseCursor(entries.cursor, 'next');
expect(nextPage.entries).toEqual(
expect.arrayContaining(
nextPageTree.map(file => expect.objectContaining({ path: file.path })),
),
);
expect(nextPage.entries).toHaveLength(20);
const lastPageTree = tree.slice(-20);
lastPageTree.forEach(file => interceptFiles(backend, file.path));
interceptCollection(backend, collectionManyEntriesConfig, { page: 25 });
const lastPage = await backend.traverseCursor(nextPage.cursor, 'last');
expect(lastPage.entries).toEqual(
expect.arrayContaining(
lastPageTree.map(file => expect.objectContaining({ path: file.path })),
),
);
expect(lastPage.entries).toHaveLength(20);
});
});
describe('filterFile', () => {
it('should return true for nested file with matching depth', () => {
backend = resolveBackend(defaultConfig);
expect(
backend.implementation.filterFile(
'content/posts',
{ name: 'index.md', path: 'content/posts/dir1/dir2/index.md' },
'md',
3,
),
).toBe(true);
});
it('should return false for nested file with non matching depth', () => {
backend = resolveBackend(defaultConfig);
expect(
backend.implementation.filterFile(
'content/posts',
{ name: 'index.md', path: 'content/posts/dir1/dir2/index.md' },
'md',
2,
),
).toBe(false);
});
});
afterEach(() => {
nock.cleanAll();
authStore.logout();
backend = null;
expect(authStore.retrieve()).toEqual(null);
});
});

View File

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

View File

@ -1,189 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.2.5](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-proxy@1.2.4...netlify-cms-backend-proxy@1.2.5) (2022-09-22)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.2.4](https://github.com/netlify/netlify-cms/compare/netlify-cms-backend-proxy@1.2.3...netlify-cms-backend-proxy@1.2.4) (2022-09-21)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.2.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.2.2...netlify-cms-backend-proxy@1.2.3) (2021-06-01)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.2.2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.2.1...netlify-cms-backend-proxy@1.2.2) (2021-05-31)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.2.1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.2.0...netlify-cms-backend-proxy@1.2.1) (2021-05-19)
**Note:** Version bump only for package netlify-cms-backend-proxy
# [1.2.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.1.7...netlify-cms-backend-proxy@1.2.0) (2021-05-04)
### Features
* added react 17 as peer dependency in packages ([#5316](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/issues/5316)) ([9e42380](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
## [1.1.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.1.6...netlify-cms-backend-proxy@1.1.7) (2021-02-23)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.1.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.1.5...netlify-cms-backend-proxy@1.1.6) (2021-02-10)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.1.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.1.4...netlify-cms-backend-proxy@1.1.5) (2020-09-20)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.1.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.1.3...netlify-cms-backend-proxy@1.1.4) (2020-09-15)
**Note:** Version bump only for package netlify-cms-backend-proxy
## 1.1.3 (2020-09-08)
### Reverts
* Revert "chore(release): publish" ([828bb16](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
## 1.1.2 (2020-08-20)
### Reverts
* Revert "chore(release): publish" ([8262487](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/82624879ccbcb16610090041db28f00714d924c8))
## 1.1.1 (2020-07-27)
### Reverts
* Revert "chore(release): publish" ([118d50a](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/118d50a7a70295f25073e564b5161aa2b9883056))
# [1.1.0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.0.7...netlify-cms-backend-proxy@1.1.0) (2020-06-18)
### Bug Fixes
* handle token expiry ([#3847](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/issues/3847)) ([285c940](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/285c940562548d7bc88de244123ba87ff66fba65))
### Features
* add backend status down indicator ([#3889](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/issues/3889)) ([a50edc7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
## [1.0.7](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.0.6...netlify-cms-backend-proxy@1.0.7) (2020-05-19)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.0.6](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.0.5...netlify-cms-backend-proxy@1.0.6) (2020-04-06)
### Bug Fixes
* **backend-proxy:** fix error reporting ([#3527](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/issues/3527)) ([f94dea3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/f94dea386ce89f0f92744d0c4196416706999ea0))
## [1.0.5](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.0.4...netlify-cms-backend-proxy@1.0.5) (2020-04-01)
**Note:** Version bump only for package netlify-cms-backend-proxy
## [1.0.4](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.0.3...netlify-cms-backend-proxy@1.0.4) (2020-03-03)
### Bug Fixes
* **locale:** Remove hard coded string literals ([#3333](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/issues/3333)) ([7c45a3c](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/7c45a3cda983be427864a56e58791565eb9232e2))
## [1.0.3](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/compare/netlify-cms-backend-proxy@1.0.2...netlify-cms-backend-proxy@1.0.3) (2020-02-06)
### Bug Fixes
* **locale:** remove hard coded strings ([#3193](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/issues/3193)) ([fc91bf8](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy/commit/fc91bf8781e65ce1dc946363dbb10419a145c66b))
## 1.0.2 (2020-01-22)
**Note:** Version bump only for package netlify-cms-backend-proxy

View File

@ -1,9 +0,0 @@
# Proxy backend
Facilitates [local development](https://www.netlifycms.org/docs/beta-features/#working-with-a-local-git-repository).
## Code structure
`Implementation` for [File Management System API](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-lib-util/README.md). An `RPC` wrapper for `netlify-cms-proxy-server`.
`AuthenticationPage` - a mock authentication page

View File

@ -1,29 +0,0 @@
{
"name": "netlify-cms-backend-proxy",
"description": "Proxy backend for Netlify CMS",
"version": "1.2.5",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-proxy",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"license": "MIT",
"module": "dist/esm/index.js",
"main": "dist/netlify-cms-backend-proxy.js",
"keywords": [
"netlify",
"netlify-cms",
"backend"
],
"sideEffects": false,
"scripts": {
"develop": "yarn 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\""
},
"peerDependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0"
}
}

View File

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

View File

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

View File

@ -1,17 +0,0 @@
# Test backend
The backend behind https://cms-demo.netlify.com/.
Used for demo purposes only.
## Code structure
`Implementation` for [File Management System API](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-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

@ -1,31 +0,0 @@
{
"name": "netlify-cms-backend-test",
"description": "Development testing backend for Netlify CMS",
"version": "2.11.5",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-backend-test",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"license": "MIT",
"module": "dist/esm/index.js",
"main": "dist/netlify-cms-backend-test.js",
"keywords": [
"netlify",
"netlify-cms",
"backend"
],
"sideEffects": false,
"scripts": {
"develop": "yarn 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\""
},
"peerDependencies": {
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"lodash": "^4.17.11",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0",
"uuid": "^3.3.2"
}
}

View File

@ -1,266 +0,0 @@
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

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

View File

@ -3,6 +3,198 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.55.59](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.58...netlify-cms-core@2.55.59) (2022-09-29)
**Note:** Version bump only for package netlify-cms-core
## [2.55.58](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.57...netlify-cms-core@2.55.58) (2022-09-28)
**Note:** Version bump only for package netlify-cms-core
## [2.55.57](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.56...netlify-cms-core@2.55.57) (2022-09-28)
**Note:** Version bump only for package netlify-cms-core
## [2.55.56](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.55...netlify-cms-core@2.55.56) (2022-09-28)
**Note:** Version bump only for package netlify-cms-core
## [2.55.55](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.54...netlify-cms-core@2.55.55) (2022-09-28)
**Note:** Version bump only for package netlify-cms-core
## [2.55.54](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.53...netlify-cms-core@2.55.54) (2022-09-28)
**Note:** Version bump only for package netlify-cms-core
## [2.55.53](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.52...netlify-cms-core@2.55.53) (2022-09-28)
**Note:** Version bump only for package netlify-cms-core
## [2.55.52](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.51...netlify-cms-core@2.55.52) (2022-09-27)
**Note:** Version bump only for package netlify-cms-core
## [2.55.51](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.50...netlify-cms-core@2.55.51) (2022-09-27)
**Note:** Version bump only for package netlify-cms-core
## [2.55.50](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.49...netlify-cms-core@2.55.50) (2022-09-27)
**Note:** Version bump only for package netlify-cms-core
## [2.55.49](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.48...netlify-cms-core@2.55.49) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.48](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.47...netlify-cms-core@2.55.48) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.47](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.47...netlify-cms-core@2.55.47) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.47](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.46...netlify-cms-core@2.55.47) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.46](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.45...netlify-cms-core@2.55.46) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.45](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.44...netlify-cms-core@2.55.45) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.44](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.43...netlify-cms-core@2.55.44) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.43](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.42...netlify-cms-core@2.55.43) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.42](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.41...netlify-cms-core@2.55.42) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.41](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.40...netlify-cms-core@2.55.41) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.40](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.39...netlify-cms-core@2.55.40) (2022-09-26)
**Note:** Version bump only for package netlify-cms-core
## [2.55.39](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.38...netlify-cms-core@2.55.39) (2022-09-23)
**Note:** Version bump only for package netlify-cms-core
## [2.55.38](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.37...netlify-cms-core@2.55.38) (2022-09-23)
**Note:** Version bump only for package netlify-cms-core
## [2.55.37](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.36...netlify-cms-core@2.55.37) (2022-09-23)
**Note:** Version bump only for package netlify-cms-core
## [2.55.36](https://github.com/netlify/netlify-cms/compare/netlify-cms-core@2.55.35...netlify-cms-core@2.55.36) (2022-09-22)
**Note:** Version bump only for package netlify-cms-core
@ -2229,7 +2421,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
### Features
* **netlify-cms-widget-relation:** use react-select and add support for multiple entries ([#1936](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/1936)) ([518f6fb](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/518f6fb))
* **relation-widget:** use react-select and add support for multiple entries ([#1936](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/1936)) ([518f6fb](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/518f6fb))
@ -2269,7 +2461,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
* **config:** allow config.yml file load to be skipped ([#2053](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/2053)) ([14f94a0](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/14f94a0))
* **netlify-cms-core:** expose loadEntry action to Widgets ([#2010](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/2010)) ([5d8aef1](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/5d8aef1))
* **netlify-cms-widget-map:** add map widget ([#2051](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/2051)) ([18f34d2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/18f34d2))
* **map-widget:** add map widget ([#2051](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/2051)) ([18f34d2](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/18f34d2))
* **widget-number:** add range validation ([#2049](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/2049)) ([dc44cac](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/dc44cac))
* **workflow:** add deploy preview links ([#2028](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/2028)) ([15d221d](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/15d221d))
@ -2333,7 +2525,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
### Features
* **netlify-cms-widget-select:** add support for multiple selection ([#1901](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/1901)) ([88bf287](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/88bf287))
* **select-widget:** add support for multiple selection ([#1901](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/1901)) ([88bf287](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/88bf287))
* add cloudinary support ([#1932](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/issues/1932)) ([1fc2f50](https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core/commit/1fc2f50))

View File

@ -9,3 +9,76 @@ In the meantime, you can:
site](https://www.netlifycms.org) for more info.
2. Reach out to the [community chat](https://netlifycms.org/chat/) if you need help.
3. Help out and [write the readme yourself](https://github.com/netlify/netlify-cms/edit/master/packages/netlify-cms-core/README.md)!
# Using Core
```tsx
import React from 'react';
import {
AzureBackend,
BitbucketBackend,
BooleanWidget,
CodeWidget,
ColorStringWidget,
DateTimeWidget,
FileWidget,
GitGatewayBackend,
GitHubBackend,
GitLabBackend,
imageEditorComponent,
ImageWidget,
ListWidget,
MapWidget,
MarkdownWidget,
NetlifyCmsCore as CMS,
NumberWidget,
ObjectWidget,
ProxyBackend,
RelationWidget,
SelectWidget,
StringWidget,
TestBackend,
TextWidget,
locales,
Icon,
images
} from 'netlify-cms-core';
// Register all the things
CMS.registerBackend('git-gateway', GitGatewayBackend);
CMS.registerBackend('azure', AzureBackend);
CMS.registerBackend('github', GitHubBackend);
CMS.registerBackend('gitlab', GitLabBackend);
CMS.registerBackend('bitbucket', BitbucketBackend);
CMS.registerBackend('test-repo', TestBackend);
CMS.registerBackend('proxy', ProxyBackend);
CMS.registerWidget([
StringWidget.Widget(),
NumberWidget.Widget(),
TextWidget.Widget(),
ImageWidget.Widget(),
FileWidget.Widget(),
SelectWidget.Widget(),
MarkdownWidget.Widget(),
ListWidget.Widget(),
ObjectWidget.Widget(),
RelationWidget.Widget(),
BooleanWidget.Widget(),
MapWidget.Widget(),
DateTimeWidget.Widget(),
CodeWidget.Widget(),
ColorStringWidget.Widget(),
]);
CMS.registerEditorComponent(imageEditorComponent);
CMS.registerEditorComponent({
id: 'code-block',
label: 'Code Block',
widget: 'code',
type: 'code-block',
});
CMS.registerLocale('en', locales.en);
Object.keys(images).forEach(iconName => {
CMS.registerIcon(iconName, <Icon type={iconName} />);
});
```

View File

@ -1,7 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
declare module 'netlify-cms-core' {
import type { ComponentType, ReactNode } from 'react';
import type { List, Map } from 'immutable';
import type { Iterable as ImmutableIterable, List, Map } from 'immutable';
import type { ComponentType, FocusEventHandler, ReactNode } from 'react';
import type { t } from 'react-polyglot';
import type { Pluggable } from 'unified';
export type CmsBackendType =
@ -298,6 +299,19 @@ declare module 'netlify-cms-core' {
pattern?: string;
}
export type SortDirection = 'Ascending' | 'Descending' | 'None';
export interface CmsSortableFieldsDefault {
field: string;
direction: SortDirection;
}
export interface CmsSortableFields {
default?: CmsSortableFieldsDefault;
fields: string[];
}
export interface CmsCollection {
name: string;
icon?: string;
@ -337,15 +351,10 @@ declare module 'netlify-cms-core' {
path?: string;
media_folder?: string;
public_folder?: string;
sortable_fields?: string[];
sortable_fields?: CmsSortableFields;
view_filters?: ViewFilter[];
view_groups?: ViewGroup[];
i18n?: boolean | CmsI18nConfig;
/**
* @deprecated Use sortable_fields instead
*/
sortableFields?: string[];
}
export interface CmsBackend {
@ -425,7 +434,14 @@ declare module 'netlify-cms-core' {
widget: string;
}
export interface EditorComponentOptions {
export interface EditorComponentWidgetOptions {
id: string;
label: string;
widget: string;
type: string;
}
export interface EditorComponentManualOptions {
id: string;
label: string;
fields: EditorComponentField[];
@ -436,6 +452,8 @@ declare module 'netlify-cms-core' {
toPreview: (data: any) => string;
}
export type EditorComponentOptions = EditorComponentManualOptions | EditorComponentWidgetOptions;
export interface PreviewStyleOptions {
raw: boolean;
}
@ -444,7 +462,7 @@ declare module 'netlify-cms-core' {
value: string;
}
export type CmsBackendClass = any; // TODO: type properly
export type CmsBackendClass = Implementation;
export interface CmsRegistryBackend {
init: (args: any) => CmsBackendClass;
@ -456,6 +474,9 @@ declare module 'netlify-cms-core' {
onChange: (value: T) => void;
forID: string;
classNameWrapper: string;
setActiveStyle: FocusEventHandler;
setInactiveStyle: FocusEventHandler;
t: t;
}
export interface CmsWidgetPreviewProps<T = any> {
@ -471,12 +492,17 @@ declare module 'netlify-cms-core' {
name: string;
controlComponent: CmsWidgetControlProps<T>;
previewComponent?: CmsWidgetPreviewProps<T>;
validator?: (props: {
field: Map<string, any>;
value: T | undefined | null;
t: t;
}) => boolean | { error: any } | Promise<boolean | { error: any }>;
globalStyles?: any;
}
export interface CmsWidget<T = any> {
control: CmsWidgetControlProps<T>;
preview?: CmsWidgetPreviewProps<T>;
control: ComponentType<CmsWidgetControlProps<T>>;
preview?: ComponentType<CmsWidgetPreviewProps<T>>;
globalStyles?: any;
}
@ -547,7 +573,7 @@ declare module 'netlify-cms-core' {
document: Document;
};
export interface CMS {
export interface CMSApi {
getBackend: (name: string) => CmsRegistryBackend | undefined;
getEditorComponents: () => Map<string, ComponentType<any>>;
getRemarkPlugins: () => Array<Pluggable>;
@ -574,7 +600,7 @@ declare module 'netlify-cms-core' {
component: ComponentType<PreviewTemplateComponentProps>,
) => void;
registerWidget: (
widget: string | CmsWidgetParam,
widget: string | CmsWidgetParam | CmsWidgetParam[],
control?: ComponentType<CmsWidgetControlProps> | string,
preview?: ComponentType<CmsWidgetPreviewProps>,
) => void;
@ -584,11 +610,353 @@ declare module 'netlify-cms-core' {
) => void;
registerIcon: (iconName: string, icon: ReactNode) => void;
getIcon: (iconName: string) => ReactNode;
registerAdditionalLink: (id: string, title: string, link: string, iconName?: string) => void;
getAdditionalLinks: () => { title: string, link: string, iconName?: string }[];
registerAdditionalLink: (
id: string,
title: string,
data: string | ComponentType,
iconName?: string,
) => void;
getAdditionalLinks: () => { title: string; data: string | ComponentType; iconName?: string }[];
getAdditionalLink: (
id: string,
) => { title: string; data: string | ComponentType; iconName?: string } | undefined;
}
export const NetlifyCmsCore: CMS;
export const CMS: CMSApi;
export default NetlifyCmsCore;
export default CMS;
// Backends
export type DisplayURLObject = { id: string; path: string };
export type DisplayURL = DisplayURLObject | string;
export type DataFile = {
path: string;
slug: string;
raw: string;
newPath?: string;
};
export type AssetProxy = {
path: string;
fileObj?: File;
toBase64?: () => Promise<string>;
};
export type Entry = {
dataFiles: DataFile[];
assets: AssetProxy[];
};
export type PersistOptions = {
newEntry?: boolean;
commitMessage: string;
collectionName?: string;
useWorkflow?: boolean;
unpublished?: boolean;
status?: string;
};
export type DeleteOptions = {};
export type Credentials = { token: string | {}; refresh_token?: string };
export type User = Credentials & {
backendName?: string;
login?: string;
name: string;
useOpenAuthoring?: boolean;
};
export interface ImplementationEntry {
data: string;
file: { path: string; label?: string; id?: string | null; author?: string; updatedOn?: string };
}
export type ImplementationFile = {
id?: string | null | undefined;
label?: string;
path: string;
};
export interface ImplementationMediaFile {
name: string;
id: string;
size?: number;
displayURL?: DisplayURL;
path: string;
draft?: boolean;
url?: string;
file?: File;
}
export interface UnpublishedEntryMediaFile {
id: string;
path: string;
}
export interface UnpublishedEntryDiff {
id: string;
path: string;
newFile: boolean;
}
export interface UnpublishedEntry {
pullRequestAuthor?: string;
slug: string;
collection: string;
status: string;
diffs: UnpublishedEntryDiff[];
updatedAt: string;
}
export type CursorStoreObject = {
actions: Set<string>;
data: Map<string, unknown>;
meta: Map<string, unknown>;
};
export type CursorStore = {
get<K extends keyof CursorStoreObject>(
key: K,
defaultValue?: CursorStoreObject[K],
): CursorStoreObject[K];
getIn<V>(path: string[]): V;
set<K extends keyof CursorStoreObject, V extends CursorStoreObject[K]>(
key: K,
value: V,
): CursorStoreObject[K];
setIn(path: string[], value: unknown): CursorStore;
hasIn(path: string[]): boolean;
mergeIn(path: string[], value: unknown): CursorStore;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
update: (...args: any[]) => CursorStore;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
updateIn: (...args: any[]) => CursorStore;
};
export type ActionHandler = (action: string) => unknown;
export class Cursor {
static create(...args: {}[]): Cursor;
updateStore(...args: any[]): Cursor;
updateInStore(...args: any[]): Cursor;
hasAction(action: string): boolean;
addAction(action: string): Cursor;
removeAction(action: string): Cursor;
setActions(actions: Iterable<string>): Cursor;
mergeActions(actions: Set<string>): Cursor;
getActionHandlers(handler: ActionHandler): ImmutableIterable<string, unknown>;
setData(data: {}): Cursor;
mergeData(data: {}): Cursor;
wrapData(data: {}): Cursor;
unwrapData(): [Map<string, unknown>, Cursor];
clearData(): Cursor;
setMeta(meta: {}): Cursor;
mergeMeta(meta: {}): Cursor;
}
class Implementation {
authComponent: () => void;
restoreUser: (user: User) => Promise<User>;
authenticate: (credentials: Credentials) => Promise<User>;
logout: () => Promise<void> | void | null;
getToken: () => Promise<string | null>;
getEntry: (path: string) => Promise<ImplementationEntry>;
entriesByFolder: (
folder: string,
extension: string,
depth: number,
) => Promise<ImplementationEntry[]>;
entriesByFiles: (files: ImplementationFile[]) => Promise<ImplementationEntry[]>;
getMediaDisplayURL?: (displayURL: DisplayURL) => Promise<string>;
getMedia: (folder?: string) => Promise<ImplementationMediaFile[]>;
getMediaFile: (path: string) => Promise<ImplementationMediaFile>;
persistEntry: (entry: Entry, opts: PersistOptions) => Promise<void>;
persistMedia: (file: AssetProxy, opts: PersistOptions) => Promise<ImplementationMediaFile>;
deleteFiles: (paths: string[], commitMessage: string) => Promise<void>;
unpublishedEntries: () => Promise<string[]>;
unpublishedEntry: (args: {
id?: string;
collection?: string;
slug?: string;
}) => Promise<UnpublishedEntry>;
unpublishedEntryDataFile: (
collection: string,
slug: string,
path: string,
id: string,
) => Promise<string>;
unpublishedEntryMediaFile: (
collection: string,
slug: string,
path: string,
id: string,
) => Promise<ImplementationMediaFile>;
updateUnpublishedEntryStatus: (
collection: string,
slug: string,
newStatus: string,
) => Promise<void>;
publishUnpublishedEntry: (collection: string, slug: string) => Promise<void>;
deleteUnpublishedEntry: (collection: string, slug: string) => Promise<void>;
getDeployPreview: (
collectionName: string,
slug: string,
) => Promise<{ url: string; status: string } | null>;
allEntriesByFolder?: (
folder: string,
extension: string,
depth: number,
) => Promise<ImplementationEntry[]>;
traverseCursor?: (
cursor: Cursor,
action: string,
) => Promise<{ entries: ImplementationEntry[]; cursor: Cursor }>;
isGitBackend?: () => boolean;
status: () => Promise<{
auth: { status: boolean };
api: { status: boolean; statusPage: string };
}>;
}
export class AzureBackend extends Implementation {}
export class BitbucketBackend extends Implementation {}
export class GitGatewayBackend extends Implementation {}
export class GitHubBackend extends Implementation {}
export class GitLabBackend extends Implementation {}
export class ProxyBackend extends Implementation {}
export class TestBackend extends Implementation {}
// Widgets
export const BooleanWidget: {
Widget: () => CmsWidgetParam<boolean>;
};
export const CodeWidget: {
Widget: () => CmsWidgetParam<any>;
};
export const ColorStringWidget: {
Widget: () => CmsWidgetParam<string>;
};
export const DateTimeWidget: {
Widget: () => CmsWidgetParam<Date | string>;
};
export const FileWidget: {
Widget: () => CmsWidgetParam<string | string[] | List<string>>;
};
export const ImageWidget: {
Widget: () => CmsWidgetParam<string | string[] | List<string>>;
};
export const ListWidget: {
Widget: () => CmsWidgetParam<List<any>>;
};
export const MapWidget: {
Widget: () => CmsWidgetParam<any>;
};
export const MarkdownWidget: {
Widget: () => CmsWidgetParam<string>;
};
export const NumberWidget: {
Widget: () => CmsWidgetParam<string | number>;
};
export const ObjectWidget: {
Widget: () => CmsWidgetParam<Map<string, any> | Record<string, any>>;
};
export const RelationWidget: {
Widget: () => CmsWidgetParam<any>;
};
export const SelectWidget: {
Widget: () => CmsWidgetParam<string | string[]>;
};
export const StringWidget: {
Widget: () => CmsWidgetParam<string>;
};
export const TextWidget: {
Widget: () => CmsWidgetParam<string>;
};
export const MediaLibraryCloudinary: {
name: string;
init: ({
options,
handleInsert,
}?: {
options?: Record<string, any> | undefined;
handleInsert: any;
}) => Promise<{
show: ({
config,
allowMultiple,
}?: {
config?: Record<string, any> | undefined;
allowMultiple: boolean;
}) => any;
hide: () => any;
enableStandalone: () => boolean;
}>;
};
export const MediaLibraryUploadcare: {
name: string;
init: ({
options,
handleInsert,
}?: {
options?:
| {
config: Record<string, any>;
settings: Record<string, any>;
}
| undefined;
handleInsert: any;
}) => Promise<{
show: ({
value,
config,
allowMultiple,
imagesOnly,
}?: {
value: any;
config?: Record<string, any> | undefined;
allowMultiple: boolean;
imagesOnly?: boolean | undefined;
}) => any;
enableStandalone: () => boolean;
}>;
};
export const imageEditorComponent: EditorComponentManualOptions;
export const locales: {
en: Record<string, any>;
};
class NetlifyAuthenticator {
constructor(config: Record<string, any>);
refresh: (args: {
provider: string;
refresh_token: string;
}) => Promise<{ token: string; refresh_token: string }>;
}
export { NetlifyAuthenticator };
// Images
export interface IconProps {
type: string;
direction?: 'right' | 'down' | 'left' | 'up';
size?: string;
className?: string;
}
export const Icon: React.ComponentType<IconProps>;
export const images: Record<string, ReactNode>;
}

View File

@ -1,7 +1,7 @@
{
"name": "netlify-cms-core",
"description": "Netlify CMS core application, see netlify-cms package for the main distribution.",
"version": "2.55.36",
"version": "2.55.59",
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-core",
"bugs": "https://github.com/netlify/netlify-cms/issues",
"module": "dist/esm/index.js",
@ -13,10 +13,10 @@
],
"types": "index.d.ts",
"scripts": {
"develop": "yarn build:esm --watch",
"develop": "webpack serve --hot",
"webpack": "node --max_old_space_size=4096 ../../node_modules/webpack/bin/webpack.js",
"build": "cross-env NODE_ENV=production run-s webpack",
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore \"**/__tests__\" --root-mode upward --extensions \".js,.jsx,.ts,.tsx\""
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore **/__tests__ --root-mode upward --extensions \".js,.jsx,.ts,.tsx\""
},
"keywords": [
"netlify",
@ -25,78 +25,121 @@
],
"license": "MIT",
"dependencies": {
"@iarna/toml": "2.2.5",
"ajv": "8.1.0",
"ajv-errors": "^3.0.0",
"ajv-keywords": "^5.0.0",
"clean-stack": "^4.1.0",
"copy-text-to-clipboard": "^3.0.0",
"deepmerge": "^4.2.2",
"diacritics": "^1.3.0",
"fuzzy": "^0.1.1",
"gotrue-js": "^0.9.24",
"gray-matter": "^4.0.2",
"history": "^4.7.2",
"immer": "^9.0.0",
"js-base64": "^3.0.0",
"jwt-decode": "^3.0.0",
"node-polyglot": "^2.3.0",
"prop-types": "^15.7.2",
"react": "^16.8.4",
"react-dnd": "^14.0.0",
"react-dnd-html5-backend": "^14.0.0",
"react-dom": "^16.8.4",
"react-frame-component": "^5.2.1",
"react-hot-loader": "^4.8.0",
"react-immutable-proptypes": "^2.1.0",
"react-is": "18.2.0",
"react-markdown": "^6.0.2",
"react-modal": "^3.8.1",
"react-polyglot": "^0.7.0",
"react-redux": "^7.2.0",
"react-router-dom": "^5.2.0",
"react-scroll-sync": "^0.9.0",
"react-sortable-hoc": "^2.0.0",
"react-split-pane": "^0.1.85",
"react-topbar-progress-indicator": "^4.0.0",
"react-virtualized-auto-sizer": "^1.0.2",
"react-waypoint": "^10.0.0",
"react-window": "^1.8.5",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"redux-notifications": "^4.0.1",
"redux-thunk": "^2.3.0",
"remark-gfm": "3.0.1",
"sanitize-filename": "^1.6.1",
"semaphore": "^1.0.5",
"tomlify-j0.4": "^3.0.0-alpha.0",
"url": "^0.11.0",
"url-join": "^4.0.1",
"what-input": "^5.1.4",
"yaml": "^1.8.3"
},
"peerDependencies": {
"@emotion/css": "11.10.0",
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"immutable": "^3.7.6",
"lodash": "^4.17.11",
"moment": "^2.24.0",
"netlify-cms-editor-component-image": "^2.6.7",
"netlify-cms-lib-auth": "^2.3.0",
"netlify-cms-lib-util": "^2.12.3",
"netlify-cms-lib-widgets": "^1.6.1",
"netlify-cms-ui-default": "^2.12.1",
"prop-types": "^15.7.2",
"react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0",
"react-immutable-proptypes": "^2.1.0"
"@hot-loader/react-dom": "17.0.2",
"@iarna/toml": "2.2.5",
"@mui/icons-material": "5.10.6",
"@mui/material": "5.10.6",
"@reduxjs/toolkit": "1.8.5",
"ajv": "6.12.6",
"ajv-errors": "1.0.1",
"ajv-keywords": "3.5.2",
"apollo-cache-inmemory": "1.6.6",
"apollo-client": "2.6.10",
"apollo-link-context": "1.0.20",
"apollo-link-http": "1.5.17",
"array-move": "4.0.0",
"clean-stack": "4.2.0",
"codemirror": "5.65.9",
"common-tags": "1.8.1",
"copy-text-to-clipboard": "3.0.1",
"create-react-class": "15.7.0",
"deepmerge": "4.2.2",
"diacritics": "1.3.0",
"dompurify": "2.4.0",
"fuzzy": "0.1.3",
"gotrue-js": "0.9.29",
"graphql": "15.8.0",
"graphql-tag": "2.12.6",
"gray-matter": "4.0.3",
"history": "4.10.1",
"immer": "9.0.15",
"immutable": "3.8.2",
"ini": "2.0.0",
"is-hotkey": "0.2.0",
"js-base64": "3.7.2",
"js-sha256": "0.9.0",
"jwt-decode": "3.1.2",
"localforage": "1.10.0",
"lodash": "4.17.21",
"mdast-util-definitions": "1.2.5",
"mdast-util-to-string": "1.1.0",
"minimatch": "3.0.4",
"moment": "2.29.4",
"node-polyglot": "2.4.2",
"ol": "6.15.1",
"prop-types": "15.8.1",
"react": "17.0.2",
"react-aria-menubutton": "7.0.3",
"react-codemirror2": "7.2.1",
"react-color": "2.19.3",
"react-datetime": "3.1.1",
"react-dnd": "14.0.5",
"react-dnd-html5-backend": "14.1.0",
"react-dom": "17.0.2",
"react-frame-component": "5.2.3",
"react-hot-loader": "4.13.0",
"react-immutable-proptypes": "2.2.0",
"react-is": "18.2.0",
"react-markdown": "6.0.3",
"react-modal": "3.15.1",
"react-polyglot": "0.7.2",
"react-redux": "8.0.4",
"react-router-dom": "5.3.3",
"react-scroll-sync": "0.9.0",
"react-select": "4.3.1",
"react-sortable-hoc": "2.0.0",
"react-split-pane": "0.1.92",
"react-textarea-autosize": "8.3.4",
"react-toggled": "1.2.7",
"react-topbar-progress-indicator": "4.1.1",
"react-transition-group": "4.4.5",
"react-virtualized-auto-sizer": "1.0.7",
"react-waypoint": "10.3.0",
"react-window": "1.8.7",
"rehype-parse": "6.0.2",
"rehype-remark": "8.1.1",
"rehype-stringify": "7.0.0",
"remark-gfm": "3.0.1",
"remark-parse": "6.0.3",
"remark-rehype": "4.0.1",
"remark-stringify": "6.0.4",
"sanitize-filename": "1.6.3",
"semaphore": "1.1.0",
"slate": "0.47.9",
"slate-base64-serializer": "0.2.115",
"slate-plain-serializer": "0.7.13",
"slate-react": "0.22.10",
"slate-soft-break": "0.9.0",
"tomlify-j0.4": "3.0.0",
"unified": "7.1.0",
"unist-builder": "1.0.4",
"unist-util-visit-parents": "2.1.2",
"uploadcare-widget": "3.19.0",
"uploadcare-widget-tab-effects": "1.5.0",
"url": "0.11.0",
"url-join": "4.0.1",
"uuid": "3.4.0",
"validate-color": "2.2.1",
"what-input": "5.2.12",
"what-the-diff": "0.6.0",
"yaml": "1.10.2"
},
"devDependencies": {
"@types/history": "^4.7.8",
"@types/react": "18.0.20",
"@types/history": "4.7.11",
"@types/react": "17.0.50",
"@types/react-dom": "17.0.17",
"@types/react-router-dom": "5.3.3",
"@types/react-scroll-sync": "0.8.4",
"@types/redux-mock-store": "^1.0.2",
"@types/url-join": "^4.0.0",
"redux-mock-store": "^1.5.3"
"@types/url-join": "4.0.1",
"commonmark": "0.30.0",
"commonmark-spec": "0.30.0",
"cross-env": "7.0.3",
"react-svg-loader": "3.0.3",
"slate-hyperscript": "0.13.9",
"webpack": "4.46.0",
"webpack-cli": "4.10.0"
}
}

View File

@ -1,934 +0,0 @@
import { Map, List, fromJS } from 'immutable';
import {
resolveBackend,
Backend,
extractSearchFields,
expandSearchEntries,
mergeExpandedEntries,
} from '../backend';
import { getBackend } from '../lib/registry';
import { FOLDER, FILES } from '../constants/collectionTypes';
jest.mock('../lib/registry');
jest.mock('netlify-cms-lib-util');
jest.mock('../lib/urlHelper');
describe('Backend', () => {
describe('filterEntries', () => {
let backend;
beforeEach(() => {
getBackend.mockReturnValue({
init: jest.fn(),
});
backend = resolveBackend({
backend: {
name: 'git-gateway',
},
});
});
it('filters string values', () => {
const result = backend.filterEntries(
{
entries: [
{
data: {
testField: 'testValue',
},
},
{
data: {
testField: 'testValue2',
},
},
],
},
Map({ field: 'testField', value: 'testValue' }),
);
expect(result.length).toBe(1);
});
it('filters number values', () => {
const result = backend.filterEntries(
{
entries: [
{
data: {
testField: 42,
},
},
{
data: {
testField: 5,
},
},
],
},
Map({ field: 'testField', value: 42 }),
);
expect(result.length).toBe(1);
});
it('filters boolean values', () => {
const result = backend.filterEntries(
{
entries: [
{
data: {
testField: false,
},
},
{
data: {
testField: true,
},
},
],
},
Map({ field: 'testField', value: false }),
);
expect(result.length).toBe(1);
});
it('filters list values', () => {
const result = backend.filterEntries(
{
entries: [
{
data: {
testField: ['valueOne', 'valueTwo', 'testValue'],
},
},
{
data: {
testField: ['valueThree'],
},
},
],
},
Map({ field: 'testField', value: 'testValue' }),
);
expect(result.length).toBe(1);
});
});
describe('getLocalDraftBackup', () => {
const { localForage, asyncLock } = require('netlify-cms-lib-util');
asyncLock.mockImplementation(() => ({ acquire: jest.fn(), release: jest.fn() }));
beforeEach(() => {
jest.clearAllMocks();
});
it('should return empty object on no item', async () => {
const implementation = {
init: jest.fn(() => implementation),
};
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
const collection = Map({
name: 'posts',
});
const slug = 'slug';
localForage.getItem.mockReturnValue();
const result = await backend.getLocalDraftBackup(collection, slug);
expect(result).toEqual({});
expect(localForage.getItem).toHaveBeenCalledTimes(1);
expect(localForage.getItem).toHaveBeenCalledWith('backup.posts.slug');
});
it('should return empty object on item with empty content', async () => {
const implementation = {
init: jest.fn(() => implementation),
};
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
const collection = Map({
name: 'posts',
});
const slug = 'slug';
localForage.getItem.mockReturnValue({ raw: '' });
const result = await backend.getLocalDraftBackup(collection, slug);
expect(result).toEqual({});
expect(localForage.getItem).toHaveBeenCalledTimes(1);
expect(localForage.getItem).toHaveBeenCalledWith('backup.posts.slug');
});
it('should return backup entry, empty media files and assets when only raw property was saved', async () => {
const implementation = {
init: jest.fn(() => implementation),
};
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
const collection = Map({
name: 'posts',
});
const slug = 'slug';
localForage.getItem.mockReturnValue({
raw: '---\ntitle: "Hello World"\n---\n',
});
const result = await backend.getLocalDraftBackup(collection, slug);
expect(result).toEqual({
entry: {
author: '',
mediaFiles: [],
collection: 'posts',
slug: 'slug',
path: '',
partial: false,
raw: '---\ntitle: "Hello World"\n---\n',
data: { title: 'Hello World' },
meta: {},
i18n: {},
label: null,
isModification: null,
status: '',
updatedOn: '',
},
});
expect(localForage.getItem).toHaveBeenCalledTimes(1);
expect(localForage.getItem).toHaveBeenCalledWith('backup.posts.slug');
});
it('should return backup entry, media files and assets when all were backed up', async () => {
const implementation = {
init: jest.fn(() => implementation),
};
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
const collection = Map({
name: 'posts',
});
const slug = 'slug';
localForage.getItem.mockReturnValue({
raw: '---\ntitle: "Hello World"\n---\n',
mediaFiles: [{ id: '1' }],
});
const result = await backend.getLocalDraftBackup(collection, slug);
expect(result).toEqual({
entry: {
author: '',
mediaFiles: [{ id: '1' }],
collection: 'posts',
slug: 'slug',
path: '',
partial: false,
raw: '---\ntitle: "Hello World"\n---\n',
data: { title: 'Hello World' },
meta: {},
i18n: {},
label: null,
isModification: null,
status: '',
updatedOn: '',
},
});
expect(localForage.getItem).toHaveBeenCalledTimes(1);
expect(localForage.getItem).toHaveBeenCalledWith('backup.posts.slug');
});
});
describe('persistLocalDraftBackup', () => {
const { localForage } = require('netlify-cms-lib-util');
beforeEach(() => {
jest.clearAllMocks();
});
it('should not persist empty entry', async () => {
const implementation = {
init: jest.fn(() => implementation),
};
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
backend.entryToRaw = jest.fn().mockReturnValue('');
const collection = Map({
name: 'posts',
});
const slug = 'slug';
const entry = Map({
slug,
});
await backend.persistLocalDraftBackup(entry, collection);
expect(backend.entryToRaw).toHaveBeenCalledTimes(1);
expect(backend.entryToRaw).toHaveBeenCalledWith(collection, entry);
expect(localForage.setItem).toHaveBeenCalledTimes(0);
});
it('should persist non empty entry', async () => {
const implementation = {
init: jest.fn(() => implementation),
};
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
backend.entryToRaw = jest.fn().mockReturnValue('content');
const collection = Map({
name: 'posts',
});
const slug = 'slug';
const entry = Map({
slug,
path: 'content/posts/entry.md',
mediaFiles: List([{ id: '1' }]),
});
await backend.persistLocalDraftBackup(entry, collection);
expect(backend.entryToRaw).toHaveBeenCalledTimes(1);
expect(backend.entryToRaw).toHaveBeenCalledWith(collection, entry);
expect(localForage.setItem).toHaveBeenCalledTimes(2);
expect(localForage.setItem).toHaveBeenCalledWith('backup.posts.slug', {
mediaFiles: [{ id: '1' }],
path: 'content/posts/entry.md',
raw: 'content',
});
expect(localForage.setItem).toHaveBeenCalledWith('backup', 'content');
});
});
describe('persistMedia', () => {
it('should persist media', async () => {
const persistMediaResult = {};
const implementation = {
init: jest.fn(() => implementation),
persistMedia: jest.fn().mockResolvedValue(persistMediaResult),
};
const config = { backend: { name: 'github' } };
const backend = new Backend(implementation, { config, backendName: config.backend.name });
const user = { login: 'login', name: 'name' };
backend.currentUser = jest.fn().mockResolvedValue(user);
const file = { path: 'static/media/image.png' };
const result = await backend.persistMedia(config, file);
expect(result).toBe(persistMediaResult);
expect(implementation.persistMedia).toHaveBeenCalledTimes(1);
expect(implementation.persistMedia).toHaveBeenCalledWith(
{ path: 'static/media/image.png' },
{ commitMessage: 'Upload “static/media/image.png”' },
);
});
});
describe('unpublishedEntry', () => {
it('should return unpublished entry', async () => {
const unpublishedEntryResult = {
diffs: [{ path: 'src/posts/index.md', newFile: false }, { path: 'netlify.png' }],
};
const implementation = {
init: jest.fn(() => implementation),
unpublishedEntry: jest.fn().mockResolvedValue(unpublishedEntryResult),
unpublishedEntryDataFile: jest
.fn()
.mockResolvedValueOnce('---\ntitle: "Hello World"\n---\n'),
unpublishedEntryMediaFile: jest.fn().mockResolvedValueOnce({ id: '1' }),
};
const config = {
media_folder: 'static/images',
};
const backend = new Backend(implementation, { config, backendName: 'github' });
const collection = fromJS({
name: 'posts',
folder: 'src/posts',
fields: [],
});
const state = {
config,
integrations: Map({}),
mediaLibrary: Map({}),
};
const slug = 'slug';
const result = await backend.unpublishedEntry(state, collection, slug);
expect(result).toEqual({
author: '',
collection: 'posts',
slug: '',
path: 'src/posts/index.md',
partial: false,
raw: '---\ntitle: "Hello World"\n---\n',
data: { title: 'Hello World' },
meta: { path: 'src/posts/index.md' },
i18n: {},
label: null,
isModification: true,
mediaFiles: [{ id: '1', draft: true }],
status: '',
updatedOn: '',
});
});
});
describe('generateUniqueSlug', () => {
beforeEach(() => {
jest.resetAllMocks();
});
it("should return unique slug when entry doesn't exist", async () => {
const { sanitizeSlug } = require('../lib/urlHelper');
sanitizeSlug.mockReturnValue('some-post-title');
const implementation = {
init: jest.fn(() => implementation),
getEntry: jest.fn(() => Promise.resolve()),
};
const collection = fromJS({
name: 'posts',
fields: [
{
name: 'title',
},
],
type: FOLDER,
folder: 'posts',
slug: '{{slug}}',
path: 'sub_dir/{{slug}}',
});
const entry = Map({
title: 'some post title',
});
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
await expect(backend.generateUniqueSlug(collection, entry, Map({}), [])).resolves.toBe(
'sub_dir/some-post-title',
);
});
it('should return unique slug when entry exists', async () => {
const { sanitizeSlug, sanitizeChar } = require('../lib/urlHelper');
sanitizeSlug.mockReturnValue('some-post-title');
sanitizeChar.mockReturnValue('-');
const implementation = {
init: jest.fn(() => implementation),
getEntry: jest.fn(),
};
implementation.getEntry.mockResolvedValueOnce({ data: 'data' });
implementation.getEntry.mockResolvedValueOnce();
const collection = fromJS({
name: 'posts',
fields: [
{
name: 'title',
},
],
type: FOLDER,
folder: 'posts',
slug: '{{slug}}',
path: 'sub_dir/{{slug}}',
});
const entry = Map({
title: 'some post title',
});
const backend = new Backend(implementation, { config: {}, backendName: 'github' });
await expect(backend.generateUniqueSlug(collection, entry, Map({}), [])).resolves.toBe(
'sub_dir/some-post-title-1',
);
});
});
describe('extractSearchFields', () => {
it('should extract slug', () => {
expect(extractSearchFields(['slug'])({ slug: 'entry-slug', data: {} })).toEqual(
' entry-slug',
);
});
it('should extract path', () => {
expect(extractSearchFields(['path'])({ path: 'entry-path', data: {} })).toEqual(
' entry-path',
);
});
it('should extract fields', () => {
expect(
extractSearchFields(['title', 'order'])({ data: { title: 'Entry Title', order: 5 } }),
).toEqual(' Entry Title 5');
});
it('should extract nested fields', () => {
expect(
extractSearchFields(['nested.title'])({ data: { nested: { title: 'nested title' } } }),
).toEqual(' nested title');
});
});
describe('search/query', () => {
const collections = [
fromJS({
name: 'posts',
folder: 'posts',
fields: [
{ name: 'title', widget: 'string' },
{ name: 'short_title', widget: 'string' },
{ name: 'author', widget: 'string' },
{ name: 'description', widget: 'string' },
{ name: 'nested', widget: 'object', fields: { name: 'title', widget: 'string' } },
],
}),
fromJS({
name: 'pages',
folder: 'pages',
fields: [
{ name: 'title', widget: 'string' },
{ name: 'short_title', widget: 'string' },
{ name: 'author', widget: 'string' },
{ name: 'description', widget: 'string' },
{ name: 'nested', widget: 'object', fields: { name: 'title', widget: 'string' } },
],
}),
];
const posts = [
{
path: 'posts/find-me.md',
slug: 'find-me',
data: {
title: 'find me by title',
short_title: 'find me by short title',
author: 'find me by author',
description: 'find me by description',
nested: { title: 'find me by nested title' },
},
},
{ path: 'posts/not-me.md', slug: 'not-me', data: { title: 'not me' } },
];
const pages = [
{
path: 'pages/find-me.md',
slug: 'find-me',
data: {
title: 'find me by title',
short_title: 'find me by short title',
author: 'find me by author',
description: 'find me by description',
nested: { title: 'find me by nested title' },
},
},
{ path: 'pages/not-me.md', slug: 'not-me', data: { title: 'not me' } },
];
const files = [
{
path: 'files/file1.md',
slug: 'file1',
data: {
author: 'find me by author',
},
},
{
path: 'files/file2.md',
slug: 'file2',
data: {
other: 'find me by other',
},
},
];
const implementation = {
init: jest.fn(() => implementation),
};
let backend;
beforeEach(() => {
backend = new Backend(implementation, { config: {}, backendName: 'github' });
backend.listAllEntries = jest.fn(collection => {
if (collection.get('name') === 'posts') {
return Promise.resolve(posts);
}
if (collection.get('name') === 'pages') {
return Promise.resolve(pages);
}
if (collection.get('name') === 'files') {
return Promise.resolve(files);
}
return Promise.resolve([]);
});
});
it('should search collections by title', async () => {
const results = await backend.search(collections, 'find me by title');
expect(results).toEqual({
entries: [posts[0], pages[0]],
});
});
it('should search collections by short title', async () => {
const results = await backend.search(collections, 'find me by short title');
expect(results).toEqual({
entries: [posts[0], pages[0]],
});
});
it('should search collections by author', async () => {
const results = await backend.search(collections, 'find me by author');
expect(results).toEqual({
entries: [posts[0], pages[0]],
});
});
it('should search collections by summary description', async () => {
const results = await backend.search(
collections.map(c => c.set('summary', '{{description}}')),
'find me by description',
);
expect(results).toEqual({
entries: [posts[0], pages[0]],
});
});
it('should search in file collection using top level fields', async () => {
const collections = [
fromJS({
name: 'files',
files: [
{
name: 'file1',
fields: [{ name: 'author', widget: 'string' }],
},
{
name: 'file2',
fields: [{ name: 'other', widget: 'string' }],
},
],
type: FILES,
}),
];
expect(await backend.search(collections, 'find me by author')).toEqual({
entries: [files[0]],
});
expect(await backend.search(collections, 'find me by other')).toEqual({
entries: [files[1]],
});
});
it('should query collections by title', async () => {
const results = await backend.query(collections[0], ['title'], 'find me by title');
expect(results).toEqual({
hits: [posts[0]],
query: 'find me by title',
});
});
it('should query collections by slug', async () => {
const results = await backend.query(collections[0], ['slug'], 'find-me');
expect(results).toEqual({
hits: [posts[0]],
query: 'find-me',
});
});
it('should query collections by path', async () => {
const results = await backend.query(collections[0], ['path'], 'posts/find-me.md');
expect(results).toEqual({
hits: [posts[0]],
query: 'posts/find-me.md',
});
});
it('should query collections by nested field', async () => {
const results = await backend.query(
collections[0],
['nested.title'],
'find me by nested title',
);
expect(results).toEqual({
hits: [posts[0]],
query: 'find me by nested title',
});
});
});
describe('expandSearchEntries', () => {
it('should expand entry with list to multiple entries', () => {
const entry = {
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
],
},
},
list: [1, 2],
},
};
expect(expandSearchEntries([entry], ['list.*', 'field.nested.list.*.name'])).toEqual([
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
],
},
},
list: [1, 2],
},
field: 'list.0',
},
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
],
},
},
list: [1, 2],
},
field: 'list.1',
},
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
],
},
},
list: [1, 2],
},
field: 'field.nested.list.0.name',
},
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
],
},
},
list: [1, 2],
},
field: 'field.nested.list.1.name',
},
]);
});
});
describe('mergeExpandedEntries', () => {
it('should merge entries and filter data', () => {
const expanded = [
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
{ id: 3, name: '3' },
{ id: 4, name: '4' },
],
},
},
list: [1, 2],
},
field: 'field.nested.list.0.name',
},
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
{ id: 3, name: '3' },
{ id: 4, name: '4' },
],
},
},
list: [1, 2],
},
field: 'field.nested.list.3.name',
},
];
expect(mergeExpandedEntries(expanded)).toEqual([
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 4, name: '4' },
],
},
},
list: [1, 2],
},
},
]);
});
it('should merge entries and filter data based on different fields', () => {
const expanded = [
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
{ id: 3, name: '3' },
{ id: 4, name: '4' },
],
},
},
list: [1, 2],
},
field: 'field.nested.list.0.name',
},
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
{ id: 3, name: '3' },
{ id: 4, name: '4' },
],
},
},
list: [1, 2],
},
field: 'field.nested.list.3.name',
},
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
{ id: 3, name: '3' },
{ id: 4, name: '4' },
],
},
},
list: [1, 2],
},
field: 'list.1',
},
];
expect(mergeExpandedEntries(expanded)).toEqual([
{
data: {
field: {
nested: {
list: [
{ id: 1, name: '1' },
{ id: 4, name: '4' },
],
},
},
list: [2],
},
},
]);
});
it('should merge entries and keep sort by entry index', () => {
const expanded = [
{
data: {
list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
},
field: 'list.5',
},
{
data: {
list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
},
field: 'list.0',
},
{
data: {
list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
},
field: 'list.11',
},
{
data: {
list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
},
field: 'list.1',
},
];
expect(mergeExpandedEntries(expanded)).toEqual([
{
data: {
list: [5, 0, 11, 1],
},
},
]);
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,224 +0,0 @@
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { fromJS } from 'immutable';
import { addAssets } from '../media';
import * as actions from '../editorialWorkflow';
jest.mock('../../backend');
jest.mock('../../valueObjects/AssetProxy');
jest.mock('netlify-cms-lib-util');
jest.mock('uuid/v4', () => {
return jest.fn().mockReturnValue('000000000000000000000');
});
jest.mock('redux-notifications', () => {
const actual = jest.requireActual('redux-notifications');
return {
...actual,
actions: {
notifSend: jest.fn().mockImplementation(payload => ({
type: 'NOTIF_SEND',
...payload,
})),
},
};
});
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('editorialWorkflow actions', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('loadUnpublishedEntry', () => {
it('should load unpublished entry', () => {
const { currentBackend } = require('../../backend');
const { createAssetProxy } = require('../../valueObjects/AssetProxy');
const assetProxy = { name: 'name', path: 'path' };
const entry = { mediaFiles: [{ file: { name: 'name' }, id: '1', draft: true }] };
const backend = {
unpublishedEntry: jest.fn().mockResolvedValue(entry),
};
const store = mockStore({
config: fromJS({}),
collections: fromJS({
posts: { name: 'posts' },
}),
mediaLibrary: fromJS({
isLoading: false,
}),
editorialWorkflow: fromJS({
pages: { ids: [] },
}),
});
currentBackend.mockReturnValue(backend);
createAssetProxy.mockResolvedValue(assetProxy);
const slug = 'slug';
const collection = store.getState().collections.get('posts');
return store.dispatch(actions.loadUnpublishedEntry(collection, slug)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(4);
expect(actions[0]).toEqual({
type: 'UNPUBLISHED_ENTRY_REQUEST',
payload: {
collection: 'posts',
slug,
},
});
expect(actions[1]).toEqual(addAssets([assetProxy]));
expect(actions[2]).toEqual({
type: 'UNPUBLISHED_ENTRY_SUCCESS',
payload: {
collection: 'posts',
entry: { ...entry, mediaFiles: [{ file: { name: 'name' }, id: '1', draft: true }] },
},
});
expect(actions[3]).toEqual({
type: 'DRAFT_CREATE_FROM_ENTRY',
payload: {
entry,
},
});
});
});
});
describe('publishUnpublishedEntry', () => {
it('should publish unpublished entry and report success', () => {
const { currentBackend } = require('../../backend');
const entry = {};
const backend = {
publishUnpublishedEntry: jest.fn().mockResolvedValue(),
getEntry: jest.fn().mockResolvedValue(entry),
getMedia: jest.fn().mockResolvedValue([]),
};
const store = mockStore({
config: fromJS({}),
integrations: fromJS([]),
mediaLibrary: fromJS({
isLoading: false,
}),
collections: fromJS({
posts: { name: 'posts' },
}),
});
currentBackend.mockReturnValue(backend);
const slug = 'slug';
return store.dispatch(actions.publishUnpublishedEntry('posts', slug)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(8);
expect(actions[0]).toEqual({
type: 'UNPUBLISHED_ENTRY_PUBLISH_REQUEST',
payload: {
collection: 'posts',
slug,
},
});
expect(actions[1]).toEqual({
type: 'MEDIA_LOAD_REQUEST',
payload: {
page: 1,
},
});
expect(actions[2]).toEqual({
type: 'NOTIF_SEND',
message: { key: 'ui.toast.entryPublished' },
kind: 'success',
dismissAfter: 4000,
});
expect(actions[3]).toEqual({
type: 'UNPUBLISHED_ENTRY_PUBLISH_SUCCESS',
payload: {
collection: 'posts',
slug,
},
});
expect(actions[4]).toEqual({
type: 'MEDIA_LOAD_SUCCESS',
payload: {
files: [],
},
});
expect(actions[5]).toEqual({
type: 'ENTRY_REQUEST',
payload: {
slug,
collection: 'posts',
},
});
expect(actions[6]).toEqual({
type: 'ENTRY_SUCCESS',
payload: {
entry,
collection: 'posts',
},
});
expect(actions[7]).toEqual({
type: 'DRAFT_CREATE_FROM_ENTRY',
payload: {
entry,
},
});
});
});
it('should publish unpublished entry and report error', () => {
const { currentBackend } = require('../../backend');
const error = new Error('failed to publish entry');
const backend = {
publishUnpublishedEntry: jest.fn().mockRejectedValue(error),
};
const store = mockStore({
config: fromJS({}),
collections: fromJS({
posts: { name: 'posts' },
}),
});
currentBackend.mockReturnValue(backend);
const slug = 'slug';
return store.dispatch(actions.publishUnpublishedEntry('posts', slug)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(3);
expect(actions[0]).toEqual({
type: 'UNPUBLISHED_ENTRY_PUBLISH_REQUEST',
payload: {
collection: 'posts',
slug,
},
});
expect(actions[1]).toEqual({
type: 'NOTIF_SEND',
message: { key: 'ui.toast.onFailToPublishEntry', details: error },
kind: 'danger',
dismissAfter: 8000,
});
expect(actions[2]).toEqual({
type: 'UNPUBLISHED_ENTRY_PUBLISH_FAILURE',
payload: {
collection: 'posts',
slug,
},
});
});
});
});
});

View File

@ -1,575 +0,0 @@
import { fromJS, Map } from 'immutable';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import {
createEmptyDraft,
createEmptyDraftData,
retrieveLocalBackup,
persistLocalBackup,
getMediaAssets,
validateMetaField,
} from '../entries';
import AssetProxy from '../../valueObjects/AssetProxy';
jest.mock('../../backend');
jest.mock('netlify-cms-lib-util');
jest.mock('../mediaLibrary');
jest.mock('../../reducers/entries');
jest.mock('../../reducers/entryDraft');
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('entries', () => {
describe('createEmptyDraft', () => {
const { currentBackend } = require('../../backend');
const backend = {
processEntry: jest.fn((_state, _collection, entry) => Promise.resolve(entry)),
};
currentBackend.mockReturnValue(backend);
beforeEach(() => {
jest.clearAllMocks();
});
it('should dispatch draft created action', () => {
const store = mockStore({ mediaLibrary: fromJS({ files: [] }) });
const collection = fromJS({
fields: [{ name: 'title' }],
});
return store.dispatch(createEmptyDraft(collection, '')).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(1);
expect(actions[0]).toEqual({
payload: {
author: '',
collection: undefined,
data: {},
meta: {},
i18n: {},
isModification: null,
label: null,
mediaFiles: [],
partial: false,
path: '',
raw: '',
slug: '',
status: '',
updatedOn: '',
},
type: 'DRAFT_CREATE_EMPTY',
});
});
});
it('should populate draft entry from URL param', () => {
const store = mockStore({ mediaLibrary: fromJS({ files: [] }) });
const collection = fromJS({
fields: [{ name: 'title' }, { name: 'boolean' }],
});
return store.dispatch(createEmptyDraft(collection, '?title=title&boolean=True')).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(1);
expect(actions[0]).toEqual({
payload: {
author: '',
collection: undefined,
data: { title: 'title', boolean: true },
meta: {},
i18n: {},
isModification: null,
label: null,
mediaFiles: [],
partial: false,
path: '',
raw: '',
slug: '',
status: '',
updatedOn: '',
},
type: 'DRAFT_CREATE_EMPTY',
});
});
});
it('should html escape URL params', () => {
const store = mockStore({ mediaLibrary: fromJS({ files: [] }) });
const collection = fromJS({
fields: [{ name: 'title' }],
});
return store
.dispatch(createEmptyDraft(collection, "?title=<script>alert('hello')</script>"))
.then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(1);
expect(actions[0]).toEqual({
payload: {
author: '',
collection: undefined,
data: { title: '&lt;script&gt;alert(&#039;hello&#039;)&lt;/script&gt;' },
meta: {},
i18n: {},
isModification: null,
label: null,
mediaFiles: [],
partial: false,
path: '',
raw: '',
slug: '',
status: '',
updatedOn: '',
},
type: 'DRAFT_CREATE_EMPTY',
});
});
});
});
describe('createEmptyDraftData', () => {
it('should allow an empty array as list default for a single field list', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [],
field: { name: 'url', widget: 'text' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({ images: fromJS([]) });
});
it('should allow a complex array as list default for a single field list', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [
{
url: 'https://image.png',
},
],
field: { name: 'url', widget: 'text' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({
images: fromJS([
{
url: 'https://image.png',
},
]),
});
});
it('should allow an empty array as list default for a fields list', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [],
fields: [
{ name: 'title', widget: 'text' },
{ name: 'url', widget: 'text' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({ images: fromJS([]) });
});
it('should allow a complex array as list default for a fields list', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [
{
title: 'default image',
url: 'https://image.png',
},
],
fields: [
{ name: 'title', widget: 'text' },
{ name: 'url', widget: 'text' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({
images: fromJS([
{
title: 'default image',
url: 'https://image.png',
},
]),
});
});
it('should use field default when no list default is provided', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
field: { name: 'url', widget: 'text', default: 'https://image.png' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({ images: [{ url: 'https://image.png' }] });
});
it('should use fields default when no list default is provided', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
fields: [
{ name: 'title', widget: 'text', default: 'default image' },
{ name: 'url', widget: 'text', default: 'https://image.png' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({
images: [{ title: 'default image', url: 'https://image.png' }],
});
});
it('should not set empty value for list fields widget', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
fields: [
{ name: 'title', widget: 'text' },
{ name: 'url', widget: 'text' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({});
});
it('should set default value for object field widget', () => {
const fields = fromJS([
{
name: 'post',
widget: 'object',
field: { name: 'image', widget: 'text', default: 'https://image.png' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({ post: { image: 'https://image.png' } });
});
it('should set default values for object fields widget', () => {
const fields = fromJS([
{
name: 'post',
widget: 'object',
fields: [
{ name: 'title', widget: 'text', default: 'default title' },
{ name: 'url', widget: 'text', default: 'https://image.png' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({
post: { title: 'default title', url: 'https://image.png' },
});
});
it('should not set empty value for object fields widget', () => {
const fields = fromJS([
{
name: 'post',
widget: 'object',
fields: [
{ name: 'title', widget: 'text' },
{ name: 'url', widget: 'text' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({});
});
it('should populate nested fields', () => {
const fields = fromJS([
{
name: 'names',
widget: 'list',
field: {
name: 'object',
widget: 'object',
fields: [
{ name: 'first', widget: 'string', default: 'first' },
{ name: 'second', widget: 'string', default: 'second' },
],
},
},
]);
expect(createEmptyDraftData(fields)).toEqual({
names: [{ object: { first: 'first', second: 'second' } }],
});
});
});
describe('persistLocalBackup', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should persist local backup with media files', () => {
const { currentBackend } = require('../../backend');
const backend = {
persistLocalDraftBackup: jest.fn(() => Promise.resolve()),
};
const store = mockStore({
config: Map(),
});
currentBackend.mockReturnValue(backend);
const collection = Map();
const mediaFiles = [{ path: 'static/media/image.png' }];
const entry = fromJS({ mediaFiles });
return store.dispatch(persistLocalBackup(entry, collection)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(0);
expect(backend.persistLocalDraftBackup).toHaveBeenCalledTimes(1);
expect(backend.persistLocalDraftBackup).toHaveBeenCalledWith(entry, collection);
});
});
});
describe('retrieveLocalBackup', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should retrieve media files with local backup', () => {
const { currentBackend } = require('../../backend');
const { createAssetProxy } = require('../../valueObjects/AssetProxy');
const backend = {
getLocalDraftBackup: jest.fn((...args) => args),
};
const store = mockStore({
config: Map(),
});
currentBackend.mockReturnValue(backend);
const collection = Map({
name: 'collection',
});
const slug = 'slug';
const file = new File([], 'image.png');
const mediaFiles = [{ path: 'static/media/image.png', url: 'url', file }];
const asset = createAssetProxy(mediaFiles[0]);
const entry = { mediaFiles };
backend.getLocalDraftBackup.mockReturnValue({ entry });
return store.dispatch(retrieveLocalBackup(collection, slug)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(2);
expect(actions[0]).toEqual({
type: 'ADD_ASSETS',
payload: [asset],
});
expect(actions[1]).toEqual({
type: 'DRAFT_LOCAL_BACKUP_RETRIEVED',
payload: { entry },
});
});
});
});
describe('getMediaAssets', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should map mediaFiles to assets', () => {
const mediaFiles = fromJS([{ path: 'path1' }, { path: 'path2', draft: true }]);
const entry = Map({ mediaFiles });
expect(getMediaAssets({ entry })).toEqual([new AssetProxy({ path: 'path2' })]);
});
});
describe('validateMetaField', () => {
const state = {
config: {
slug: {
encoding: 'unicode',
clean_accents: false,
sanitize_replacement: '-',
},
},
entries: fromJS([]),
};
const collection = fromJS({
folder: 'folder',
type: 'folder_based_collection',
name: 'name',
});
const t = jest.fn((key, args) => ({ key, args }));
const { selectCustomPath } = require('../../reducers/entryDraft');
const { selectEntryByPath } = require('../../reducers/entries');
beforeEach(() => {
jest.clearAllMocks();
});
it('should not return error on non meta field', () => {
expect(validateMetaField(null, null, fromJS({}), null, t)).toEqual({ error: false });
});
it('should not return error on meta path field', () => {
expect(validateMetaField(null, null, fromJS({ meta: true, name: 'other' }), null, t)).toEqual(
{ error: false },
);
});
it('should return error on empty path', () => {
expect(validateMetaField(null, null, fromJS({ meta: true, name: 'path' }), null, t)).toEqual({
error: {
message: {
key: 'editor.editorControlPane.widget.invalidPath',
args: { path: null },
},
type: 'CUSTOM',
},
});
expect(
validateMetaField(null, null, fromJS({ meta: true, name: 'path' }), undefined, t),
).toEqual({
error: {
message: {
key: 'editor.editorControlPane.widget.invalidPath',
args: { path: undefined },
},
type: 'CUSTOM',
},
});
expect(validateMetaField(null, null, fromJS({ meta: true, name: 'path' }), '', t)).toEqual({
error: {
message: {
key: 'editor.editorControlPane.widget.invalidPath',
args: { path: '' },
},
type: 'CUSTOM',
},
});
});
it('should return error on invalid path', () => {
expect(
validateMetaField(state, null, fromJS({ meta: true, name: 'path' }), 'invalid path', t),
).toEqual({
error: {
message: {
key: 'editor.editorControlPane.widget.invalidPath',
args: { path: 'invalid path' },
},
type: 'CUSTOM',
},
});
});
it('should return error on existing path', () => {
selectCustomPath.mockReturnValue('existing-path');
selectEntryByPath.mockReturnValue(fromJS({ path: 'existing-path' }));
expect(
validateMetaField(
{
...state,
entryDraft: fromJS({
entry: {},
}),
},
collection,
fromJS({ meta: true, name: 'path' }),
'existing-path',
t,
),
).toEqual({
error: {
message: {
key: 'editor.editorControlPane.widget.pathExists',
args: { path: 'existing-path' },
},
type: 'CUSTOM',
},
});
expect(selectCustomPath).toHaveBeenCalledTimes(1);
expect(selectCustomPath).toHaveBeenCalledWith(
collection,
fromJS({ entry: { meta: { path: 'existing-path' } } }),
);
expect(selectEntryByPath).toHaveBeenCalledTimes(1);
expect(selectEntryByPath).toHaveBeenCalledWith(
state.entries,
collection.get('name'),
'existing-path',
);
});
it('should not return error on non existing path for new entry', () => {
selectCustomPath.mockReturnValue('non-existing-path');
selectEntryByPath.mockReturnValue(undefined);
expect(
validateMetaField(
{
...state,
entryDraft: fromJS({
entry: {},
}),
},
collection,
fromJS({ meta: true, name: 'path' }),
'non-existing-path',
t,
),
).toEqual({
error: false,
});
});
it('should not return error when for existing entry', () => {
selectCustomPath.mockReturnValue('existing-path');
selectEntryByPath.mockReturnValue(fromJS({ path: 'existing-path' }));
expect(
validateMetaField(
{
...state,
entryDraft: fromJS({
entry: { path: 'existing-path' },
}),
},
collection,
fromJS({ meta: true, name: 'path' }),
'existing-path',
t,
),
).toEqual({
error: false,
});
});
});
});

View File

@ -1,171 +0,0 @@
import { Map } from 'immutable';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { mocked } from 'ts-jest/utils';
import { getAsset, ADD_ASSET, LOAD_ASSET_REQUEST } from '../media';
import { selectMediaFilePath } from '../../reducers/entries';
import AssetProxy from '../../valueObjects/AssetProxy';
import type { State } from '../../types/redux';
import type { AnyAction } from 'redux';
import type { ThunkDispatch } from 'redux-thunk';
const middlewares = [thunk];
const mockStore = configureMockStore<Partial<State>, ThunkDispatch<State, {}, AnyAction>>(
middlewares,
);
const mockedSelectMediaFilePath = mocked(selectMediaFilePath);
jest.mock('../../reducers/entries');
jest.mock('../mediaLibrary');
describe('media', () => {
const emptyAsset = new AssetProxy({
path: 'empty.svg',
file: new File([`<svg xmlns="http://www.w3.org/2000/svg"></svg>`], 'empty.svg', {
type: 'image/svg+xml',
}),
});
describe('getAsset', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
global.URL = { createObjectURL: jest.fn() };
beforeEach(() => {
jest.resetAllMocks();
});
it('should return empty asset for null path', () => {
const store = mockStore({});
const payload = { collection: null, entryPath: null, entry: null, path: null };
// TODO change to proper payload when immutable is removed
// from 'collections' and 'entries' state slices
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const result = store.dispatch(getAsset(payload));
const actions = store.getActions();
expect(actions).toHaveLength(0);
expect(result).toEqual(emptyAsset);
});
it('should return asset from medias state', () => {
const path = 'static/media/image.png';
const asset = new AssetProxy({ file: new File([], 'empty'), path });
const store = mockStore({
// TODO change to proper store data when immutable is removed
// from 'config' state slice
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
config: Map(),
medias: {
[path]: { asset, isLoading: false, error: null },
},
});
mockedSelectMediaFilePath.mockReturnValue(path);
const payload = { collection: Map(), entry: Map({ path: 'entryPath' }), path };
// TODO change to proper payload when immutable is removed
// from 'collections' and 'entries' state slices
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const result = store.dispatch(getAsset(payload));
const actions = store.getActions();
expect(actions).toHaveLength(0);
expect(result).toBe(asset);
expect(mockedSelectMediaFilePath).toHaveBeenCalledTimes(1);
expect(mockedSelectMediaFilePath).toHaveBeenCalledWith(
store.getState().config,
payload.collection,
payload.entry,
path,
undefined,
);
});
it('should create asset for absolute path when not in medias state', () => {
const path = 'https://asset.netlify.com/image.png';
const asset = new AssetProxy({ url: path, path });
const store = mockStore({
medias: {},
});
mockedSelectMediaFilePath.mockReturnValue(path);
const payload = { collection: null, entryPath: null, path };
// TODO change to proper payload when immutable is removed
// from 'collections' state slice
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const result = store.dispatch(getAsset(payload));
const actions = store.getActions();
expect(actions).toHaveLength(1);
expect(actions[0]).toEqual({
type: ADD_ASSET,
payload: asset,
});
expect(result).toEqual(asset);
});
it('should return empty asset and initiate load when not in medias state', () => {
const path = 'static/media/image.png';
const store = mockStore({
medias: {},
});
mockedSelectMediaFilePath.mockReturnValue(path);
const payload = { path };
// TODO change to proper payload when immutable is removed
// from 'collections' and 'entries' state slices
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const result = store.dispatch(getAsset(payload));
const actions = store.getActions();
expect(actions).toHaveLength(1);
expect(actions[0]).toEqual({
type: LOAD_ASSET_REQUEST,
payload: { path },
});
expect(result).toEqual(emptyAsset);
});
it('should return asset with original path on load error', () => {
const path = 'static/media/image.png';
const resolvePath = 'resolvePath';
const store = mockStore({
medias: {
[resolvePath]: {
asset: undefined,
error: new Error('test'),
isLoading: false,
},
},
});
mockedSelectMediaFilePath.mockReturnValue(resolvePath);
const payload = { path };
// TODO change to proper payload when immutable is removed
// from 'collections' and 'entries' state slices
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const result = store.dispatch(getAsset(payload));
const actions = store.getActions();
const asset = new AssetProxy({ url: path, path: resolvePath });
expect(actions).toHaveLength(1);
expect(actions[0]).toEqual({
type: ADD_ASSET,
payload: asset,
});
expect(result).toEqual(asset);
});
});
});

View File

@ -1,327 +0,0 @@
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { List, Map } from 'immutable';
import { insertMedia, persistMedia, deleteMedia } from '../mediaLibrary';
jest.mock('../../backend');
jest.mock('../waitUntil');
jest.mock('netlify-cms-lib-util', () => {
const lib = jest.requireActual('netlify-cms-lib-util');
return {
...lib,
getBlobSHA: jest.fn(),
};
});
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('mediaLibrary', () => {
describe('insertMedia', () => {
it('should return mediaPath as string when string is given', () => {
const store = mockStore({
config: {
public_folder: '/media',
},
collections: Map({
posts: Map({ name: 'posts' }),
}),
entryDraft: Map({
entry: Map({ isPersisting: false, collection: 'posts' }),
}),
});
store.dispatch(insertMedia('foo.png'));
expect(store.getActions()[0]).toEqual({
type: 'MEDIA_INSERT',
payload: { mediaPath: '/media/foo.png' },
});
});
it('should return mediaPath as array of strings when array of strings is given', () => {
const store = mockStore({
config: {
public_folder: '/media',
},
collections: Map({
posts: Map({ name: 'posts' }),
}),
entryDraft: Map({
entry: Map({ isPersisting: false, collection: 'posts' }),
}),
});
store.dispatch(insertMedia(['foo.png']));
expect(store.getActions()[0]).toEqual({
type: 'MEDIA_INSERT',
payload: { mediaPath: ['/media/foo.png'] },
});
});
});
const { currentBackend } = require('../../backend');
const backend = {
persistMedia: jest.fn(() => ({ id: 'id' })),
deleteMedia: jest.fn(),
};
currentBackend.mockReturnValue(backend);
describe('persistMedia', () => {
global.URL = { createObjectURL: jest.fn().mockReturnValue('displayURL') };
beforeEach(() => {
jest.clearAllMocks();
});
it('should not persist media when editing draft', () => {
const { getBlobSHA } = require('netlify-cms-lib-util');
getBlobSHA.mockReturnValue('000000000000000');
const store = mockStore({
config: {
media_folder: 'static/media',
slug: {
encoding: 'unicode',
clean_accents: false,
sanitize_replacement: '-',
},
},
collections: Map({
posts: Map({ name: 'posts' }),
}),
integrations: Map(),
mediaLibrary: Map({
files: List(),
}),
entryDraft: Map({
entry: Map({ isPersisting: false, collection: 'posts' }),
}),
});
const file = new File([''], 'name.png');
return store.dispatch(persistMedia(file)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(2);
expect(actions[0].type).toEqual('ADD_ASSET');
expect(actions[0].payload).toEqual(
expect.objectContaining({
path: 'static/media/name.png',
}),
);
expect(actions[1].type).toEqual('ADD_DRAFT_ENTRY_MEDIA_FILE');
expect(actions[1].payload).toEqual(
expect.objectContaining({
draft: true,
id: '000000000000000',
path: 'static/media/name.png',
size: file.size,
name: file.name,
}),
);
expect(getBlobSHA).toHaveBeenCalledTimes(1);
expect(getBlobSHA).toHaveBeenCalledWith(file);
expect(backend.persistMedia).toHaveBeenCalledTimes(0);
});
});
it('should persist media when not editing draft', () => {
const store = mockStore({
config: {
media_folder: 'static/media',
slug: {
encoding: 'unicode',
clean_accents: false,
sanitize_replacement: '-',
},
},
collections: Map({
posts: Map({ name: 'posts' }),
}),
integrations: Map(),
mediaLibrary: Map({
files: List(),
}),
entryDraft: Map({
entry: Map(),
}),
});
const file = new File([''], 'name.png');
return store.dispatch(persistMedia(file)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(3);
expect(actions).toHaveLength(3);
expect(actions[0]).toEqual({ type: 'MEDIA_PERSIST_REQUEST' });
expect(actions[1].type).toEqual('ADD_ASSET');
expect(actions[1].payload).toEqual(
expect.objectContaining({
path: 'static/media/name.png',
}),
);
expect(actions[2]).toEqual({
type: 'MEDIA_PERSIST_SUCCESS',
payload: {
file: { id: 'id' },
},
});
expect(backend.persistMedia).toHaveBeenCalledTimes(1);
expect(backend.persistMedia).toHaveBeenCalledWith(
store.getState().config,
expect.objectContaining({
path: 'static/media/name.png',
}),
);
});
});
it('should sanitize media name if needed when persisting', () => {
const store = mockStore({
config: {
media_folder: 'static/media',
slug: {
encoding: 'ascii',
clean_accents: true,
sanitize_replacement: '_',
},
},
collections: Map({
posts: Map({ name: 'posts' }),
}),
integrations: Map(),
mediaLibrary: Map({
files: List(),
}),
entryDraft: Map({
entry: Map(),
}),
});
const file = new File([''], 'abc DEF éâçÖ $;, .png');
return store.dispatch(persistMedia(file)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(3);
expect(actions[0]).toEqual({ type: 'MEDIA_PERSIST_REQUEST' });
expect(actions[1].type).toEqual('ADD_ASSET');
expect(actions[1].payload).toEqual(
expect.objectContaining({
path: 'static/media/abc_def_eaco_.png',
}),
);
expect(actions[2]).toEqual({
type: 'MEDIA_PERSIST_SUCCESS',
payload: {
file: { id: 'id' },
},
});
expect(backend.persistMedia).toHaveBeenCalledTimes(1);
expect(backend.persistMedia).toHaveBeenCalledWith(
store.getState().config,
expect.objectContaining({
path: 'static/media/abc_def_eaco_.png',
}),
);
});
});
});
describe('deleteMedia', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should delete non draft file', () => {
const store = mockStore({
config: {
publish_mode: 'editorial_workflow',
},
collections: Map(),
integrations: Map(),
mediaLibrary: Map({
files: List(),
}),
entryDraft: Map({
entry: Map({ isPersisting: false }),
}),
});
const file = { name: 'name.png', id: 'id', path: 'static/media/name.png', draft: false };
return store.dispatch(deleteMedia(file)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(4);
expect(actions[0]).toEqual({ type: 'MEDIA_DELETE_REQUEST' });
expect(actions[1]).toEqual({
type: 'REMOVE_ASSET',
payload: 'static/media/name.png',
});
expect(actions[2]).toEqual({
type: 'MEDIA_DELETE_SUCCESS',
payload: { file },
});
expect(actions[3]).toEqual({
type: 'REMOVE_DRAFT_ENTRY_MEDIA_FILE',
payload: { id: 'id' },
});
expect(backend.deleteMedia).toHaveBeenCalledTimes(1);
expect(backend.deleteMedia).toHaveBeenCalledWith(
store.getState().config,
'static/media/name.png',
);
});
});
it('should not delete a draft file', () => {
const store = mockStore({
config: {
publish_mode: 'editorial_workflow',
},
collections: Map(),
integrations: Map(),
mediaLibrary: Map({
files: List(),
}),
entryDraft: Map({
entry: Map({ isPersisting: false }),
}),
});
const file = { name: 'name.png', id: 'id', path: 'static/media/name.png', draft: true };
return store.dispatch(deleteMedia(file)).then(() => {
const actions = store.getActions();
expect(actions).toHaveLength(2);
expect(actions[0]).toEqual({
type: 'REMOVE_ASSET',
payload: 'static/media/name.png',
});
expect(actions[1]).toEqual({
type: 'REMOVE_DRAFT_ENTRY_MEDIA_FILE',
payload: { id: 'id' },
});
expect(backend.deleteMedia).toHaveBeenCalledTimes(0);
});
});
});
});

View File

@ -1,209 +0,0 @@
import { fromJS } from 'immutable';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { searchEntries } from '../search';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
jest.mock('../../reducers');
jest.mock('../../backend');
jest.mock('../../integrations');
describe('search', () => {
describe('searchEntries', () => {
const { currentBackend } = require('../../backend');
const { selectIntegration } = require('../../reducers');
const { getIntegrationProvider } = require('../../integrations');
beforeEach(() => {
jest.resetAllMocks();
});
it('should search entries in all collections using integration', async () => {
const store = mockStore({
collections: fromJS({ posts: { name: 'posts' }, pages: { name: 'pages' } }),
search: {},
});
selectIntegration.mockReturnValue('search_integration');
currentBackend.mockReturnValue({});
const response = { entries: [{ name: '1' }, { name: '' }], pagination: 1 };
const integration = { search: jest.fn().mockResolvedValue(response) };
getIntegrationProvider.mockReturnValue(integration);
await store.dispatch(searchEntries('find me'));
const actions = store.getActions();
expect(actions).toHaveLength(2);
expect(actions[0]).toEqual({
type: 'SEARCH_ENTRIES_REQUEST',
payload: {
searchTerm: 'find me',
searchCollections: ['posts', 'pages'],
page: 0,
},
});
expect(actions[1]).toEqual({
type: 'SEARCH_ENTRIES_SUCCESS',
payload: {
entries: response.entries,
page: response.pagination,
},
});
expect(integration.search).toHaveBeenCalledTimes(1);
expect(integration.search).toHaveBeenCalledWith(['posts', 'pages'], 'find me', 0);
});
it('should search entries in a subset of collections using integration', async () => {
const store = mockStore({
collections: fromJS({ posts: { name: 'posts' }, pages: { name: 'pages' } }),
search: {},
});
selectIntegration.mockReturnValue('search_integration');
currentBackend.mockReturnValue({});
const response = { entries: [{ name: '1' }, { name: '' }], pagination: 1 };
const integration = { search: jest.fn().mockResolvedValue(response) };
getIntegrationProvider.mockReturnValue(integration);
await store.dispatch(searchEntries('find me', ['pages']));
const actions = store.getActions();
expect(actions).toHaveLength(2);
expect(actions[0]).toEqual({
type: 'SEARCH_ENTRIES_REQUEST',
payload: {
searchTerm: 'find me',
searchCollections: ['pages'],
page: 0,
},
});
expect(actions[1]).toEqual({
type: 'SEARCH_ENTRIES_SUCCESS',
payload: {
entries: response.entries,
page: response.pagination,
},
});
expect(integration.search).toHaveBeenCalledTimes(1);
expect(integration.search).toHaveBeenCalledWith(['pages'], 'find me', 0);
});
it('should search entries in all collections using backend', async () => {
const store = mockStore({
collections: fromJS({ posts: { name: 'posts' }, pages: { name: 'pages' } }),
search: {},
});
const response = { entries: [{ name: '1' }, { name: '' }], pagination: 1 };
const backend = { search: jest.fn().mockResolvedValue(response) };
currentBackend.mockReturnValue(backend);
await store.dispatch(searchEntries('find me'));
const actions = store.getActions();
expect(actions).toHaveLength(2);
expect(actions[0]).toEqual({
type: 'SEARCH_ENTRIES_REQUEST',
payload: {
searchTerm: 'find me',
searchCollections: ['posts', 'pages'],
page: 0,
},
});
expect(actions[1]).toEqual({
type: 'SEARCH_ENTRIES_SUCCESS',
payload: {
entries: response.entries,
page: response.pagination,
},
});
expect(backend.search).toHaveBeenCalledTimes(1);
expect(backend.search).toHaveBeenCalledWith(
[fromJS({ name: 'posts' }), fromJS({ name: 'pages' })],
'find me',
);
});
it('should search entries in a subset of collections using backend', async () => {
const store = mockStore({
collections: fromJS({ posts: { name: 'posts' }, pages: { name: 'pages' } }),
search: {},
});
const response = { entries: [{ name: '1' }, { name: '' }], pagination: 1 };
const backend = { search: jest.fn().mockResolvedValue(response) };
currentBackend.mockReturnValue(backend);
await store.dispatch(searchEntries('find me', ['pages']));
const actions = store.getActions();
expect(actions).toHaveLength(2);
expect(actions[0]).toEqual({
type: 'SEARCH_ENTRIES_REQUEST',
payload: {
searchTerm: 'find me',
searchCollections: ['pages'],
page: 0,
},
});
expect(actions[1]).toEqual({
type: 'SEARCH_ENTRIES_SUCCESS',
payload: {
entries: response.entries,
page: response.pagination,
},
});
expect(backend.search).toHaveBeenCalledTimes(1);
expect(backend.search).toHaveBeenCalledWith([fromJS({ name: 'pages' })], 'find me');
});
it('should ignore identical search in all collections', async () => {
const store = mockStore({
collections: fromJS({ posts: { name: 'posts' }, pages: { name: 'pages' } }),
search: { isFetching: true, term: 'find me', collections: ['posts', 'pages'] },
});
await store.dispatch(searchEntries('find me'));
const actions = store.getActions();
expect(actions).toHaveLength(0);
});
it('should ignore identical search in a subset of collections', async () => {
const store = mockStore({
collections: fromJS({ posts: { name: 'posts' }, pages: { name: 'pages' } }),
search: { isFetching: true, term: 'find me', collections: ['pages'] },
});
await store.dispatch(searchEntries('find me', ['pages']));
const actions = store.getActions();
expect(actions).toHaveLength(0);
});
it('should not ignore same search term in different search collections', async () => {
const store = mockStore({
collections: fromJS({ posts: { name: 'posts' }, pages: { name: 'pages' } }),
search: { isFetching: true, term: 'find me', collections: ['pages'] },
});
const backend = { search: jest.fn().mockResolvedValue({}) };
currentBackend.mockReturnValue(backend);
await store.dispatch(searchEntries('find me', ['posts', 'pages']));
expect(backend.search).toHaveBeenCalledTimes(1);
expect(backend.search).toHaveBeenCalledWith(
[fromJS({ name: 'posts' }), fromJS({ name: 'pages' })],
'find me',
);
});
});
});

View File

@ -1,13 +1,11 @@
import { actions as notifActions } from 'redux-notifications';
import { currentBackend } from '../backend';
import { addSnackbar } from '../store/slices/snackbars';
import type { Credentials, User } from 'netlify-cms-lib-util';
import type { Credentials, User } from '../lib/util';
import type { ThunkDispatch } from 'redux-thunk';
import type { AnyAction } from 'redux';
import type { State } from '../types/redux';
const { notifSend, notifClear } = notifActions;
import type { t } from 'react-polyglot';
export const AUTH_REQUEST = 'AUTH_REQUEST';
export const AUTH_SUCCESS = 'AUTH_SUCCESS';
@ -96,13 +94,12 @@ export function loginUser(credentials: Credentials) {
.catch((error: Error) => {
console.error(error);
dispatch(
notifSend({
addSnackbar({
type: 'warning',
message: {
details: error.message,
key: 'ui.toast.onFailToAuth',
message: error.message,
},
kind: 'warning',
dismissAfter: 8000,
}),
);
dispatch(authError(error));
@ -116,7 +113,6 @@ export function logoutUser() {
const backend = currentBackend(state.config);
Promise.resolve(backend.logout()).then(() => {
dispatch(logout());
dispatch(notifClear());
});
};
}

View File

@ -14,8 +14,8 @@ import { FILES, FOLDER } from '../constants/collectionTypes';
import type { ThunkDispatch } from 'redux-thunk';
import type { AnyAction } from 'redux';
import type {
CmsCollection,
import type { State } from '../types/redux';
import {
CmsConfig,
CmsField,
CmsFieldBase,
@ -24,8 +24,8 @@ import type {
CmsI18nConfig,
CmsPublishMode,
CmsLocalBackend,
State,
} from '../types/redux';
CmsCollection,
} from '../interface';
export const CONFIG_REQUEST = 'CONFIG_REQUEST';
export const CONFIG_SUCCESS = 'CONFIG_SUCCESS';
@ -64,7 +64,7 @@ function getConfigUrl() {
};
const configLinkEl = document.querySelector<HTMLLinkElement>('link[rel="cms-config-url"]');
if (configLinkEl && validTypes[configLinkEl.type] && configLinkEl.href) {
console.log(`Using config file path: "${configLinkEl.href}"`);
console.info(`Using config file path: "${configLinkEl.href}"`);
return configLinkEl.href;
}
return 'config.yml';
@ -100,7 +100,7 @@ function setSnakeCaseConfig<T extends CmsField>(field: T) {
console.warn(
`Field ${field.name} is using a deprecated configuration '${camel}'. Please use '${snake}'`,
);
return { [snake]: (field as Record<string, unknown>)[camel] };
return { [snake]: (field as unknown as Record<string, unknown>)[camel] };
});
return Object.assign({}, field, ...snakeValues) as T;
@ -189,15 +189,6 @@ export function normalizeConfig(config: CmsConfig) {
normalizedCollection = { ...normalizedCollection, files: normalizedFiles };
}
if (normalizedCollection.sortableFields) {
const { sortableFields, ...rest } = normalizedCollection;
normalizedCollection = { ...rest, sortable_fields: sortableFields };
console.warn(
`Collection ${collection.name} is using a deprecated configuration 'sortableFields'. Please use 'sortable_fields'`,
);
}
return normalizedCollection;
});
@ -332,12 +323,14 @@ export function applyDefaults(originalConfig: CmsConfig) {
}
if (!collection.sortable_fields) {
collection.sortable_fields = selectDefaultSortableFields(
// TODO remove fromJS when Immutable is removed from the collections state slice
fromJS(collection),
backend,
hasIntegration(config, collection),
);
collection.sortable_fields = {
fields: selectDefaultSortableFields(
// TODO remove fromJS when Immutable is removed from the collections state slice
fromJS(collection),
backend,
hasIntegration(config, collection),
),
};
}
collection.view_filters = (view_filters || []).map(filter => {
@ -388,7 +381,7 @@ async function getConfigYaml(file: string, hasManualConfig: boolean) {
const contentType = response.headers.get('Content-Type') || 'Not-Found';
const isYaml = contentType.indexOf('yaml') !== -1;
if (!isYaml) {
console.log(`Response for ${file} was not yaml. (Content-Type: ${contentType})`);
console.info(`Response for ${file} was not yaml. (Content-Type: ${contentType})`);
if (hasManualConfig) {
return {};
}
@ -435,7 +428,7 @@ export async function detectProxyServer(localBackend?: boolean | CmsLocalBackend
: localBackend.url || defaultUrl.replace('localhost', location.hostname);
try {
console.log(`Looking for Netlify CMS Proxy Server at '${proxyUrl}'`);
console.info(`Looking for Netlify CMS Proxy Server at '${proxyUrl}'`);
const res = await fetch(`${proxyUrl}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@ -447,14 +440,14 @@ export async function detectProxyServer(localBackend?: boolean | CmsLocalBackend
type?: string;
};
if (typeof repo === 'string' && Array.isArray(publish_modes) && typeof type === 'string') {
console.log(`Detected Netlify CMS Proxy Server at '${proxyUrl}' with repo: '${repo}'`);
console.info(`Detected Netlify CMS Proxy Server at '${proxyUrl}' with repo: '${repo}'`);
return { proxyUrl, publish_modes, type };
} else {
console.log(`Netlify CMS Proxy Server not detected at '${proxyUrl}'`);
console.info(`Netlify CMS Proxy Server not detected at '${proxyUrl}'`);
return {};
}
} catch {
console.log(`Netlify CMS Proxy Server not detected at '${proxyUrl}'`);
console.info(`Netlify CMS Proxy Server not detected at '${proxyUrl}'`);
return {};
}
}
@ -462,7 +455,7 @@ export async function detectProxyServer(localBackend?: boolean | CmsLocalBackend
function getPublishMode(config: CmsConfig, publishModes?: CmsPublishMode[], backendType?: string) {
if (config.publish_mode && publishModes && !publishModes.includes(config.publish_mode)) {
const newPublishMode = publishModes[0];
console.log(
console.info(
`'${config.publish_mode}' is not supported by '${backendType}' backend, switching to '${newPublishMode}'`,
);
return newPublishMode;
@ -526,7 +519,7 @@ export function loadConfig(manualConfig: Partial<CmsConfig> = {}, onLoad: () =>
if (typeof onLoad === 'function') {
onLoad();
}
} catch (err) {
} catch (err: any) {
dispatch(configFailed(err));
throw err;
}

View File

@ -1,14 +1,12 @@
import { actions as notifActions } from 'redux-notifications';
import { currentBackend } from '../backend';
import { selectDeployPreview } from '../reducers';
import { addSnackbar } from '../store/slices/snackbars';
import type { ThunkDispatch } from 'redux-thunk';
import type { t } from 'react-polyglot';
import type { AnyAction } from 'redux';
import type { ThunkDispatch } from 'redux-thunk';
import type { Collection, Entry, State } from '../types/redux';
const { notifSend } = notifActions;
export const DEPLOY_PREVIEW_REQUEST = 'DEPLOY_PREVIEW_REQUEST';
export const DEPLOY_PREVIEW_SUCCESS = 'DEPLOY_PREVIEW_SUCCESS';
export const DEPLOY_PREVIEW_FAILURE = 'DEPLOY_PREVIEW_FAILURE';
@ -85,16 +83,12 @@ export function loadDeployPreview(
return dispatch(deployPreviewLoaded(collectionName, slug, deploy));
}
return dispatch(deployPreviewError(collectionName, slug));
} catch (error) {
} catch (error: any) {
console.error(error);
dispatch(
notifSend({
message: {
details: error.message,
key: 'ui.toast.onFailToLoadDeployPreview',
},
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onFailToLoadDeployPreview', details: error.message },
}),
);
dispatch(deployPreviewError(collectionName, slug));

View File

@ -1,45 +1,43 @@
import { List, Map } from 'immutable';
import { get } from 'lodash';
import { actions as notifActions } from 'redux-notifications';
import { Map, List } from 'immutable';
import { EDITORIAL_WORKFLOW_ERROR } from 'netlify-cms-lib-util';
import { currentBackend, slugFromCustomPath } from '../backend';
import { EDITORIAL_WORKFLOW, status } from '../constants/publishModes';
import ValidationErrorTypes from '../constants/validationErrorTypes';
import { EDITORIAL_WORKFLOW_ERROR } from '../lib/util';
import {
selectPublishedSlugs,
selectUnpublishedSlugs,
selectEntry,
selectPublishedSlugs,
selectUnpublishedEntry,
selectUnpublishedSlugs,
} from '../reducers';
import { selectEditingDraft } from '../reducers/entries';
import { EDITORIAL_WORKFLOW, status } from '../constants/publishModes';
import { navigateToEntry } from '../routing/history';
import { addSnackbar } from '../store/slices/snackbars';
import { createAssetProxy } from '../valueObjects/AssetProxy';
import {
loadEntry,
createDraftFromEntry,
entryDeleted,
getMediaAssets,
createDraftFromEntry,
loadEntries,
getSerializedEntry,
loadEntries,
loadEntry,
} from './entries';
import { createAssetProxy } from '../valueObjects/AssetProxy';
import { addAssets } from './media';
import { loadMedia } from './mediaLibrary';
import ValidationErrorTypes from '../constants/validationErrorTypes';
import { navigateToEntry } from '../routing/history';
import type { AnyAction } from 'redux';
import type { ThunkDispatch } from 'redux-thunk';
import type { Status } from '../constants/publishModes';
import type {
Collection,
EntryMap,
State,
Collections,
EntryDraft,
EntryMap,
MediaFile,
State,
} from '../types/redux';
import type { AnyAction } from 'redux';
import type { EntryValue } from '../valueObjects/Entry';
import type { Status } from '../constants/publishModes';
import type { ThunkDispatch } from 'redux-thunk';
const { notifSend } = notifActions;
/*
* Constant Declarations
@ -271,19 +269,15 @@ export function loadUnpublishedEntry(collection: Collection, slug: string) {
dispatch(addAssets(assetProxies));
dispatch(unpublishedEntryLoaded(collection, entry));
dispatch(createDraftFromEntry(entry));
} catch (error) {
} catch (error: any) {
if (error.name === EDITORIAL_WORKFLOW_ERROR && error.notUnderEditorialWorkflow) {
dispatch(unpublishedEntryRedirected(collection, slug));
dispatch(loadEntry(collection, slug));
} else {
dispatch(
notifSend({
message: {
key: 'ui.toast.onFailToLoadEntries',
details: error,
},
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onFailToLoadEntries', details: error },
}),
);
}
@ -307,13 +301,9 @@ export function loadUnpublishedEntries(collections: Collections) {
.then(response => dispatch(unpublishedEntriesLoaded(response.entries, response.pagination)))
.catch((error: Error) => {
dispatch(
notifSend({
message: {
key: 'ui.toast.onFailToLoadEntries',
details: error,
},
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onFailToLoadEntries', details: error },
}),
);
dispatch(unpublishedEntriesFailed(error));
@ -343,12 +333,9 @@ export function persistUnpublishedEntry(collection: Collection, existingUnpublis
if (hasPresenceErrors) {
dispatch(
notifSend({
message: {
key: 'ui.toast.missingRequiredField',
},
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: { key: 'ui.toast.missingRequiredField' },
}),
);
}
@ -378,12 +365,9 @@ export function persistUnpublishedEntry(collection: Collection, existingUnpublis
usedSlugs,
});
dispatch(
notifSend({
message: {
key: 'ui.toast.entrySaved',
},
kind: 'success',
dismissAfter: 4000,
addSnackbar({
type: 'success',
message: { key: 'ui.toast.entrySaved' },
}),
);
dispatch(unpublishedEntryPersisted(collection, serializedEntry));
@ -392,15 +376,11 @@ export function persistUnpublishedEntry(collection: Collection, existingUnpublis
dispatch(loadUnpublishedEntry(collection, newSlug));
navigateToEntry(collection.get('name'), newSlug);
}
} catch (error) {
} catch (error: any) {
dispatch(
notifSend({
message: {
key: 'ui.toast.onFailToPersist',
details: error,
},
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onFailToPersist', details: error },
}),
);
return Promise.reject(
@ -425,25 +405,18 @@ export function updateUnpublishedEntryStatus(
.updateUnpublishedEntryStatus(collection, slug, newStatus)
.then(() => {
dispatch(
notifSend({
message: {
key: 'ui.toast.entryUpdated',
},
kind: 'success',
dismissAfter: 4000,
addSnackbar({
type: 'success',
message: { key: 'ui.toast.entryUpdated' },
}),
);
dispatch(unpublishedEntryStatusChangePersisted(collection, slug, newStatus));
})
.catch((error: Error) => {
dispatch(
notifSend({
message: {
key: 'ui.toast.onFailToUpdateStatus',
details: error,
},
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onFailToUpdateStatus', details: error },
}),
);
dispatch(unpublishedEntryStatusChangeError(collection, slug));
@ -460,20 +433,18 @@ export function deleteUnpublishedEntry(collection: string, slug: string) {
.deleteUnpublishedEntry(collection, slug)
.then(() => {
dispatch(
notifSend({
addSnackbar({
type: 'success',
message: { key: 'ui.toast.onDeleteUnpublishedChanges' },
kind: 'success',
dismissAfter: 4000,
}),
);
dispatch(unpublishedEntryDeleted(collection, slug));
})
.catch((error: Error) => {
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onDeleteUnpublishedChanges', details: error },
kind: 'danger',
dismissAfter: 8000,
}),
);
dispatch(unpublishedEntryDeleteError(collection, slug));
@ -493,10 +464,9 @@ export function publishUnpublishedEntry(collectionName: string, slug: string) {
// re-load media after entry was published
dispatch(loadMedia());
dispatch(
notifSend({
addSnackbar({
type: 'success',
message: { key: 'ui.toast.entryPublished' },
kind: 'success',
dismissAfter: 4000,
}),
);
dispatch(unpublishedEntryPublished(collectionName, slug));
@ -513,10 +483,9 @@ export function publishUnpublishedEntry(collectionName: string, slug: string) {
}
} catch (error) {
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onFailToPublishEntry', details: error },
kind: 'danger',
dismissAfter: 8000,
}),
);
dispatch(unpublishedEntryPublishError(collectionName, slug));
@ -548,19 +517,17 @@ export function unpublishPublishedEntry(collection: Collection, slug: string) {
dispatch(entryDeleted(collection, slug));
dispatch(loadUnpublishedEntry(collection, slug));
dispatch(
notifSend({
addSnackbar({
type: 'success',
message: { key: 'ui.toast.entryUnpublished' },
kind: 'success',
dismissAfter: 4000,
}),
);
})
.catch((error: Error) => {
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onFailToUnpublishEntry', details: error },
kind: 'danger',
dismissAfter: 8000,
}),
);
dispatch(unpublishedEntryPersistedFail(error, collection, entry.get('slug')));

View File

@ -1,46 +1,36 @@
import { fromJS, List, Map } from 'immutable';
import { isEqual } from 'lodash';
import { actions as notifActions } from 'redux-notifications';
import { Cursor } from 'netlify-cms-lib-util';
import { selectCollectionEntriesCursor } from '../reducers/cursors';
import { selectFields, updateFieldByKey } from '../reducers/collections';
import { selectIntegration, selectPublishedSlugs } from '../reducers';
import { getIntegrationProvider } from '../integrations';
import { currentBackend } from '../backend';
import { serializeValues } from '../lib/serializeEntryValues';
import { createEntry } from '../valueObjects/Entry';
import { createAssetProxy } from '../valueObjects/AssetProxy';
import ValidationErrorTypes from '../constants/validationErrorTypes';
import { addAssets, getAsset } from './media';
import { SortDirection } from '../types/redux';
import { waitForMediaLibraryToLoad, loadMedia } from './mediaLibrary';
import { waitUntil } from './waitUntil';
import { selectIsFetching, selectEntriesSortFields, selectEntryByPath } from '../reducers/entries';
import { getIntegrationProvider } from '../integrations';
import { SortDirection } from '../interface';
import { getProcessSegment } from '../lib/formatters';
import { duplicateDefaultI18nFields, hasI18n, I18N, I18N_FIELD, serializeI18n } from '../lib/i18n';
import { serializeValues } from '../lib/serializeEntryValues';
import { Cursor } from '../lib/util';
import { selectIntegration, selectPublishedSlugs } from '../reducers';
import { selectFields, updateFieldByKey } from '../reducers/collections';
import { selectCollectionEntriesCursor } from '../reducers/cursors';
import { selectEntriesSortFields, selectEntryByPath, selectIsFetching } from '../reducers/entries';
import { selectCustomPath } from '../reducers/entryDraft';
import { navigateToEntry } from '../routing/history';
import { getProcessSegment } from '../lib/formatters';
import { hasI18n, duplicateDefaultI18nFields, serializeI18n, I18N, I18N_FIELD } from '../lib/i18n';
import { addSnackbar } from '../store/slices/snackbars';
import { createAssetProxy } from '../valueObjects/AssetProxy';
import { createEntry } from '../valueObjects/Entry';
import { addAssets, getAsset } from './media';
import { loadMedia, waitForMediaLibraryToLoad } from './mediaLibrary';
import { waitUntil } from './waitUntil';
import type { ImplementationMediaFile } from 'netlify-cms-lib-util';
import type { Set } from 'immutable';
import type { AnyAction } from 'redux';
import type { ThunkDispatch } from 'redux-thunk';
import type {
Collection,
EntryMap,
State,
EntryFields,
EntryField,
ViewFilter,
ViewGroup,
Entry,
} from '../types/redux';
import type { EntryValue } from '../valueObjects/Entry';
import type { Backend } from '../backend';
import type { ViewFilter, ViewGroup } from '../interface';
import type { ImplementationMediaFile } from '../lib/util';
import type { Collection, Entry, EntryField, EntryFields, EntryMap, State } from '../types/redux';
import type AssetProxy from '../valueObjects/AssetProxy';
import type { Set } from 'immutable';
const { notifSend } = notifActions;
import type { EntryValue } from '../valueObjects/Entry';
/*
* Constant Declarations
@ -534,16 +524,15 @@ export function loadEntry(collection: Collection, slug: string) {
const loadedEntry = await tryLoadEntry(getState(), collection, slug);
dispatch(entryLoaded(collection, loadedEntry));
dispatch(createDraftFromEntry(loadedEntry));
} catch (error) {
} catch (error: any) {
console.error(error);
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: {
details: error.message,
key: 'ui.toast.onFailToLoadEntries',
details: error.message,
},
kind: 'danger',
dismissAfter: 8000,
}),
);
dispatch(entryLoadError(error, collection, slug));
@ -630,15 +619,14 @@ export function loadEntries(collection: Collection, page = 0) {
append,
),
);
} catch (err) {
} catch (err: any) {
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: {
details: err,
key: 'ui.toast.onFailToLoadEntries',
details: err,
},
kind: 'danger',
dismissAfter: 8000,
}),
);
return Promise.reject(dispatch(entriesFailed(collection, err)));
@ -681,16 +669,15 @@ export function traverseCollectionCursor(collection: Collection, action: string)
return dispatch(
entriesLoaded(collection, entries, pagination, addAppendActionsToCursor(newCursor), append),
);
} catch (err) {
} catch (err: any) {
console.error(err);
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: {
details: err,
key: 'ui.toast.onFailToLoadEntries',
details: err,
},
kind: 'danger',
dismissAfter: 8000,
}),
);
return Promise.reject(dispatch(entriesFailed(collection, err)));
@ -894,12 +881,11 @@ export function persistEntry(collection: Collection) {
if (hasPresenceErrors) {
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: {
key: 'ui.toast.missingRequiredField',
},
kind: 'danger',
dismissAfter: 8000,
}),
);
}
@ -926,12 +912,11 @@ export function persistEntry(collection: Collection) {
})
.then(async (newSlug: string) => {
dispatch(
notifSend({
addSnackbar({
type: 'success',
message: {
key: 'ui.toast.entrySaved',
},
kind: 'success',
dismissAfter: 4000,
}),
);
@ -951,13 +936,12 @@ export function persistEntry(collection: Collection) {
.catch((error: Error) => {
console.error(error);
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: {
details: error,
key: 'ui.toast.onFailToPersist',
details: error,
},
kind: 'danger',
dismissAfter: 8000,
}),
);
return Promise.reject(dispatch(entryPersistFail(collection, serializedEntry, error)));
@ -978,13 +962,12 @@ export function deleteEntry(collection: Collection, slug: string) {
})
.catch((error: Error) => {
dispatch(
notifSend({
addSnackbar({
type: 'error',
message: {
details: error,
key: 'ui.toast.onFailToDelete',
details: error,
},
kind: 'danger',
dismissAfter: 8000,
}),
);
console.error(error);

View File

@ -1,5 +1,4 @@
import { isAbsolutePath } from 'netlify-cms-lib-util';
import { isAbsolutePath } from '../lib/util';
import { createAssetProxy } from '../valueObjects/AssetProxy';
import { selectMediaFilePath } from '../reducers/entries';
import { selectMediaFileByPath } from '../reducers/mediaLibrary';
@ -60,7 +59,7 @@ export function loadAsset(resolvedPath: string) {
dispatch(addAsset(asset));
}
dispatch(loadAssetSuccess(resolvedPath));
} catch (e) {
} catch (e: any) {
dispatch(loadAssetFailure(resolvedPath, e));
}
};

View File

@ -1,35 +1,34 @@
import { Map } from 'immutable';
import { actions as notifActions } from 'redux-notifications';
import { basename, getBlobSHA } from 'netlify-cms-lib-util';
import { currentBackend } from '../backend';
import { createAssetProxy } from '../valueObjects/AssetProxy';
import confirm from '../components/UI/Confirm';
import { getIntegrationProvider } from '../integrations';
import { sanitizeSlug } from '../lib/urlHelper';
import { basename, getBlobSHA } from '../lib/util';
import { selectIntegration } from '../reducers';
import {
selectEditingDraft,
selectMediaFilePath,
selectMediaFilePublicPath,
selectEditingDraft,
} from '../reducers/entries';
import { selectMediaDisplayURL, selectMediaFiles } from '../reducers/mediaLibrary';
import { getIntegrationProvider } from '../integrations';
import { addAsset, removeAsset } from './media';
import { addSnackbar } from '../store/slices/snackbars';
import { createAssetProxy } from '../valueObjects/AssetProxy';
import { addDraftEntryMediaFile, removeDraftEntryMediaFile } from './entries';
import { sanitizeSlug } from '../lib/urlHelper';
import { addAsset, removeAsset } from './media';
import { waitUntilWithTimeout } from './waitUntil';
import type {
State,
MediaFile,
DisplayURLState,
MediaLibraryInstance,
EntryField,
} from '../types/redux';
import type { AnyAction } from 'redux';
import type { ThunkDispatch } from 'redux-thunk';
import type { ImplementationMediaFile } from '../lib/util';
import type {
DisplayURLState,
EntryField,
MediaFile,
MediaLibraryInstance,
State,
} from '../types/redux';
import type AssetProxy from '../valueObjects/AssetProxy';
import type { ImplementationMediaFile } from 'netlify-cms-lib-util';
const { notifSend } = notifActions;
export const MEDIA_LIBRARY_OPEN = 'MEDIA_LIBRARY_OPEN';
export const MEDIA_LIBRARY_CLOSE = 'MEDIA_LIBRARY_CLOSE';
@ -169,7 +168,7 @@ export function loadMedia(
.catch((error: { status?: number }) => {
console.error(error);
if (error.status === 404) {
console.log('This 404 was expected and handled appropriately.');
console.info('This 404 was expected and handled appropriately.');
dispatch(mediaLoaded([]));
} else {
dispatch(mediaLoadFailed());
@ -231,7 +230,16 @@ export function persistMedia(file: File, opts: MediaOptions = {}) {
* may not be unique, so we forego this check.
*/
if (!integration && existingFile) {
if (!window.confirm(`${existingFile.name} already exists. Do you want to replace it?`)) {
if (
!(await confirm({
title: 'mediaLibrary.mediaLibrary.alreadyExistsTitle',
body: {
key: 'mediaLibrary.mediaLibrary.alreadyExistsBody',
options: { filename: existingFile.name },
},
color: 'error',
}))
) {
return;
} else {
await dispatch(deleteMedia(existingFile, { privateUpload }));
@ -299,10 +307,12 @@ export function persistMedia(file: File, opts: MediaOptions = {}) {
} catch (error) {
console.error(error);
dispatch(
notifSend({
message: `Failed to persist media: ${error}`,
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: {
key: 'ui.toast.onFailToPersistMedia',
details: error,
},
}),
);
return dispatch(mediaPersistFailed({ privateUpload }));
@ -323,13 +333,15 @@ export function deleteMedia(file: MediaFile, opts: MediaOptions = {}) {
try {
await provider.delete(file.id);
return dispatch(mediaDeleted(file, { privateUpload }));
} catch (error) {
} catch (error: any) {
console.error(error);
dispatch(
notifSend({
message: `Failed to delete media: ${error.message}`,
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: {
key: 'ui.toast.onFailToDeleteMedia',
details: error.message,
},
}),
);
return dispatch(mediaDeleteFailed({ privateUpload }));
@ -353,13 +365,15 @@ export function deleteMedia(file: MediaFile, opts: MediaOptions = {}) {
dispatch(removeDraftEntryMediaFile({ id: file.id }));
}
}
} catch (error) {
} catch (error: any) {
console.error(error);
dispatch(
notifSend({
message: `Failed to delete media: ${error.message}`,
kind: 'danger',
dismissAfter: 8000,
addSnackbar({
type: 'error',
message: {
key: 'ui.toast.onFailToDeleteMedia',
details: error.message,
},
}),
);
return dispatch(mediaDeleteFailed());
@ -401,7 +415,7 @@ export function loadMediaDisplayURL(file: MediaFile) {
} else {
throw new Error('No display URL was returned!');
}
} catch (err) {
} catch (err: any) {
console.error(err);
dispatch(mediaDisplayURLFailure(id, err));
}

View File

@ -1,13 +1,10 @@
import { actions as notifActions } from 'redux-notifications';
import { currentBackend } from '../backend';
import { addSnackbar, removeSnackbarById } from '../store/slices/snackbars';
import type { ThunkDispatch } from 'redux-thunk';
import type { AnyAction } from 'redux';
import type { ThunkDispatch } from 'redux-thunk';
import type { State } from '../types/redux';
const { notifSend, notifDismiss } = notifActions;
export const STATUS_REQUEST = 'STATUS_REQUEST';
export const STATUS_SUCCESS = 'STATUS_SUCCESS';
export const STATUS_FAILURE = 'STATUS_FAILURE';
@ -48,17 +45,16 @@ export function checkBackendStatus() {
const status = await backend.status();
const backendDownKey = 'ui.toast.onBackendDown';
const previousBackendDownNotifs = state.notifs.filter(n => n.message?.key === backendDownKey);
const previousBackendDownNotifs = state.snackbar.messages.filter(
n => n.message?.key === backendDownKey,
);
if (status.api.status === false) {
if (previousBackendDownNotifs.length === 0) {
dispatch(
notifSend({
message: {
details: status.api.statusPage,
key: 'ui.toast.onBackendDown',
},
kind: 'danger',
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onBackendDown', details: status.api.statusPage },
}),
);
}
@ -66,21 +62,19 @@ export function checkBackendStatus() {
} else if (status.api.status === true && previousBackendDownNotifs.length > 0) {
// If backend is up, clear all the danger messages
previousBackendDownNotifs.forEach(notif => {
dispatch(notifDismiss(notif.id));
dispatch(removeSnackbarById(notif.id));
});
}
const authError = status.auth.status === false;
if (authError) {
const key = 'ui.toast.onLoggedOut';
const existingNotification = state.notifs.find(n => n.message?.key === key);
const existingNotification = state.snackbar.messages.find(n => n.message?.key === key);
if (!existingNotification) {
dispatch(
notifSend({
message: {
key: 'ui.toast.onLoggedOut',
},
kind: 'danger',
addSnackbar({
type: 'error',
message: { key: 'ui.toast.onLoggedOut' },
}),
);
}

View File

@ -1,6 +1,6 @@
import { WAIT_UNTIL_ACTION } from '../redux/middleware/waitUntilAction';
import { WAIT_UNTIL_ACTION } from '../store/middleware/waitUntilAction';
import type { WaitActionArgs } from '../redux/middleware/waitUntilAction';
import type { WaitActionArgs } from '../store/middleware/waitUntilAction';
import type { ThunkDispatch } from 'redux-thunk';
import type { AnyAction } from 'redux';
import type { State } from '../types/redux';

View File

@ -1,78 +1,78 @@
import { attempt, flatten, isError, uniq, trim, sortBy, get, set } from 'lodash';
import { List, fromJS, Set } from 'immutable';
import * as fuzzy from 'fuzzy';
import { fromJS, List, Set } from 'immutable';
import { attempt, flatten, get, isError, set, sortBy, trim, uniq } from 'lodash';
import { basename, dirname, extname, join } from 'path';
import { FILES, FOLDER } from './constants/collectionTypes';
import { status } from './constants/publishModes';
import { resolveFormat } from './formats/formats';
import { commitMessageFormatter, previewUrlFormatter, slugFormatter } from './lib/formatters';
import {
localForage,
formatI18nBackup,
getFilePaths,
getI18nBackup,
getI18nDataFiles,
getI18nEntry,
getI18nFiles,
getI18nFilesDepth,
groupEntries,
hasI18n,
} from './lib/i18n';
import { getBackend, invokeEvent } from './lib/registry';
import { sanitizeChar } from './lib/urlHelper';
import {
asyncLock,
blobToFileObj,
Cursor,
CURSOR_COMPATIBILITY_SYMBOL,
getPathDepth,
blobToFileObj,
asyncLock,
EDITORIAL_WORKFLOW_ERROR,
} from 'netlify-cms-lib-util';
import { basename, join, extname, dirname } from 'path';
import { stringTemplate } from 'netlify-cms-lib-widgets';
import { resolveFormat } from './formats/formats';
import { selectUseWorkflow } from './reducers/config';
import { selectMediaFilePath, selectEntry } from './reducers/entries';
import { selectIntegration } from './reducers/integrations';
getPathDepth,
localForage,
} from './lib/util';
import { stringTemplate } from './lib/widgets';
import {
selectEntrySlug,
selectEntryPath,
selectFileEntryLabel,
selectAllowNewEntries,
selectAllowDeletion,
selectAllowNewEntries,
selectEntryPath,
selectEntrySlug,
selectFieldsComments,
selectFileEntryLabel,
selectFolderEntryExtension,
selectHasMetaPath,
selectInferedField,
selectMediaFolders,
selectFieldsComments,
selectHasMetaPath,
} from './reducers/collections';
import { createEntry } from './valueObjects/Entry';
import { sanitizeChar } from './lib/urlHelper';
import { getBackend, invokeEvent } from './lib/registry';
import { commitMessageFormatter, slugFormatter, previewUrlFormatter } from './lib/formatters';
import { status } from './constants/publishModes';
import { FOLDER, FILES } from './constants/collectionTypes';
import { selectUseWorkflow } from './reducers/config';
import { selectEntry, selectMediaFilePath } from './reducers/entries';
import { selectCustomPath } from './reducers/entryDraft';
import {
getI18nFilesDepth,
getI18nFiles,
hasI18n,
getFilePaths,
getI18nEntry,
groupEntries,
getI18nDataFiles,
getI18nBackup,
formatI18nBackup,
} from './lib/i18n';
import { selectIntegration } from './reducers/integrations';
import { createEntry } from './valueObjects/Entry';
import type AssetProxy from './valueObjects/AssetProxy';
import type { Map } from 'immutable';
import type { CmsConfig } from './interface';
import type {
CmsConfig,
AsyncLock,
Credentials,
DataFile,
DisplayURL,
Implementation as BackendImplementation,
ImplementationEntry,
UnpublishedEntry,
UnpublishedEntryDiff,
User,
} from './lib/util';
import type {
Collection,
CollectionFile,
Collections,
EntryDraft,
EntryField,
EntryMap,
FilterRule,
EntryDraft,
Collection,
Collections,
CollectionFile,
State,
EntryField,
} from './types/redux';
import type AssetProxy from './valueObjects/AssetProxy';
import type { EntryValue } from './valueObjects/Entry';
import type {
Implementation as BackendImplementation,
DisplayURL,
ImplementationEntry,
Credentials,
User,
AsyncLock,
UnpublishedEntry,
DataFile,
UnpublishedEntryDiff,
} from 'netlify-cms-lib-util';
import type { Map } from 'immutable';
const { extractTemplateVars, dateParsers, expandPath } = stringTemplate;
@ -399,7 +399,7 @@ export class Backend {
async logout() {
try {
await this.implementation.logout();
} catch (e) {
} catch (e: any) {
console.warn('Error during logout', e.message);
} finally {
this.user = null;

View File

@ -1,5 +1,7 @@
import { Base64 } from 'js-base64';
import { partial, result, trim, trimStart } from 'lodash';
import { dirname, basename } from 'path';
import {
localForage,
APIError,
@ -18,10 +20,9 @@ import {
PreviewState,
readFileMetadata,
branchFromContentKey,
} from 'netlify-cms-lib-util';
import { dirname, basename } from 'path';
} from '../../lib/util';
import type { ApiRequest, AssetProxy, PersistOptions, DataFile } from 'netlify-cms-lib-util';
import type { ApiRequest, AssetProxy, PersistOptions, DataFile } from '../../lib/util';
import type { Map } from 'immutable';
export const API_NAME = 'Azure DevOps';
@ -277,7 +278,7 @@ export default class API {
request = (req: ApiRequest): Promise<Response> => {
try {
return requestWithBackoff(this, req);
} catch (err) {
} catch (err: any) {
throw new APIError(err.message, null, API_NAME);
}
};
@ -377,9 +378,9 @@ export default class API {
name: basename(file.path),
}));
return files;
} catch (err) {
} catch (err: any) {
if (err && err.status === 404) {
console.log('This 404 was expected and handled appropriately.');
console.info('This 404 was expected and handled appropriately.');
return [];
} else {
throw err;

View File

@ -1,8 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { ImplicitAuthenticator } from 'netlify-cms-lib-auth';
import { AuthenticationPage, Icon } from 'netlify-cms-ui-default';
import { AuthenticationPage, Icon } from '../../ui';
import { ImplicitAuthenticator } from '../../lib/auth';
import alert from '../../components/UI/Alert';
const LoginButtonIcon = styled(Icon)`
margin-right: 18px;
@ -32,7 +34,10 @@ export default class AzureAuthenticationPage extends React.Component {
// Complete implicit authentication if we were redirected back to from the provider.
this.auth.completeAuth((err, data) => {
if (err) {
alert(err);
alert({
title: 'auth.errors.authTitle',
body: { key: 'auth.errors.authBody', options: { details: err } },
});
return;
}
this.props.onLogin(data);

View File

@ -1,5 +1,6 @@
import { trimStart, trim } from 'lodash';
import semaphore from 'semaphore';
import {
basename,
getMediaDisplayURL,
@ -15,8 +16,7 @@ import {
entriesByFolder,
contentKeyFromBranch,
getBlobSHA,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
import AuthenticationPage from './AuthenticationPage';
import API, { API_NAME } from './API';
@ -34,7 +34,7 @@ import type {
AsyncLock,
User,
UnpublishedEntryMediaFile,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
const MAX_CONCURRENT_DOWNLOADS = 10;

View File

@ -1,4 +1,8 @@
import { flow, get } from 'lodash';
import { dirname } from 'path';
import { oneLine } from 'common-tags';
import { parse } from 'what-the-diff';
import {
localForage,
unsentRequest,
@ -22,10 +26,7 @@ import {
requestWithBackoff,
readFileMetadata,
throwOnConflictingBranches,
} from 'netlify-cms-lib-util';
import { dirname } from 'path';
import { oneLine } from 'common-tags';
import { parse } from 'what-the-diff';
} from '../../lib/util';
import type {
ApiRequest,
@ -33,7 +34,7 @@ import type {
PersistOptions,
FetchError,
DataFile,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
interface Config {
apiRoot?: string;
@ -192,7 +193,7 @@ const APPLICATION_JSON = 'application/json; charset=utf-8';
function replace404WithEmptyResponse(err: FetchError) {
if (err && err.status === 404) {
console.log('This 404 was expected and handled appropriately.');
console.info('This 404 was expected and handled appropriately.');
return { size: 0, values: [] as BitBucketFile[] } as BitBucketSrcResult;
} else {
return Promise.reject(err);
@ -236,7 +237,7 @@ export default class API {
request = (req: ApiRequest): Promise<Response> => {
try {
return requestWithBackoff(this, req);
} catch (err) {
} catch (err: any) {
throw new APIError(err.message, null, API_NAME);
}
};
@ -345,7 +346,7 @@ export default class API {
url: `${this.repoURL}/commits`,
params: { include: branch, pagelen: 100 },
}).catch(e => {
console.log(`Failed getting commits for branch '${branch}'`, e);
console.info(`Failed getting commits for branch '${branch}'`, e);
return [];
});
@ -493,7 +494,7 @@ export default class API {
method: 'POST',
body: formData,
});
} catch (error) {
} catch (error: any) {
const message = error.message || '';
// very descriptive message from Bitbucket
if (parentSha && message.includes('Something went wrong')) {
@ -681,7 +682,7 @@ export default class API {
}
async listUnpublishedBranches() {
console.log(
console.info(
'%c Checking for Unpublished entries',
'line-height: 30px;text-align: center;font-weight: bold',
);

View File

@ -1,8 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { NetlifyAuthenticator, ImplicitAuthenticator } from 'netlify-cms-lib-auth';
import { AuthenticationPage, Icon } from 'netlify-cms-ui-default';
import { AuthenticationPage, Icon } from '../../ui';
import { NetlifyAuthenticator, ImplicitAuthenticator } from '../../lib/auth';
const LoginButtonIcon = styled(Icon)`
margin-right: 18px;

View File

@ -1,7 +1,8 @@
import minimatch from 'minimatch';
import { unsentRequest } from 'netlify-cms-lib-util';
import type { ApiRequest, PointerFile } from 'netlify-cms-lib-util';
import { unsentRequest } from '../../lib/util';
import type { ApiRequest, PointerFile } from '../../lib/util';
type MakeAuthorizedRequest = (req: ApiRequest) => Promise<Response>;

View File

@ -1,6 +1,7 @@
import semaphore from 'semaphore';
import { trimStart } from 'lodash';
import { stripIndent } from 'common-tags';
import {
CURSOR_COMPATIBILITY_SYMBOL,
filterByExtension,
@ -25,9 +26,8 @@ import {
allEntriesByFolder,
AccessTokenError,
branchFromContentKey,
} from 'netlify-cms-lib-util';
import { NetlifyAuthenticator } from 'netlify-cms-lib-auth';
} from '../../lib/util';
import { NetlifyAuthenticator } from '../../lib/auth';
import AuthenticationPage from './AuthenticationPage';
import API, { API_NAME } from './API';
import { GitLfsClient } from './git-lfs-client';
@ -46,7 +46,7 @@ import type {
ImplementationFile,
AsyncLock,
FetchError,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
import type { Semaphore } from 'semaphore';
const MAX_CONCURRENT_DOWNLOADS = 10;
@ -386,7 +386,7 @@ export default class BitbucketBackend implements Implementation {
.then(attributes => getLargeMediaPatternsFromGitAttributesFile(attributes as string))
.catch((err: FetchError) => {
if (err.status === 404) {
console.log('This 404 was expected and handled appropriately.');
console.info('This 404 was expected and handled appropriately.');
} else {
console.error(err);
}
@ -450,7 +450,7 @@ export default class BitbucketBackend implements Implementation {
async persistMedia(mediaFile: AssetProxy, options: PersistOptions) {
const { fileObj, path } = mediaFile;
const displayURL = URL.createObjectURL(fileObj);
const displayURL = URL.createObjectURL(fileObj as Blob);
const client = await this.getLargeMediaClient();
const fixedPath = path.startsWith('/') ? path.slice(1) : path;
if (!client.enabled || !client.matchPath(fixedPath)) {

View File

@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import styled from '@emotion/styled';
import { partial } from 'lodash';
import {
AuthenticationPage,
buttons,
@ -10,7 +11,7 @@ import {
colorsRaw,
lengths,
zIndex,
} from 'netlify-cms-ui-default';
} from '../../ui';
const LoginButton = styled.button`
${buttons.button};

View File

@ -1,8 +1,8 @@
import { API as GithubAPI } from 'netlify-cms-backend-github';
import { APIError } from 'netlify-cms-lib-util';
import { APIError } from '../../lib/util';
import { API as GithubAPI } from '../github';
import type { Config as GitHubConfig, Diff } from 'netlify-cms-backend-github/src/API';
import type { FetchError } from 'netlify-cms-lib-util';
import type { Config as GitHubConfig, Diff } from '../github/API';
import type { FetchError } from '../../lib/util';
import type { Octokit } from '@octokit/rest';
type Config = GitHubConfig & {

View File

@ -1,8 +1,8 @@
import { API as GitlabAPI } from 'netlify-cms-backend-gitlab';
import { unsentRequest } from 'netlify-cms-lib-util';
import { unsentRequest } from '../../lib/util';
import { API as GitlabAPI } from '../gitlab';
import type { Config as GitLabConfig, CommitAuthor } from 'netlify-cms-backend-gitlab/src/API';
import type { ApiRequest } from 'netlify-cms-lib-util';
import type { Config as GitLabConfig, CommitAuthor } from '../gitlab/API';
import type { ApiRequest } from '../../lib/util';
type Config = GitLabConfig & { tokenPromise: () => Promise<string>; commitAuthor: CommitAuthor };

View File

@ -2,6 +2,7 @@ import GoTrue from 'gotrue-js';
import jwtDecode from 'jwt-decode';
import { get, pick, intersection } from 'lodash';
import ini from 'ini';
import {
APIError,
unsentRequest,
@ -13,11 +14,10 @@ import {
getLargeMediaFilteredMediaFiles,
AccessTokenError,
PreviewState,
} from 'netlify-cms-lib-util';
import { GitHubBackend } from 'netlify-cms-backend-github';
import { GitLabBackend } from 'netlify-cms-backend-gitlab';
import { BitbucketBackend, API as BitBucketAPI } from 'netlify-cms-backend-bitbucket';
} from '../../lib/util';
import { GitHubBackend } from '../github';
import { GitLabBackend } from '../gitlab';
import { BitbucketBackend, API as BitBucketAPI } from '../bitbucket';
import GitHubAPI from './GitHubAPI';
import GitLabAPI from './GitLabAPI';
import AuthenticationPage from './AuthenticationPage';
@ -37,7 +37,7 @@ import type {
Config,
ImplementationFile,
DisplayURLObject,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
const STATUS_PAGE = 'https://www.netlifystatus.com';
const GIT_GATEWAY_STATUS_ENDPOINT = `${STATUS_PAGE}/api/v2/components.json`;
@ -105,7 +105,7 @@ let initPromise = Promise.resolve() as Promise<unknown>;
if (window.netlifyIdentity) {
let initialized = false;
initPromise = Promise.race([
new Promise(resolve => {
new Promise<void>(resolve => {
window.netlifyIdentity?.on('init', () => {
initialized = true;
resolve();
@ -113,7 +113,7 @@ if (window.netlifyIdentity) {
}),
new Promise(resolve => setTimeout(resolve, 2500)).then(() => {
if (!initialized) {
console.log('Manually initializing identity widget');
console.info('Manually initializing identity widget');
window.netlifyIdentity?.init();
}
}),
@ -273,7 +273,7 @@ export default class GitGateway implements Implementation {
const func = user.jwt.bind(user);
const token = await func();
return token;
} catch (error) {
} catch (error: any) {
throw new AccessTokenError(`Failed getting access token: ${error.message}`);
}
};
@ -416,9 +416,10 @@ export default class GitGateway implements Implementation {
if (isLargeMedia) {
const branch = this.backend!.getBranch(collection, slug);
const { url, blob } = await this.getLargeMediaDisplayURL({ path, id }, branch);
const name = basename(path);
return {
id,
name: basename(path),
name,
path,
url,
displayURL: url,
@ -457,7 +458,7 @@ export default class GitGateway implements Implementation {
.then((patterns: string[]) => ({ err: null, patterns }))
.catch((err: Error) => {
if (err.message.includes('404')) {
console.log('This 404 was expected and handled appropriately.');
console.info('This 404 was expected and handled appropriately.');
return { err: null, patterns: [] as string[] };
} else {
return { err, patterns: [] as string[] };
@ -531,9 +532,10 @@ export default class GitGateway implements Implementation {
const isLargeMedia = await this.isLargeMediaFile(path);
if (isLargeMedia) {
const { url, blob } = await this.getLargeMediaDisplayURL({ path, id: null });
const name = basename(path);
return {
id: url,
name: basename(path),
name,
path,
url,
displayURL: url,
@ -556,7 +558,7 @@ export default class GitGateway implements Implementation {
async persistMedia(mediaFile: AssetProxy, options: PersistOptions) {
const { fileObj, path } = mediaFile;
const displayURL = URL.createObjectURL(fileObj);
const displayURL = URL.createObjectURL(fileObj as Blob);
const client = await this.getLargeMediaClient();
const fixedPath = path.startsWith('/') ? path.slice(1) : path;
const isLargeMedia = await this.isLargeMediaFile(fixedPath);

View File

@ -1,9 +1,10 @@
import { flow, fromPairs, map } from 'lodash/fp';
import { isPlainObject, isEmpty } from 'lodash';
import minimatch from 'minimatch';
import { unsentRequest } from 'netlify-cms-lib-util';
import type { ApiRequest, PointerFile } from 'netlify-cms-lib-util';
import { unsentRequest } from '../../lib/util';
import type { ApiRequest, PointerFile } from '../../lib/util';
type MakeAuthorizedRequest = (req: ApiRequest) => Promise<Response>;

View File

@ -1,7 +1,8 @@
import { Base64 } from 'js-base64';
import semaphore from 'semaphore';
import { initial, last, partial, result, trimStart, trim } from 'lodash';
import { oneLine } from 'common-tags';
import { dirname } from 'path';
import {
getAllResponses,
APIError,
@ -23,16 +24,10 @@ import {
requestWithBackoff,
unsentRequest,
throwOnConflictingBranches,
} from 'netlify-cms-lib-util';
import { dirname } from 'path';
} from '../../lib/util';
import alert from '../../components/UI/Alert';
import type {
AssetProxy,
DataFile,
PersistOptions,
FetchError,
ApiRequest,
} from 'netlify-cms-lib-util';
import type { AssetProxy, DataFile, PersistOptions, FetchError, ApiRequest } from '../../lib/util';
import type { Semaphore } from 'semaphore';
import type { Octokit } from '@octokit/rest';
@ -322,7 +317,7 @@ export default class API {
responseStatus = response.status;
const parsedResponse = await parser(response);
return parsedResponse;
} catch (error) {
} catch (error: any) {
return this.handleRequestError(error, responseStatus);
}
}
@ -395,7 +390,7 @@ export default class API {
if (!this._metadataSemaphore) {
this._metadataSemaphore = semaphore(1);
}
return new Promise((resolve, reject) =>
return new Promise<void>((resolve, reject) =>
this._metadataSemaphore?.take(async () => {
try {
const branchData = await this.checkMetadataRef();
@ -422,7 +417,7 @@ export default class API {
if (!this._metadataSemaphore) {
this._metadataSemaphore = semaphore(1);
}
return new Promise(resolve =>
return new Promise<void>(resolve =>
this._metadataSemaphore?.take(async () => {
try {
const branchData = await this.checkMetadataRef();
@ -442,7 +437,7 @@ export default class API {
}
async retrieveMetadataOld(key: string): Promise<Metadata> {
console.log(
console.info(
'%c Checking for MetaData files',
'line-height: 30px;text-align: center;font-weight: bold',
);
@ -454,7 +449,7 @@ export default class API {
function errorHandler(err: Error) {
if (err.message === 'Not Found') {
console.log(
console.info(
'%c %s does not have metadata',
'line-height: 30px;text-align: center;font-weight: bold',
key,
@ -565,7 +560,7 @@ export default class API {
);
return commits;
} catch (e) {
console.log(e);
console.info(e);
return [];
}
}
@ -696,9 +691,9 @@ export default class API {
size: file.size!,
}))
);
} catch (err) {
} catch (err: any) {
if (err && err.status === 404) {
console.log('This 404 was expected and handled appropriately.');
console.info('This 404 was expected and handled appropriately.');
return [];
} else {
throw err;
@ -771,40 +766,40 @@ export default class API {
async migratePullRequest(pullRequest: GitHubPull, countMessage: string) {
const { number } = pullRequest;
console.log(`Migrating Pull Request '${number}' (${countMessage})`);
console.info(`Migrating Pull Request '${number}' (${countMessage})`);
const contentKey = contentKeyFromBranch(pullRequest.head.ref);
let metadata = await this.retrieveMetadataOld(contentKey).catch(() => undefined);
if (!metadata) {
console.log(`Skipped migrating Pull Request '${number}' (${countMessage})`);
console.info(`Skipped migrating Pull Request '${number}' (${countMessage})`);
return;
}
let newNumber = number;
if (!metadata.version) {
console.log(`Migrating Pull Request '${number}' to version 1`);
console.info(`Migrating Pull Request '${number}' to version 1`);
// migrate branch from cms/slug to cms/collection/slug
try {
({ metadata, pullRequest } = await this.migrateToVersion1(pullRequest, metadata));
} catch (e) {
console.log(`Failed to migrate Pull Request '${number}' to version 1. See error below.`);
console.info(`Failed to migrate Pull Request '${number}' to version 1. See error below.`);
console.error(e);
return;
}
newNumber = pullRequest.number;
console.log(
console.info(
`Done migrating Pull Request '${number}' to version 1. New pull request '${newNumber}' created.`,
);
}
if (metadata.version === '1') {
console.log(`Migrating Pull Request '${newNumber}' to labels`);
console.info(`Migrating Pull Request '${newNumber}' to labels`);
// migrate branch from using orphan ref to store metadata to pull requests label
await this.migrateToPullRequestLabels(pullRequest, metadata);
console.log(`Done migrating Pull Request '${newNumber}' to labels`);
console.info(`Done migrating Pull Request '${newNumber}' to labels`);
}
console.log(
console.info(
`Done migrating Pull Request '${
number === newNumber ? newNumber : `${number} => ${newNumber}`
}'`,
@ -819,7 +814,7 @@ export default class API {
}
async listUnpublishedBranches() {
console.log(
console.info(
'%c Checking for Unpublished entries',
'line-height: 30px;text-align: center;font-weight: bold',
);
@ -846,11 +841,13 @@ export default class API {
for (const pr of pullRequests) {
if (!migrationNotified) {
migrationNotified = true;
alert(oneLine`
Netlify CMS is adding labels to ${pullRequests.length} of your Editorial Workflow
entries. The "Workflow" tab will be unavailable during this migration. You may use other
areas of the CMS during this time. Note that closing the CMS will pause the migration.
`);
alert({
title: 'api.labelsMigrationTitle',
body: {
key: 'api.labelsMigrationBody',
options: { pullRequests: pullRequests.length },
},
});
}
prCount = prCount + 1;
await this.migratePullRequest(pr, `${prCount} of ${pullRequests.length}`);
@ -1224,7 +1221,7 @@ export default class API {
try {
const result = await this.createRef('heads', branchName, sha);
return result;
} catch (e) {
} catch (e: any) {
const message = String(e.message || '');
if (message === 'Reference update failed') {
await throwOnConflictingBranches(branchName, name => this.getBranch(name), API_NAME);
@ -1239,7 +1236,7 @@ export default class API {
const result = await this.patchBranch(branchName, sha, { force: true });
return result;
} catch (e) {
console.log(e);
console.error(e);
}
}
throw e;
@ -1290,7 +1287,7 @@ export default class API {
}
async openPR(number: number) {
console.log('%c Re-opening PR', 'line-height: 30px;text-align: center;font-weight: bold');
console.info('%c Re-opening PR', 'line-height: 30px;text-align: center;font-weight: bold');
const result: Octokit.PullsUpdateBranchResponse = await this.request(
`${this.originRepoURL}/pulls/${number}`,
{
@ -1304,7 +1301,7 @@ export default class API {
}
async closePR(number: number) {
console.log('%c Deleting PR', 'line-height: 30px;text-align: center;font-weight: bold');
console.info('%c Deleting PR', 'line-height: 30px;text-align: center;font-weight: bold');
const result: Octokit.PullsUpdateBranchResponse = await this.request(
`${this.originRepoURL}/pulls/${number}`,
{
@ -1318,7 +1315,7 @@ export default class API {
}
async mergePR(pullrequest: GitHubPull) {
console.log('%c Merging PR', 'line-height: 30px;text-align: center;font-weight: bold');
console.info('%c Merging PR', 'line-height: 30px;text-align: center;font-weight: bold');
try {
const result: Octokit.PullsMergeResponse = await this.request(
`${this.originRepoURL}/pulls/${pullrequest.number}/merge`,
@ -1349,7 +1346,7 @@ export default class API {
files.forEach(file => {
commitMessage += `\n* "${file.path}"`;
});
console.log(
console.info(
'%c Automatic merge not possible - Forcing merge.',
'line-height: 30px;text-align: center;font-weight: bold',
);

View File

@ -1,8 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { NetlifyAuthenticator } from 'netlify-cms-lib-auth';
import { AuthenticationPage, Icon } from 'netlify-cms-ui-default';
import { AuthenticationPage, Icon } from '../../ui';
import { NetlifyAuthenticator } from '../../lib/auth';
const LoginButtonIcon = styled(Icon)`
margin-right: 18px;

View File

@ -6,6 +6,8 @@ import {
} from 'apollo-cache-inmemory';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { trim, trimStart } from 'lodash';
import {
APIError,
readFile,
@ -14,9 +16,7 @@ import {
branchFromContentKey,
CMS_BRANCH_PREFIX,
throwOnConflictingBranches,
} from 'netlify-cms-lib-util';
import { trim, trimStart } from 'lodash';
} from '../../lib/util';
import introspectionQueryResultData from './fragmentTypes';
import API, { API_NAME, PullRequestState, MOCK_PULL_REQUEST } from './API';
import * as queries from './queries';
@ -152,7 +152,7 @@ export default class GraphQLAPI extends API {
try {
const result = await this.client.mutate(options);
return result;
} catch (error) {
} catch (error: any) {
const errors = error.graphQLErrors;
if (Array.isArray(errors) && errors.some(e => e.message === 'Ref cannot be created.')) {
const refName = options?.variables?.createRefInput?.name || '';
@ -180,7 +180,7 @@ export default class GraphQLAPI extends API {
const result = await this.client.mutate(options);
return result;
} catch (e) {
console.log(e);
console.error(e);
}
}
}
@ -581,7 +581,7 @@ export default class GraphQLAPI extends API {
} else {
return await this.deleteBranch(branchName);
}
} catch (e) {
} catch (e: any) {
const { graphQLErrors } = e;
if (graphQLErrors && graphQLErrors.length > 0) {
const branchNotFound = graphQLErrors.some((e: Error) => e.type === 'NOT_FOUND');

View File

@ -0,0 +1,572 @@
export default {
__schema: {
types: [
{
kind: 'INTERFACE',
name: 'Node',
possibleTypes: [
{ name: 'AddedToProjectEvent' },
{ name: 'App' },
{ name: 'AssignedEvent' },
{ name: 'BaseRefChangedEvent' },
{ name: 'BaseRefForcePushedEvent' },
{ name: 'Blob' },
{ name: 'Bot' },
{ name: 'BranchProtectionRule' },
{ name: 'ClosedEvent' },
{ name: 'CodeOfConduct' },
{ name: 'CommentDeletedEvent' },
{ name: 'Commit' },
{ name: 'CommitComment' },
{ name: 'CommitCommentThread' },
{ name: 'ConvertedNoteToIssueEvent' },
{ name: 'CrossReferencedEvent' },
{ name: 'DemilestonedEvent' },
{ name: 'DeployKey' },
{ name: 'DeployedEvent' },
{ name: 'Deployment' },
{ name: 'DeploymentEnvironmentChangedEvent' },
{ name: 'DeploymentStatus' },
{ name: 'ExternalIdentity' },
{ name: 'Gist' },
{ name: 'GistComment' },
{ name: 'HeadRefDeletedEvent' },
{ name: 'HeadRefForcePushedEvent' },
{ name: 'HeadRefRestoredEvent' },
{ name: 'Issue' },
{ name: 'IssueComment' },
{ name: 'Label' },
{ name: 'LabeledEvent' },
{ name: 'Language' },
{ name: 'License' },
{ name: 'LockedEvent' },
{ name: 'Mannequin' },
{ name: 'MarketplaceCategory' },
{ name: 'MarketplaceListing' },
{ name: 'MentionedEvent' },
{ name: 'MergedEvent' },
{ name: 'Milestone' },
{ name: 'MilestonedEvent' },
{ name: 'MovedColumnsInProjectEvent' },
{ name: 'Organization' },
{ name: 'OrganizationIdentityProvider' },
{ name: 'OrganizationInvitation' },
{ name: 'PinnedEvent' },
{ name: 'Project' },
{ name: 'ProjectCard' },
{ name: 'ProjectColumn' },
{ name: 'PublicKey' },
{ name: 'PullRequest' },
{ name: 'PullRequestCommit' },
{ name: 'PullRequestCommitCommentThread' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewComment' },
{ name: 'PullRequestReviewThread' },
{ name: 'PushAllowance' },
{ name: 'Reaction' },
{ name: 'ReadyForReviewEvent' },
{ name: 'Ref' },
{ name: 'ReferencedEvent' },
{ name: 'RegistryPackage' },
{ name: 'RegistryPackageDependency' },
{ name: 'RegistryPackageFile' },
{ name: 'RegistryPackageTag' },
{ name: 'RegistryPackageVersion' },
{ name: 'Release' },
{ name: 'ReleaseAsset' },
{ name: 'RemovedFromProjectEvent' },
{ name: 'RenamedTitleEvent' },
{ name: 'ReopenedEvent' },
{ name: 'Repository' },
{ name: 'RepositoryInvitation' },
{ name: 'RepositoryTopic' },
{ name: 'ReviewDismissalAllowance' },
{ name: 'ReviewDismissedEvent' },
{ name: 'ReviewRequest' },
{ name: 'ReviewRequestRemovedEvent' },
{ name: 'ReviewRequestedEvent' },
{ name: 'SavedReply' },
{ name: 'SecurityAdvisory' },
{ name: 'SponsorsListing' },
{ name: 'Sponsorship' },
{ name: 'Status' },
{ name: 'StatusContext' },
{ name: 'SubscribedEvent' },
{ name: 'Tag' },
{ name: 'Team' },
{ name: 'Topic' },
{ name: 'TransferredEvent' },
{ name: 'Tree' },
{ name: 'UnassignedEvent' },
{ name: 'UnlabeledEvent' },
{ name: 'UnlockedEvent' },
{ name: 'UnpinnedEvent' },
{ name: 'UnsubscribedEvent' },
{ name: 'User' },
{ name: 'UserBlockedEvent' },
{ name: 'UserContentEdit' },
{ name: 'UserStatus' },
],
},
{
kind: 'INTERFACE',
name: 'UniformResourceLocatable',
possibleTypes: [
{ name: 'Bot' },
{ name: 'ClosedEvent' },
{ name: 'Commit' },
{ name: 'CrossReferencedEvent' },
{ name: 'Gist' },
{ name: 'Issue' },
{ name: 'Mannequin' },
{ name: 'MergedEvent' },
{ name: 'Milestone' },
{ name: 'Organization' },
{ name: 'PullRequest' },
{ name: 'PullRequestCommit' },
{ name: 'ReadyForReviewEvent' },
{ name: 'Release' },
{ name: 'Repository' },
{ name: 'RepositoryTopic' },
{ name: 'ReviewDismissedEvent' },
{ name: 'User' },
],
},
{
kind: 'INTERFACE',
name: 'Actor',
possibleTypes: [
{ name: 'Bot' },
{ name: 'Mannequin' },
{ name: 'Organization' },
{ name: 'User' },
],
},
{
kind: 'INTERFACE',
name: 'RegistryPackageOwner',
possibleTypes: [{ name: 'Organization' }, { name: 'Repository' }, { name: 'User' }],
},
{
kind: 'INTERFACE',
name: 'ProjectOwner',
possibleTypes: [{ name: 'Organization' }, { name: 'Repository' }, { name: 'User' }],
},
{
kind: 'INTERFACE',
name: 'Closable',
possibleTypes: [
{ name: 'Issue' },
{ name: 'Milestone' },
{ name: 'Project' },
{ name: 'PullRequest' },
],
},
{
kind: 'INTERFACE',
name: 'Updatable',
possibleTypes: [
{ name: 'CommitComment' },
{ name: 'GistComment' },
{ name: 'Issue' },
{ name: 'IssueComment' },
{ name: 'Project' },
{ name: 'PullRequest' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewComment' },
],
},
{
kind: 'UNION',
name: 'ProjectCardItem',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'INTERFACE',
name: 'Assignable',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'INTERFACE',
name: 'Comment',
possibleTypes: [
{ name: 'CommitComment' },
{ name: 'GistComment' },
{ name: 'Issue' },
{ name: 'IssueComment' },
{ name: 'PullRequest' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewComment' },
],
},
{
kind: 'INTERFACE',
name: 'UpdatableComment',
possibleTypes: [
{ name: 'CommitComment' },
{ name: 'GistComment' },
{ name: 'Issue' },
{ name: 'IssueComment' },
{ name: 'PullRequest' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewComment' },
],
},
{
kind: 'INTERFACE',
name: 'Labelable',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'INTERFACE',
name: 'Lockable',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'INTERFACE',
name: 'RegistryPackageSearch',
possibleTypes: [{ name: 'Organization' }, { name: 'User' }],
},
{
kind: 'INTERFACE',
name: 'RepositoryOwner',
possibleTypes: [{ name: 'Organization' }, { name: 'User' }],
},
{
kind: 'INTERFACE',
name: 'MemberStatusable',
possibleTypes: [{ name: 'Organization' }, { name: 'Team' }],
},
{
kind: 'INTERFACE',
name: 'ProfileOwner',
possibleTypes: [{ name: 'Organization' }, { name: 'User' }],
},
{
kind: 'UNION',
name: 'PinnableItem',
possibleTypes: [{ name: 'Gist' }, { name: 'Repository' }],
},
{
kind: 'INTERFACE',
name: 'Starrable',
possibleTypes: [{ name: 'Gist' }, { name: 'Repository' }, { name: 'Topic' }],
},
{ kind: 'INTERFACE', name: 'RepositoryInfo', possibleTypes: [{ name: 'Repository' }] },
{
kind: 'INTERFACE',
name: 'GitObject',
possibleTypes: [{ name: 'Blob' }, { name: 'Commit' }, { name: 'Tag' }, { name: 'Tree' }],
},
{
kind: 'INTERFACE',
name: 'RepositoryNode',
possibleTypes: [
{ name: 'CommitComment' },
{ name: 'CommitCommentThread' },
{ name: 'Issue' },
{ name: 'IssueComment' },
{ name: 'PullRequest' },
{ name: 'PullRequestCommitCommentThread' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewComment' },
],
},
{
kind: 'INTERFACE',
name: 'Subscribable',
possibleTypes: [
{ name: 'Commit' },
{ name: 'Issue' },
{ name: 'PullRequest' },
{ name: 'Repository' },
{ name: 'Team' },
],
},
{
kind: 'INTERFACE',
name: 'Deletable',
possibleTypes: [
{ name: 'CommitComment' },
{ name: 'GistComment' },
{ name: 'IssueComment' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewComment' },
],
},
{
kind: 'INTERFACE',
name: 'Reactable',
possibleTypes: [
{ name: 'CommitComment' },
{ name: 'Issue' },
{ name: 'IssueComment' },
{ name: 'PullRequest' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewComment' },
],
},
{
kind: 'INTERFACE',
name: 'GitSignature',
possibleTypes: [
{ name: 'GpgSignature' },
{ name: 'SmimeSignature' },
{ name: 'UnknownSignature' },
],
},
{
kind: 'UNION',
name: 'RequestedReviewer',
possibleTypes: [{ name: 'User' }, { name: 'Team' }, { name: 'Mannequin' }],
},
{
kind: 'UNION',
name: 'PullRequestTimelineItem',
possibleTypes: [
{ name: 'Commit' },
{ name: 'CommitCommentThread' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewThread' },
{ name: 'PullRequestReviewComment' },
{ name: 'IssueComment' },
{ name: 'ClosedEvent' },
{ name: 'ReopenedEvent' },
{ name: 'SubscribedEvent' },
{ name: 'UnsubscribedEvent' },
{ name: 'MergedEvent' },
{ name: 'ReferencedEvent' },
{ name: 'CrossReferencedEvent' },
{ name: 'AssignedEvent' },
{ name: 'UnassignedEvent' },
{ name: 'LabeledEvent' },
{ name: 'UnlabeledEvent' },
{ name: 'MilestonedEvent' },
{ name: 'DemilestonedEvent' },
{ name: 'RenamedTitleEvent' },
{ name: 'LockedEvent' },
{ name: 'UnlockedEvent' },
{ name: 'DeployedEvent' },
{ name: 'DeploymentEnvironmentChangedEvent' },
{ name: 'HeadRefDeletedEvent' },
{ name: 'HeadRefRestoredEvent' },
{ name: 'HeadRefForcePushedEvent' },
{ name: 'BaseRefForcePushedEvent' },
{ name: 'ReviewRequestedEvent' },
{ name: 'ReviewRequestRemovedEvent' },
{ name: 'ReviewDismissedEvent' },
{ name: 'UserBlockedEvent' },
],
},
{
kind: 'UNION',
name: 'Closer',
possibleTypes: [{ name: 'Commit' }, { name: 'PullRequest' }],
},
{
kind: 'UNION',
name: 'ReferencedSubject',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'UNION',
name: 'Assignee',
possibleTypes: [
{ name: 'Bot' },
{ name: 'Mannequin' },
{ name: 'Organization' },
{ name: 'User' },
],
},
{
kind: 'UNION',
name: 'MilestoneItem',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'UNION',
name: 'RenamedTitleSubject',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'UNION',
name: 'PullRequestTimelineItems',
possibleTypes: [
{ name: 'PullRequestCommit' },
{ name: 'PullRequestCommitCommentThread' },
{ name: 'PullRequestReview' },
{ name: 'PullRequestReviewThread' },
{ name: 'PullRequestRevisionMarker' },
{ name: 'BaseRefChangedEvent' },
{ name: 'BaseRefForcePushedEvent' },
{ name: 'DeployedEvent' },
{ name: 'DeploymentEnvironmentChangedEvent' },
{ name: 'HeadRefDeletedEvent' },
{ name: 'HeadRefForcePushedEvent' },
{ name: 'HeadRefRestoredEvent' },
{ name: 'MergedEvent' },
{ name: 'ReviewDismissedEvent' },
{ name: 'ReviewRequestedEvent' },
{ name: 'ReviewRequestRemovedEvent' },
{ name: 'ReadyForReviewEvent' },
{ name: 'IssueComment' },
{ name: 'CrossReferencedEvent' },
{ name: 'AddedToProjectEvent' },
{ name: 'AssignedEvent' },
{ name: 'ClosedEvent' },
{ name: 'CommentDeletedEvent' },
{ name: 'ConvertedNoteToIssueEvent' },
{ name: 'DemilestonedEvent' },
{ name: 'LabeledEvent' },
{ name: 'LockedEvent' },
{ name: 'MentionedEvent' },
{ name: 'MilestonedEvent' },
{ name: 'MovedColumnsInProjectEvent' },
{ name: 'PinnedEvent' },
{ name: 'ReferencedEvent' },
{ name: 'RemovedFromProjectEvent' },
{ name: 'RenamedTitleEvent' },
{ name: 'ReopenedEvent' },
{ name: 'SubscribedEvent' },
{ name: 'TransferredEvent' },
{ name: 'UnassignedEvent' },
{ name: 'UnlabeledEvent' },
{ name: 'UnlockedEvent' },
{ name: 'UserBlockedEvent' },
{ name: 'UnpinnedEvent' },
{ name: 'UnsubscribedEvent' },
],
},
{
kind: 'UNION',
name: 'IssueOrPullRequest',
possibleTypes: [{ name: 'Issue' }, { name: 'PullRequest' }],
},
{
kind: 'UNION',
name: 'IssueTimelineItem',
possibleTypes: [
{ name: 'Commit' },
{ name: 'IssueComment' },
{ name: 'CrossReferencedEvent' },
{ name: 'ClosedEvent' },
{ name: 'ReopenedEvent' },
{ name: 'SubscribedEvent' },
{ name: 'UnsubscribedEvent' },
{ name: 'ReferencedEvent' },
{ name: 'AssignedEvent' },
{ name: 'UnassignedEvent' },
{ name: 'LabeledEvent' },
{ name: 'UnlabeledEvent' },
{ name: 'UserBlockedEvent' },
{ name: 'MilestonedEvent' },
{ name: 'DemilestonedEvent' },
{ name: 'RenamedTitleEvent' },
{ name: 'LockedEvent' },
{ name: 'UnlockedEvent' },
{ name: 'TransferredEvent' },
],
},
{
kind: 'UNION',
name: 'IssueTimelineItems',
possibleTypes: [
{ name: 'IssueComment' },
{ name: 'CrossReferencedEvent' },
{ name: 'AddedToProjectEvent' },
{ name: 'AssignedEvent' },
{ name: 'ClosedEvent' },
{ name: 'CommentDeletedEvent' },
{ name: 'ConvertedNoteToIssueEvent' },
{ name: 'DemilestonedEvent' },
{ name: 'LabeledEvent' },
{ name: 'LockedEvent' },
{ name: 'MentionedEvent' },
{ name: 'MilestonedEvent' },
{ name: 'MovedColumnsInProjectEvent' },
{ name: 'PinnedEvent' },
{ name: 'ReferencedEvent' },
{ name: 'RemovedFromProjectEvent' },
{ name: 'RenamedTitleEvent' },
{ name: 'ReopenedEvent' },
{ name: 'SubscribedEvent' },
{ name: 'TransferredEvent' },
{ name: 'UnassignedEvent' },
{ name: 'UnlabeledEvent' },
{ name: 'UnlockedEvent' },
{ name: 'UserBlockedEvent' },
{ name: 'UnpinnedEvent' },
{ name: 'UnsubscribedEvent' },
],
},
{
kind: 'UNION',
name: 'ReviewDismissalAllowanceActor',
possibleTypes: [{ name: 'User' }, { name: 'Team' }],
},
{
kind: 'UNION',
name: 'PushAllowanceActor',
possibleTypes: [{ name: 'User' }, { name: 'Team' }],
},
{
kind: 'UNION',
name: 'PermissionGranter',
possibleTypes: [{ name: 'Organization' }, { name: 'Repository' }, { name: 'Team' }],
},
{ kind: 'INTERFACE', name: 'Sponsorable', possibleTypes: [{ name: 'User' }] },
{
kind: 'INTERFACE',
name: 'Contribution',
possibleTypes: [
{ name: 'CreatedCommitContribution' },
{ name: 'CreatedIssueContribution' },
{ name: 'CreatedPullRequestContribution' },
{ name: 'CreatedPullRequestReviewContribution' },
{ name: 'CreatedRepositoryContribution' },
{ name: 'JoinedGitHubContribution' },
{ name: 'RestrictedContribution' },
],
},
{
kind: 'UNION',
name: 'CreatedRepositoryOrRestrictedContribution',
possibleTypes: [
{ name: 'CreatedRepositoryContribution' },
{ name: 'RestrictedContribution' },
],
},
{
kind: 'UNION',
name: 'CreatedIssueOrRestrictedContribution',
possibleTypes: [{ name: 'CreatedIssueContribution' }, { name: 'RestrictedContribution' }],
},
{
kind: 'UNION',
name: 'CreatedPullRequestOrRestrictedContribution',
possibleTypes: [
{ name: 'CreatedPullRequestContribution' },
{ name: 'RestrictedContribution' },
],
},
{
kind: 'UNION',
name: 'SearchResultItem',
possibleTypes: [
{ name: 'Issue' },
{ name: 'PullRequest' },
{ name: 'Repository' },
{ name: 'User' },
{ name: 'Organization' },
{ name: 'MarketplaceListing' },
{ name: 'App' },
],
},
{
kind: 'UNION',
name: 'CollectionItemContent',
possibleTypes: [{ name: 'Repository' }, { name: 'Organization' }, { name: 'User' }],
},
],
},
};

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import semaphore from 'semaphore';
import trimStart from 'lodash/trimStart';
import { stripIndent } from 'common-tags';
import {
CURSOR_COMPATIBILITY_SYMBOL,
Cursor,
@ -20,8 +21,7 @@ import {
contentKeyFromBranch,
unsentRequest,
branchFromContentKey,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
import AuthenticationPage from './AuthenticationPage';
import API, { API_NAME } from './API';
import GraphQLAPI from './GraphQLAPI';
@ -39,7 +39,7 @@ import type {
ImplementationFile,
UnpublishedEntryMediaFile,
Entry,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
import type { Semaphore } from 'semaphore';
type GitHubUser = Octokit.UsersGetAuthenticatedResponse;
@ -190,7 +190,7 @@ export default class GitHub implements Implementation {
.then(() => true)
.catch(err => {
if (err && err.status === 404) {
console.log('This 404 was expected and handled appropriately.');
console.info('This 404 was expected and handled appropriately.');
return false;
} else {
return Promise.reject(err);
@ -495,7 +495,7 @@ export default class GitHub implements Implementation {
try {
await this.api!.persistFiles([], [mediaFile], options);
const { sha, path, fileObj } = mediaFile as AssetProxy & { sha: string };
const displayURL = URL.createObjectURL(fileObj);
const displayURL = URL.createObjectURL(fileObj as Blob);
return {
id: sha,
name: fileObj!.name,

View File

@ -41,7 +41,7 @@ fetch(`${API_HOST}/graphql`, {
if (err) {
console.error('Error writing fragmentTypes file', err);
} else {
console.log('Fragment types successfully extracted!');
console.info('Fragment types successfully extracted!');
}
},
);

View File

@ -2,6 +2,13 @@ import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { Base64 } from 'js-base64';
import { Map } from 'immutable';
import { flow, partial, result, trimStart } from 'lodash';
import { dirname } from 'path';
const NO_CACHE = 'no-cache';
import * as queries from './queries';
import {
localForage,
parseLinkHeader,
@ -25,14 +32,7 @@ import {
requestWithBackoff,
readFileMetadata,
throwOnConflictingBranches,
} from 'netlify-cms-lib-util';
import { Base64 } from 'js-base64';
import { Map } from 'immutable';
import { flow, partial, result, trimStart } from 'lodash';
import { dirname } from 'path';
const NO_CACHE = 'no-cache';
import * as queries from './queries';
} from '../../lib/util';
import type { ApolloQueryResult } from 'apollo-client';
import type { NormalizedCacheObject } from 'apollo-cache-inmemory';
@ -43,7 +43,7 @@ import type {
PersistOptions,
FetchError,
ImplementationFile,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
export const API_NAME = 'GitLab';
@ -288,7 +288,7 @@ export default class API {
request = async (req: ApiRequest): Promise<Response> => {
try {
return requestWithBackoff(this, req);
} catch (err) {
} catch (err: any) {
throw new APIError(err.message, null, API_NAME);
}
};
@ -333,7 +333,7 @@ export default class API {
return true;
}
} catch (e) {
console.log('Failed getting default branch', e);
console.error('Failed getting default branch', e);
}
}
}
@ -607,7 +607,7 @@ export default class API {
body: JSON.stringify(commitParams),
});
return result;
} catch (error) {
} catch (error: any) {
const message = error.message || '';
if (newBranch && message.includes(`Could not update ${branch}`)) {
await throwOnConflictingBranches(branch, name => this.getBranch(name), API_NAME);
@ -710,7 +710,7 @@ export default class API {
}
async listUnpublishedBranches() {
console.log(
console.info(
'%c Checking for Unpublished entries',
'line-height: 30px;text-align: center;font-weight: bold',
);

View File

@ -1,12 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { AuthenticationPage, Icon } from '../../ui';
import {
NetlifyAuthenticator,
ImplicitAuthenticator,
PkceAuthenticator,
} from 'netlify-cms-lib-auth';
import { AuthenticationPage, Icon } from 'netlify-cms-ui-default';
} from '../../lib/auth';
const LoginButtonIcon = styled(Icon)`
margin-right: 18px;

View File

@ -2,6 +2,7 @@ import trimStart from 'lodash/trimStart';
import semaphore from 'semaphore';
import { trim } from 'lodash';
import { stripIndent } from 'common-tags';
import {
CURSOR_COMPATIBILITY_SYMBOL,
basename,
@ -21,8 +22,7 @@ import {
allEntriesByFolder,
filterByExtension,
branchFromContentKey,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
import AuthenticationPage from './AuthenticationPage';
import API, { API_NAME } from './API';
@ -39,7 +39,7 @@ import type {
ImplementationFile,
UnpublishedEntryMediaFile,
AsyncLock,
} from 'netlify-cms-lib-util';
} from '../../lib/util';
import type { Semaphore } from 'semaphore';
const MAX_CONCURRENT_DOWNLOADS = 10;

Some files were not shown because too many files have changed in this diff Show More