Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(endpoints): add UI Extensions endpoint
- Loading branch information
Benedikt Rötsch
committed
Aug 15, 2017
1 parent
8baf9c6
commit 9d4bcf3
Showing
7 changed files
with
320 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/** | ||
* UI Extension instances | ||
* @namespace UiExtension | ||
*/ | ||
import cloneDeep from 'lodash/cloneDeep' | ||
import { freezeSys, toPlainObject } from 'contentful-sdk-core' | ||
import enhanceWithMethods from '../enhance-with-methods' | ||
import { | ||
createUpdateEntity, | ||
createDeleteEntity | ||
} from '../instance-actions' | ||
|
||
/** | ||
* @memberof UiExtension | ||
* @typedef UiExtension | ||
* @prop {Meta.Sys} sys - System metadata | ||
* @prop {object} extension - UI Extension config | ||
* @prop {string} extension.name - Extension name | ||
* @prop {array} extension.fieldTypes - Field types where an extension can be used | ||
* @prop {array} extension.src - URL where the root HTML document of the extension can be found | ||
* @prop {array} extension.srcdoc - String representation of the extension (e.g. inline HTML code) | ||
* @prop {boolean} extension.sidebar - Controls the location of the extension. If true it will be rendered on the sidebar instead of replacing the field's editing control | ||
* @prop {function(): Object} toPlainObject() - Returns this UI Extension as a plain JS object | ||
*/ | ||
|
||
function createUiExtensionApi (http) { | ||
return { | ||
/** | ||
* Sends an update to the server with any changes made to the object's properties | ||
* @memberof UiExtension | ||
* @func update | ||
* @return {Promise<UiExtension>} Object returned from the server with updated changes. | ||
* @example | ||
* const contentful = require('contentful-management') | ||
* | ||
* const client = contentful.createClient({ | ||
* accessToken: '<content_management_api_key>' | ||
* }) | ||
* | ||
* client.getSpace('<space_id>') | ||
* .then((space) => space.getUiExtension('<ui_extension_id>')) | ||
* .then((uiExtension) => { | ||
* uiExtension.extension.name = 'New UI Extension name' | ||
* return uiExtension.update() | ||
* }) | ||
* .then((uiExtension) => console.log(`UI Extension ${uiExtension.sys.id} updated.`)) | ||
* .catch(console.error) | ||
*/ | ||
update: createUpdateEntity({ | ||
http: http, | ||
entityPath: 'extensions', | ||
wrapperMethod: wrapUiExtension | ||
}), | ||
|
||
/** | ||
* Deletes this object on the server. | ||
* @memberof UiExtension | ||
* @func delete | ||
* @return {Promise} Promise for the deletion. It contains no data, but the Promise error case should be handled. | ||
* @example | ||
* const contentful = require('contentful-management') | ||
* | ||
* const client = contentful.createClient({ | ||
* accessToken: '<content_management_api_key>' | ||
* }) | ||
* | ||
* client.getSpace('<space_id>') | ||
* .then((space) => space.getUiExtension('<ui_extension_id>')) | ||
* .then((uiExtension) => uiExtension.delete()) | ||
* .then(() => console.log(`UI Extension deleted.`)) | ||
* .catch(console.error) | ||
*/ | ||
delete: createDeleteEntity({ | ||
http: http, | ||
entityPath: 'extensions' | ||
}) | ||
} | ||
} | ||
|
||
/** | ||
* @private | ||
* @param {Object} http - HTTP client instance | ||
* @param {Object} data - Raw UI Extension data | ||
* @return {UiExtension} Wrapped UI Extension data | ||
*/ | ||
export function wrapUiExtension (http, data) { | ||
const uiExtension = toPlainObject(cloneDeep(data)) | ||
enhanceWithMethods(uiExtension, createUiExtensionApi(http)) | ||
return freezeSys(uiExtension) | ||
} | ||
|
||
/** | ||
* @private | ||
* @param {Object} http - HTTP client instance | ||
* @param {Object} data - Raw UI Extension collection data | ||
* @return {UiExtensionCollection} Wrapped UI Extension collection data | ||
*/ | ||
export function wrapUiExtensionCollection (http, data) { | ||
const uiExtensions = toPlainObject(cloneDeep(data)) | ||
uiExtensions.items = uiExtensions.items.map((entity) => wrapUiExtension(http, entity)) | ||
return freezeSys(uiExtensions) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
export default function uiExtensionTests (t, space) { | ||
t.test('Create, update, get, get all and delete UI Extension', (t) => { | ||
return space.createUiExtension({ | ||
extension: { | ||
name: 'My awesome extension', | ||
src: 'https://extensions.example.com/your-extension.html', | ||
fieldTypes: [ | ||
{ type: 'Text' } | ||
] | ||
} | ||
}) | ||
.then((uiExtension) => { | ||
t.equals(uiExtension.sys.type, 'Extension', 'type') | ||
t.equals(uiExtension.extension.name, 'My awesome extension', 'name') | ||
|
||
uiExtension.extension.name = 'New name' | ||
return uiExtension.update() | ||
}) | ||
.then((uiExtension) => { | ||
t.equals(uiExtension.extension.name, 'New name', 'name') | ||
|
||
return space.getUiExtension(uiExtension.sys.id) | ||
.then((uiExtension) => { | ||
t.equals(uiExtension.sys.id, uiExtension.sys.id, 'id') | ||
t.equals(uiExtension.extension.name, 'New name', 'name') | ||
|
||
return space.getUiExtensions() | ||
.then((result) => { | ||
t.equals(result.items.length, result.total, 'returns the just created ui extensions') | ||
}) | ||
.then(() => uiExtension.delete()) | ||
}) | ||
}) | ||
}) | ||
|
||
t.test('Create and delete UI Extension hosted by Contentful', (t) => { | ||
return space.createUiExtension({ | ||
extension: { | ||
name: 'My awesome extension hosted at Contentful', | ||
srcdoc: '<html><head><title>MyAwesomeUiExtension</title></head><body><h1>Awesome</h1></body></html>', | ||
fieldTypes: [ | ||
{ type: 'Text' } | ||
] | ||
} | ||
}) | ||
.then((uiExtension) => { | ||
t.equals(uiExtension.sys.type, 'Extension', 'type') | ||
t.equals(uiExtension.extension.name, 'My awesome extension hosted at Contentful', 'name') | ||
t.equals(uiExtension.extension.srcdoc, '<html><head><title>MyAwesomeUiExtension</title></head><body><h1>Awesome</h1></body></html>', 'name') | ||
|
||
return uiExtension.delete() | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import test from 'tape' | ||
import {cloneMock} from '../mocks/entities' | ||
import setupHttpMock from '../mocks/http' | ||
import {wrapUiExtension, wrapUiExtensionCollection} from '../../../lib/entities/ui-extension' | ||
import { | ||
entityWrappedTest, | ||
entityCollectionWrappedTest, | ||
entityUpdateTest, | ||
entityDeleteTest, | ||
failingActionTest, | ||
failingVersionActionTest | ||
} from '../test-creators/instance-entity-methods' | ||
|
||
function setup (promise) { | ||
return { | ||
httpMock: setupHttpMock(promise), | ||
entityMock: cloneMock('uiExtension') | ||
} | ||
} | ||
|
||
test('UiExtension is wrapped', (t) => { | ||
entityWrappedTest(t, setup, { | ||
wrapperMethod: wrapUiExtension | ||
}) | ||
}) | ||
|
||
test('UiExtension collection is wrapped', (t) => { | ||
return entityCollectionWrappedTest(t, setup, { | ||
wrapperMethod: wrapUiExtensionCollection | ||
}) | ||
}) | ||
|
||
test('UiExtension update', (t) => { | ||
return entityUpdateTest(t, setup, { | ||
wrapperMethod: wrapUiExtension | ||
}) | ||
}) | ||
|
||
test('UiExtension update fails', (t) => { | ||
return failingVersionActionTest(t, setup, { | ||
wrapperMethod: wrapUiExtension, | ||
actionMethod: 'update' | ||
}) | ||
}) | ||
|
||
test('UiExtension delete', (t) => { | ||
return entityDeleteTest(t, setup, { | ||
wrapperMethod: wrapUiExtension | ||
}) | ||
}) | ||
|
||
test('UiExtension delete fails', (t) => { | ||
return failingActionTest(t, setup, { | ||
wrapperMethod: wrapUiExtension, | ||
actionMethod: 'delete' | ||
}) | ||
}) |
Oops, something went wrong.