add private media library for integrations
This commit is contained in:
parent
d9905b4a6a
commit
9569f18ee4
@ -33,7 +33,7 @@ export function insertMedia(mediaPath) {
|
||||
}
|
||||
|
||||
export function loadMedia(opts = {}) {
|
||||
const { delay = 0, query = '', page = 1 } = opts;
|
||||
const { delay = 0, query = '', page = 1, privateUpload } = opts;
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const backend = currentBackend(state.config);
|
||||
@ -42,17 +42,18 @@ export function loadMedia(opts = {}) {
|
||||
const provider = getIntegrationProvider(state.integrations, backend.getToken, integration);
|
||||
dispatch(mediaLoading(page));
|
||||
try {
|
||||
const files = await provider.retrieve(query, page);
|
||||
const files = await provider.retrieve(query, page, privateUpload);
|
||||
const mediaLoadedOpts = {
|
||||
page,
|
||||
canPaginate: true,
|
||||
dynamicSearch: true,
|
||||
dynamicSearchQuery: query
|
||||
dynamicSearchQuery: query,
|
||||
privateUpload,
|
||||
};
|
||||
return dispatch(mediaLoaded(files, mediaLoadedOpts));
|
||||
}
|
||||
catch(error) {
|
||||
return dispatch(mediaLoadFailed());
|
||||
return dispatch(mediaLoadFailed({ privateUpload }));
|
||||
}
|
||||
}
|
||||
dispatch(mediaLoading(page));
|
||||
@ -66,7 +67,8 @@ export function loadMedia(opts = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
export function persistMedia(file, privateUpload) {
|
||||
export function persistMedia(file, opts = {}) {
|
||||
const { privateUpload } = opts;
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const backend = currentBackend(state.config);
|
||||
@ -81,7 +83,7 @@ export function persistMedia(file, privateUpload) {
|
||||
const asset = await backend.persistMedia(assetProxy);
|
||||
return dispatch(mediaPersisted(asset));
|
||||
}
|
||||
return dispatch(mediaPersisted(assetProxy.asset));
|
||||
return dispatch(mediaPersisted(assetProxy.asset, { privateUpload }));
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
@ -90,12 +92,13 @@ export function persistMedia(file, privateUpload) {
|
||||
kind: 'danger',
|
||||
dismissAfter: 8000,
|
||||
}));
|
||||
return dispatch(mediaPersistFailed());
|
||||
return dispatch(mediaPersistFailed({ privateUpload }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteMedia(file) {
|
||||
export function deleteMedia(file, opts = {}) {
|
||||
const { privateUpload } = opts;
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const backend = currentBackend(state.config);
|
||||
@ -105,7 +108,7 @@ export function deleteMedia(file) {
|
||||
dispatch(mediaDeleting());
|
||||
return provider.delete(file.id)
|
||||
.then(() => {
|
||||
return dispatch(mediaDeleted(file));
|
||||
return dispatch(mediaDeleted(file, { privateUpload }));
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
@ -114,7 +117,7 @@ export function deleteMedia(file) {
|
||||
kind: 'danger',
|
||||
dismissAfter: 8000,
|
||||
}));
|
||||
return dispatch(mediaDeleteFailed());
|
||||
return dispatch(mediaDeleteFailed({ privateUpload }));
|
||||
});
|
||||
}
|
||||
dispatch(mediaDeleting());
|
||||
@ -148,36 +151,41 @@ export function mediaLoaded(files, opts = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
export function mediaLoadFailed(error) {
|
||||
return { type: MEDIA_LOAD_FAILURE };
|
||||
export function mediaLoadFailed(error, opts = {}) {
|
||||
const { privateUpload } = opts;
|
||||
return { type: MEDIA_LOAD_FAILURE, payload: { privateUpload } };
|
||||
}
|
||||
|
||||
export function mediaPersisting() {
|
||||
return { type: MEDIA_PERSIST_REQUEST };
|
||||
}
|
||||
|
||||
export function mediaPersisted(asset) {
|
||||
export function mediaPersisted(asset, opts = {}) {
|
||||
const { privateUpload } = opts;
|
||||
return {
|
||||
type: MEDIA_PERSIST_SUCCESS,
|
||||
payload: { file: asset },
|
||||
payload: { file: asset, privateUpload },
|
||||
};
|
||||
}
|
||||
|
||||
export function mediaPersistFailed(error) {
|
||||
return { type: MEDIA_PERSIST_FAILURE };
|
||||
export function mediaPersistFailed(error, opts = {}) {
|
||||
const { privateUpload } = opts;
|
||||
return { type: MEDIA_PERSIST_FAILURE, payload: { privateUpload } };
|
||||
}
|
||||
|
||||
export function mediaDeleting() {
|
||||
return { type: MEDIA_DELETE_REQUEST };
|
||||
}
|
||||
|
||||
export function mediaDeleted(file) {
|
||||
export function mediaDeleted(file, opts = {}) {
|
||||
const { privateUpload } = opts;
|
||||
return {
|
||||
type: MEDIA_DELETE_SUCCESS,
|
||||
payload: { file },
|
||||
payload: { file, privateUpload },
|
||||
};
|
||||
}
|
||||
|
||||
export function mediaDeleteFailed(error) {
|
||||
return { type: MEDIA_DELETE_FAILURE };
|
||||
export function mediaDeleteFailed(error, opts = {}) {
|
||||
const { privateUpload } = opts;
|
||||
return { type: MEDIA_DELETE_FAILURE, payload: { privateUpload } };
|
||||
}
|
||||
|
@ -96,3 +96,25 @@
|
||||
overflow-wrap: break-word;
|
||||
line-height: 1.3 !important;
|
||||
}
|
||||
|
||||
.nc-mediaLibrary-dialogPrivate {
|
||||
background-color: var(--backgroundAltColor);
|
||||
|
||||
& .nc-mediaLibrary-title,
|
||||
& .nc-mediaLibrary-emptyMessage,
|
||||
& .nc-mediaLibrary-paginatingMessage,
|
||||
& h1 {
|
||||
color: var(--textFieldBorderColor);
|
||||
}
|
||||
|
||||
& .nc-mediaLibrary-card,
|
||||
& .nc-mediaLibrary-searchInput {
|
||||
background-color: var(--textFieldBorderColor);
|
||||
}
|
||||
|
||||
& button:disabled,
|
||||
& label[disabled] {
|
||||
background-color: rgba(217, 217, 217, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,10 @@ class MediaLibrary extends React.Component {
|
||||
if (isOpening) {
|
||||
this.setState({ selectedFile: {}, query: '' });
|
||||
}
|
||||
|
||||
if (isOpening && (this.props.privateUpload !== nextProps.privateUpload)) {
|
||||
this.props.loadMedia({ privateUpload: nextProps.privateUpload });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,7 +115,7 @@ class MediaLibrary extends React.Component {
|
||||
*/
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
const { loadMedia, persistMedia, privateUpload } = this.props;
|
||||
const { persistMedia, privateUpload } = this.props;
|
||||
const { files: fileList } = event.dataTransfer || event.target;
|
||||
const files = [...fileList];
|
||||
const file = files[0];
|
||||
@ -121,7 +125,7 @@ class MediaLibrary extends React.Component {
|
||||
* improved in the future, but isn't currently resulting in noticeable
|
||||
* performance/load time issues.
|
||||
*/
|
||||
await persistMedia(file, privateUpload);
|
||||
await persistMedia(file, { privateUpload });
|
||||
this.scrollToTop();
|
||||
};
|
||||
|
||||
@ -143,20 +147,20 @@ class MediaLibrary extends React.Component {
|
||||
*/
|
||||
handleDelete = () => {
|
||||
const { selectedFile } = this.state;
|
||||
const { files, deleteMedia } = this.props;
|
||||
const { files, deleteMedia, privateUpload } = this.props;
|
||||
if (!window.confirm('Are you sure you want to delete selected media?')) {
|
||||
return;
|
||||
}
|
||||
const file = files.find(file => selectedFile.key === file.key);
|
||||
deleteMedia(file)
|
||||
deleteMedia(file, { privateUpload })
|
||||
.then(() => {
|
||||
this.setState({ selectedFile: {} });
|
||||
});
|
||||
};
|
||||
|
||||
handleLoadMore = () => {
|
||||
const { loadMedia, dynamicSearchQuery, page } = this.props;
|
||||
loadMedia({ query: dynamicSearchQuery, page: page + 1 });
|
||||
const { loadMedia, dynamicSearchQuery, page, privateUpload } = this.props;
|
||||
loadMedia({ query: dynamicSearchQuery, page: page + 1, privateUpload });
|
||||
};
|
||||
|
||||
/**
|
||||
@ -167,8 +171,9 @@ class MediaLibrary extends React.Component {
|
||||
* so this handler has no impact.
|
||||
*/
|
||||
handleSearchKeyDown = async (event) => {
|
||||
if (event.key === 'Enter' && this.props.dynamicSearch) {
|
||||
await this.props.loadMedia({ query: this.state.query })
|
||||
const { dynamicSearch, loadMedia, privateUpload } = this.props;
|
||||
if (event.key === 'Enter' && dynamicSearch) {
|
||||
await loadMedia({ query: this.state.query, privateUpload })
|
||||
this.scrollToTop();
|
||||
}
|
||||
};
|
||||
@ -216,6 +221,7 @@ class MediaLibrary extends React.Component {
|
||||
hasNextPage,
|
||||
page,
|
||||
isPaginating,
|
||||
privateUpload,
|
||||
} = this.props;
|
||||
const { query, selectedFile } = this.state;
|
||||
const filteredFiles = forImage ? this.filterImages(files) : files;
|
||||
@ -236,7 +242,7 @@ class MediaLibrary extends React.Component {
|
||||
<Dialog
|
||||
isVisible={isVisible}
|
||||
onClose={this.handleClose}
|
||||
className="nc-mediaLibrary-dialog"
|
||||
className={c('nc-mediaLibrary-dialog', { 'nc-mediaLibrary-dialogPrivate': privateUpload })}
|
||||
footer={
|
||||
<MediaLibraryFooter
|
||||
onDelete={this.handleDelete}
|
||||
@ -251,7 +257,10 @@ class MediaLibrary extends React.Component {
|
||||
/>
|
||||
}
|
||||
>
|
||||
<h1 className="nc-mediaLibrary-title">{forImage ? 'Images' : 'Assets'}</h1>
|
||||
<h1 className="nc-mediaLibrary-title">
|
||||
{privateUpload ? 'Private ' : null}
|
||||
{forImage ? 'Images' : 'Assets'}
|
||||
</h1>
|
||||
<input
|
||||
className="nc-mediaLibrary-searchInput"
|
||||
value={query}
|
||||
|
@ -45,7 +45,7 @@ export default class FileControl extends React.Component {
|
||||
|
||||
handleClick = (e) => {
|
||||
const { field, onOpenMediaLibrary } = this.props;
|
||||
return onOpenMediaLibrary({ controlID: this.controlID, privateUpload: field.private });
|
||||
return onOpenMediaLibrary({ controlID: this.controlID, privateUpload: field.get('private') });
|
||||
};
|
||||
|
||||
renderFileName = () => {
|
||||
|
@ -43,7 +43,7 @@ export default class ImageControl extends React.Component {
|
||||
|
||||
handleClick = (e) => {
|
||||
const { field, onOpenMediaLibrary } = this.props;
|
||||
return onOpenMediaLibrary({ controlID: this.controlID, forImage: true, privateUpload: field.private });
|
||||
return onOpenMediaLibrary({ controlID: this.controlID, forImage: true, privateUpload: field.get('private') });
|
||||
};
|
||||
|
||||
renderFileName = () => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { pickBy } from 'lodash';
|
||||
import { pickBy, trimEnd } from 'lodash';
|
||||
import { addParams } from '../../../lib/urlHelper';
|
||||
|
||||
export default class AssetStore {
|
||||
@ -10,7 +10,7 @@ export default class AssetStore {
|
||||
this.getToken = getToken;
|
||||
|
||||
this.shouldConfirmUpload = config.get('shouldConfirmUpload', false);
|
||||
this.getSignedFormURL = config.get('getSignedFormURL');
|
||||
this.getSignedFormURL = trimEnd(config.get('getSignedFormURL'), '/');
|
||||
}
|
||||
|
||||
parseJsonResponse(response) {
|
||||
@ -65,8 +65,8 @@ export default class AssetStore {
|
||||
return content;
|
||||
}
|
||||
|
||||
async retrieve(query, page) {
|
||||
const params = pickBy({ search: query, page }, val => !!val);
|
||||
async retrieve(query, page, privateUpload) {
|
||||
const params = pickBy({ search: query, page, filter: privateUpload ? 'private' : 'public' }, val => !!val);
|
||||
const url = addParams(this.getSignedFormURL, params);
|
||||
const token = await this.getToken();
|
||||
const headers = {
|
||||
|
@ -17,14 +17,26 @@ import {
|
||||
} from '../actions/mediaLibrary';
|
||||
|
||||
const mediaLibrary = (state = Map({ isVisible: false, controlMedia: Map() }), action) => {
|
||||
const privateUploadChanged = state.get('privateUpload') !== get(action, ['payload', 'privateUpload']);
|
||||
switch (action.type) {
|
||||
case MEDIA_LIBRARY_OPEN: {
|
||||
const { controlID, forImage } = action.payload || {};
|
||||
const { controlID, forImage, privateUpload } = action.payload || {};
|
||||
if (privateUploadChanged) {
|
||||
return Map({
|
||||
isVisible: true,
|
||||
forImage,
|
||||
controlID,
|
||||
canInsert: !!controlID,
|
||||
privateUpload,
|
||||
controlMedia: Map(),
|
||||
});
|
||||
}
|
||||
return state.withMutations(map => {
|
||||
map.set('isVisible', true);
|
||||
map.set('forImage', forImage);
|
||||
map.set('controlID', controlID);
|
||||
map.set('canInsert', !!controlID);
|
||||
map.set('privateUpload', privateUpload);
|
||||
});
|
||||
}
|
||||
case MEDIA_LIBRARY_CLOSE:
|
||||
@ -40,7 +52,12 @@ const mediaLibrary = (state = Map({ isVisible: false, controlMedia: Map() }), ac
|
||||
map.set('isPaginating', action.payload.page > 1);
|
||||
});
|
||||
case MEDIA_LOAD_SUCCESS: {
|
||||
const { files = [], page, canPaginate, dynamicSearch, dynamicSearchQuery } = action.payload;
|
||||
const { files = [], page, canPaginate, dynamicSearch, dynamicSearchQuery, privateUpload } = action.payload;
|
||||
|
||||
if (privateUploadChanged) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const filesWithKeys = files.map(file => ({ ...file, key: uuid() }));
|
||||
return state.withMutations(map => {
|
||||
map.set('isLoading', false);
|
||||
@ -59,11 +76,17 @@ const mediaLibrary = (state = Map({ isVisible: false, controlMedia: Map() }), ac
|
||||
});
|
||||
}
|
||||
case MEDIA_LOAD_FAILURE:
|
||||
if (privateUploadChanged) {
|
||||
return state;
|
||||
}
|
||||
return state.set('isLoading', false);
|
||||
case MEDIA_PERSIST_REQUEST:
|
||||
return state.set('isPersisting', true);
|
||||
case MEDIA_PERSIST_SUCCESS: {
|
||||
const { file } = action.payload;
|
||||
if (privateUploadChanged) {
|
||||
return state;
|
||||
}
|
||||
return state.withMutations(map => {
|
||||
const fileWithKey = { ...file, key: uuid() };
|
||||
const updatedFiles = [fileWithKey, ...map.get('files')];
|
||||
@ -72,11 +95,17 @@ const mediaLibrary = (state = Map({ isVisible: false, controlMedia: Map() }), ac
|
||||
});
|
||||
}
|
||||
case MEDIA_PERSIST_FAILURE:
|
||||
if (privateUploadChanged) {
|
||||
return state;
|
||||
}
|
||||
return state.set('isPersisting', false);
|
||||
case MEDIA_DELETE_REQUEST:
|
||||
return state.set('isDeleting', true);
|
||||
case MEDIA_DELETE_SUCCESS: {
|
||||
const { key } = action.payload.file;
|
||||
if (privateUploadChanged) {
|
||||
return state;
|
||||
}
|
||||
return state.withMutations(map => {
|
||||
const updatedFiles = map.get('files').filter(file => file.key !== key);
|
||||
map.set('files', updatedFiles);
|
||||
@ -84,6 +113,9 @@ const mediaLibrary = (state = Map({ isVisible: false, controlMedia: Map() }), ac
|
||||
});
|
||||
}
|
||||
case MEDIA_DELETE_FAILURE:
|
||||
if (privateUploadChanged) {
|
||||
return state;
|
||||
}
|
||||
return state.set('isDeleting', false);
|
||||
default:
|
||||
return state;
|
||||
|
Loading…
x
Reference in New Issue
Block a user