Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4216 media editor and maps #4278

Merged
merged 5 commits into from
Oct 4, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions web/client/actions/__tests__/mediaEditor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import {
saveMedia, SAVE_MEDIA,
saveMediaSuccess, SAVE_MEDIA_SUCCESS,
selectItem, SELECT_ITEM,
updateItem, UPDATE_ITEM,
setMediaService, SET_MEDIA_SERVICE,
setMediaType, SET_MEDIA_TYPE,
setAddingMedia, ADDING_MEDIA,
setEditingMedia, EDITING_MEDIA,
show, SHOW
Expand Down Expand Up @@ -90,6 +93,12 @@ describe('mediaEditor actions', () => {
expect(action.id).toEqual(id);
expect(action.type).toEqual(SELECT_ITEM);
});
it('updateItem', () => {
const map = {id: "val"};
const action = updateItem(map);
expect(action.item).toEqual(map);
expect(action.type).toEqual(UPDATE_ITEM);
});
it('setAddingMedia', () => {
const adding = true;
const action = setAddingMedia(adding);
Expand All @@ -102,6 +111,18 @@ describe('mediaEditor actions', () => {
expect(action.editing).toEqual(editing);
expect(action.type).toEqual(EDITING_MEDIA);
});
it('setMediaService', () => {
const value = "geostory";
const action = setMediaService({value});
expect(action.id).toEqual(value);
expect(action.type).toEqual(SET_MEDIA_SERVICE);
});
it('setMediaType', () => {
const mediaType = "image";
const action = setMediaType(mediaType);
expect(action.mediaType).toEqual(mediaType);
expect(action.type).toEqual(SET_MEDIA_TYPE);
});
it('show', () => {
const owner = "geostory";
const action = show(owner);
Expand Down
33 changes: 20 additions & 13 deletions web/client/actions/mediaEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import {isObject} from 'lodash';
export const ADDING_MEDIA = "MEDIA_EDITOR:ADDING_MEDIA";
export const CHOOSE_MEDIA = "MEDIA_EDITOR:CHOOSE_MEDIA";
export const EDITING_MEDIA = "MEDIA_EDITOR:EDITING_MEDIA";
Expand All @@ -19,6 +19,18 @@ export const SET_MEDIA_TYPE = "MEDIA_EDITOR:SET_MEDIA_TYPE";
export const SET_MEDIA_SERVICE = "MEDIA_EDITOR:SET_MEDIA_SERVICE";
export const SELECT_ITEM = "MEDIA_EDITOR:SELECT_ITEM";
export const SHOW = "MEDIA_EDITOR:SHOW";
export const UPDATE_ITEM = "MEDIA_EDITOR:UPDATE_ITEM";

// RESOURCE FORMAT :
/*
{
type: 'image'|'video'|'map'|'iframe'|'document', // (pdf)
source: 'id', // id of the source, just to identify it in a local context
data: {
//specific data for the source type
}
}
*/

/**
* choose media for media editor
Expand Down Expand Up @@ -66,26 +78,21 @@ export const saveMediaSuccess = ({ mediaType, source, data, id }) => ({ type: SA
* @param {string} id of the resource
*/
export const selectItem = (id) => ({ type: SELECT_ITEM, id});
// RESOURCE FORMAT DRAFT :
/*
{
type: 'image'|'video'|'map'|'iframe'|'document' // (pdf)
source: 'id' // id of the source, just to identify it in a local context
data: {
//specific data for the source type
}
}
*/
/**
* update item in media editor list
* @param {object} param.item
*/
export const updateItem = (item) => ({ type: UPDATE_ITEM, item});
/**
* adding media
* @param {boolean} adding
*/
export const setAddingMedia = (adding) => ({ type: ADDING_MEDIA, adding });
/**
* set the media service
* @param {string} service id of the service
* @param {object|string} service id or object containing id of the service
*/
export const setMediaService = (service) => ({ type: SET_MEDIA_SERVICE, id: service ? service.value : null });
export const setMediaService = (service) => ({ type: SET_MEDIA_SERVICE, id: isObject(service) ? service.value : service });
/**
* change the media type in the media editor
* @param {string} mediaType type of the media, can be one of "image", "video" or "map"
Expand Down
7 changes: 6 additions & 1 deletion web/client/api/GeoStoreDAO.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,13 @@ const Api = {
createAttributeList,
generateMetadata,
authProviderName: "geostore",
/**
* add the geostore base url, default is /mapstore/rest/geostore/
* @param {object} options axios options
* @return {object} options with baseURL
*/
addBaseUrl: function(options) {
return assign(options || {}, {baseURL: ConfigUtils.getDefaults().geoStoreUrl});
return assign({}, options, {baseURL: options && options.baseURL || ConfigUtils.getDefaults().geoStoreUrl});
},
getData: function(id, options) {
const url = "data/" + id;
Expand Down
8 changes: 7 additions & 1 deletion web/client/api/__tests__/GeoStoreDAO-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,16 @@ describe('Test correctness of the GeoStore APIs', () => {
const result = API.addBaseUrl(null);
expect(result).toIncludeKey("baseURL");
expect(result.baseURL).toNotBe(null);

const result2 = API.addBaseUrl({otherOption: 3});
expect(result2).toIncludeKey("baseURL")
expect(result2)
.toIncludeKey("baseURL")
.toIncludeKey('otherOption');
expect(result2.baseURL).toNotBe(null);

const baseURL = "/test/geostore/rest";
const withCustomBaseUrl = API.addBaseUrl({otherOption: 3, baseURL});
expect(withCustomBaseUrl.baseURL).toBe(baseURL);
});

it('test user creation utils', () => {
Expand Down
51 changes: 51 additions & 0 deletions web/client/api/media/__tests__/geostory-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2019, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import expect from 'expect';
import {load} from '../geostory';

describe('Test correctness of the geostory media api', () => {
it('testing load stream', (done) => {
const imgType = "image";
const mapType = "map";
const streams = load({getState: () => ({
geostory: {
currentStory: {
resources: [{
"id": "3025f52e-8d57-48df-9a56-8e21ac252282",
type: imgType,
"data": {
"src": "https://images.unsplash.com",
"title": "title",
"credits": "credits",
"description": "desc",
"altText": "altText"
}
},
{
"id": "8d578d57-8d57-48df-9a56-8e21ac252282",
type: mapType,
"data": {
"title": "Map name",
"description": "map desc",
layers: [],
"altText": "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
}
}]
}
}
})
});
expect(streams.value.length).toBe(2);
const result1 = streams.value[0];
const result2 = streams.value[1];
expect(result1.mediaType).toBe(imgType);
expect(result2.mediaType).toBe(mapType);
done();
});
});
95 changes: 50 additions & 45 deletions web/client/api/media/geostory.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,39 @@
* LICENSE file in the root directory of this source tree.
*/
import { Observable } from 'rxjs';
import { isNil } from 'lodash';
import { groupBy } from 'lodash';
import uuid from 'uuid';

import { addResource, editResource } from '../../actions/geostory';
import { resourcesSelector } from '../../selectors/geostory';
import { selectedIdSelector } from '../../selectors/mediaEditor';

import { SourceTypes } from '../../utils/MediaEditorUtils';
/**
* API to save in local resources. All the methods must implement the same interface.
* TODO: bring the interface documentation into mediaAPI
*/
export default {
/**
* Saves a media with passed data and returns the object shaped as {id, mediaType, data, source}
* @param {string} mediaType type of the media (image, video...)
* @param {object} source source object
* @param {object} data the effective media data
* @param {object} store redux store middleware object (with dispatch and getStore method)
* @returns {Observable} a stream that emit an object like this
* ```
* {
* id, // generated by the service
* mediaType, // original media type
* data, // effective media object data
* source // source object
* }
* ```
*/
save: (mediaType, source, data, store) =>
Observable.of(uuid()).do(
(id) => store.dispatch(addResource(id, mediaType, data)
)).map(id => ({id, mediaType, data, source})),
/**

/**
* Saves a media with passed data and returns the object shaped as {id, mediaType, data, source}
* @param {string} mediaType type of the media (image, video...)
* @param {object} source source object
* @param {object} data the effective media data
* @param {object} store redux store middleware object (with dispatch and getStore method)
* @returns {Observable} a stream that emit an object like this
* ```
* {
* id, // generated by the service
* mediaType, // original media type
* data, // effective media object data
* source // source object
* }
* ```
*/
export const save = (mediaType, source, data, store) =>
Observable.of(uuid()).do(
(id) => store.dispatch(addResource(id, mediaType, data)
)).map(id => ({id, mediaType, data, source}));
/**
* Updates a media with passed data and returns the object shaped as {id, mediaType, data, source}
* @param {string} mediaType type of the media (image, video...)
* @param {object} source source object
Expand All @@ -54,31 +54,36 @@ export default {
* }
* ```
*/
edit: (mediaType, source, data, store) => {
const state = store.getState();
const id = selectedIdSelector(state);
return Observable.of(id).do(
() => {
return store.dispatch(editResource(id, mediaType, data));
}
).map(() => ({id, mediaType, data, source}));
},
export const edit = (mediaType, source, data, store) => {
const state = store.getState();
const id = selectedIdSelector(state);
return Observable.of(id).do(
() => {
return store.dispatch(editResource(id, mediaType, data));
}
).map(() => ({id, mediaType, data, source}));
};
/**
* load data from the source, with the search parameters passed
* @returns {Observable} a stream that emits an object with the following shape:
* load data for every media type
* @returns {Observable} a stream that emits an array of object with the following shape:
* ```json
* {
* [{
* "resources": [{id, type, data}],
* "sourceId": geostory,
* "mediaType": image | map,
* "totalCount": 1
* }
* }]
* ```
*/
load: ({mediaType}, store) => {
const resources = resourcesSelector(store.getState())
.filter(({ type }) => !isNil(mediaType) ? type === mediaType : true);
return Observable.of({
resources,
totalCount: resources.length
});
}
export const load = (store) => {
const resources = resourcesSelector(store.getState());
const separatedResourcesPerType = resources.length ? groupBy(resourcesSelector(store.getState()), "type") : {};
return Object.keys(separatedResourcesPerType).length && Observable.of(
Object.keys(separatedResourcesPerType).map(mediaType => ({
resources: separatedResourcesPerType[mediaType],
sourceId: SourceTypes.GEOSTORY,
mediaType,
totalCount: separatedResourcesPerType[mediaType].length
}))
) || Observable.of(null);
};
5 changes: 2 additions & 3 deletions web/client/api/media/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
* LICENSE file in the root directory of this source tree.
*/

import geostory from './geostory';

import * as geostory from './geostory';

const registry = {
"geostory": geostory
};


export default () => registry.geostory; // TODO: support other kinds of media types and sources
export default (sourceType) => registry[sourceType]; // TODO: support other kinds of media types and sources
14 changes: 9 additions & 5 deletions web/client/api/persistence/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const ApiProviders = {
/**
* MapStore Persistence layer.
* By default MapStore persists resources on geostore. You can add a persistence provider creating an object that
* implements the CRUD interface (createResource, getResource, updateResource and deleteResource)
* implements the CRUD interface (createResource, [getResource, getResources], updateResource and deleteResource)
* and adding it to the API providers calling `addApi`.
* Then you can select your provider by settings the `persistenceApi` property in `localConfig.json`
* or by programmatically calling `setApi` method. LocalConfig takes precedence.
Expand Down Expand Up @@ -79,10 +79,14 @@ const Persistence = {
*/
createResource: (...args) => Persistence.getApi().createResource(...args),
/**
* Updates a resource setting up permission and linked resources
* @param {resource} param0 the resource to update (must contain the id)
* @return an observable that emits the id of the updated resource
*/
* retrieves resources and for each resource it retrieves data with all information about user's permission on that resource, attributes and data.
*/
getResources: (...args) => Persistence.getApi().getResources(...args),
/**
* Updates a resource setting up permission and linked resources
* @param {resource} param0 the resource to update (must contain the id)
* @return an observable that emits the id of the updated resource
*/
updateResource: (...args) => Persistence.getApi().updateResource(...args),
/**
* Updates a resource attribute
Expand Down
4 changes: 2 additions & 2 deletions web/client/components/geostory/builder/Builder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ class Builder extends React.Component {
},
{
tooltipId: "geostory.builder.settings.tooltip",
glyph: "cog"

glyph: "cog",
disabled: true // TODO: restore when implemented
},
{
tooltipId: `geostory.builder.${cardPreviewEnabled ? "hide" : "show"}`,
Expand Down
4 changes: 2 additions & 2 deletions web/client/components/geostory/common/AddBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ class AddBar extends React.Component {
id: PropTypes.string,
type: PropTypes.string,
buttons: PropTypes.array,
containerWidth: PropTypes.number,
containerHeight: PropTypes.number
containerWidth: PropTypes.oneOf(PropTypes.number, PropTypes.string),
containerHeight: PropTypes.oneOf(PropTypes.number, PropTypes.string)
};

static defaultProps = {
Expand Down
Loading