Merge pull request #293 from Benaiah/label-cards-in-editorial-workflow
Add meta info to cards in editorial workflow
This commit is contained in:
commit
96d6242b78
@ -124,7 +124,15 @@ class Backend {
|
|||||||
.then(loadedEntries => loadedEntries.filter(entry => entry !== null))
|
.then(loadedEntries => loadedEntries.filter(entry => entry !== null))
|
||||||
.then(entries => (
|
.then(entries => (
|
||||||
entries.map((loadedEntry) => {
|
entries.map((loadedEntry) => {
|
||||||
const entry = createEntry(loadedEntry.metaData.collection, loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
|
const entry = createEntry(
|
||||||
|
loadedEntry.metaData.collection,
|
||||||
|
loadedEntry.slug,
|
||||||
|
loadedEntry.file.path,
|
||||||
|
{
|
||||||
|
raw: loadedEntry.data,
|
||||||
|
isModification: loadedEntry.isModification,
|
||||||
|
}
|
||||||
|
);
|
||||||
entry.metaData = loadedEntry.metaData;
|
entry.metaData = loadedEntry.metaData;
|
||||||
return entry;
|
return entry;
|
||||||
})
|
})
|
||||||
@ -138,7 +146,14 @@ class Backend {
|
|||||||
unpublishedEntry(collection, slug) {
|
unpublishedEntry(collection, slug) {
|
||||||
return this.implementation.unpublishedEntry(collection, slug)
|
return this.implementation.unpublishedEntry(collection, slug)
|
||||||
.then((loadedEntry) => {
|
.then((loadedEntry) => {
|
||||||
const entry = createEntry("draft", loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
|
const entry = createEntry(
|
||||||
|
"draft",
|
||||||
|
loadedEntry.slug,
|
||||||
|
loadedEntry.file.path,
|
||||||
|
{
|
||||||
|
raw: loadedEntry.data,
|
||||||
|
isModification: loadedEntry.isModification,
|
||||||
|
});
|
||||||
entry.metaData = loadedEntry.metaData;
|
entry.metaData = loadedEntry.metaData;
|
||||||
return entry;
|
return entry;
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import LocalForage from "localforage";
|
import LocalForage from "localforage";
|
||||||
import { Base64 } from "js-base64";
|
import { Base64 } from "js-base64";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { filterPromises } from "../../lib/promiseHelper";
|
import { filterPromises, resolvePromiseProperties } from "../../lib/promiseHelper";
|
||||||
import AssetProxy from "../../valueObjects/AssetProxy";
|
import AssetProxy from "../../valueObjects/AssetProxy";
|
||||||
import { SIMPLE, EDITORIAL_WORKFLOW, status } from "../../constants/publishModes";
|
import { SIMPLE, EDITORIAL_WORKFLOW, status } from "../../constants/publishModes";
|
||||||
import { APIError, EditorialWorkflowError } from "../../valueObjects/errors";
|
import { APIError, EditorialWorkflowError } from "../../valueObjects/errors";
|
||||||
@ -159,20 +159,29 @@ export default class API {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readUnpublishedBranchFile(contentKey) {
|
readUnpublishedBranchFile(contentKey) {
|
||||||
let metaData;
|
const metaDataPromise = this.retrieveMetadata(contentKey)
|
||||||
const unpublishedPromise = this.retrieveMetadata(contentKey)
|
.then(data => (data.objects.entry.path ? data : Promise.reject(null)));
|
||||||
.then((data) => {
|
return resolvePromiseProperties({
|
||||||
metaData = data;
|
metaData: metaDataPromise,
|
||||||
if (data.objects.entry.path) {
|
fileData: metaDataPromise.then(
|
||||||
return this.readFile(data.objects.entry.path, null, data.branch);
|
data => this.readFile(data.objects.entry.path, null, data.branch)),
|
||||||
}
|
isModification: metaDataPromise.then(
|
||||||
return Promise.reject(null);
|
data => this.isUnpublishedEntryModification(data.objects.entry.path, this.branch)),
|
||||||
})
|
})
|
||||||
.then(fileData => ({ metaData, fileData }))
|
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
throw new EditorialWorkflowError('content is not under editorial workflow', true);
|
throw new EditorialWorkflowError('content is not under editorial workflow', true);
|
||||||
});
|
});
|
||||||
return unpublishedPromise;
|
}
|
||||||
|
|
||||||
|
isUnpublishedEntryModification(path, branch) {
|
||||||
|
return this.readFile(path, null, branch)
|
||||||
|
.then(data => true)
|
||||||
|
.catch((err) => {
|
||||||
|
if (err.message && err.message === "Not Found") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
listUnpublishedBranches() {
|
listUnpublishedBranches() {
|
||||||
|
@ -99,6 +99,7 @@ export default class GitHub {
|
|||||||
file: { path },
|
file: { path },
|
||||||
data: data.fileData,
|
data: data.fileData,
|
||||||
metaData: data.metaData,
|
metaData: data.metaData,
|
||||||
|
isModification: data.isModification,
|
||||||
});
|
});
|
||||||
sem.leave();
|
sem.leave();
|
||||||
}
|
}
|
||||||
@ -127,6 +128,7 @@ export default class GitHub {
|
|||||||
file: { path: data.metaData.objects.entry.path },
|
file: { path: data.metaData.objects.entry.path },
|
||||||
data: data.fileData,
|
data: data.fileData,
|
||||||
metaData: data.metaData,
|
metaData: data.metaData,
|
||||||
|
isModification: data.isModification,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
--defaultColor: #333;
|
--defaultColor: #333;
|
||||||
--defaultColorLight: #eee;
|
--defaultColorLight: #eee;
|
||||||
--backgroundColor: #fff;
|
--backgroundColor: #fff;
|
||||||
|
--backgroundColorShaded: #eee;
|
||||||
--shadowColor: rgba(0, 0, 0, .25);
|
--shadowColor: rgba(0, 0, 0, .25);
|
||||||
--infoColor: #69c;
|
--infoColor: #69c;
|
||||||
--successColor: #1c7;
|
--successColor: #1c7;
|
||||||
--warningColor: #fa0;
|
--warningColor: #fa0;
|
||||||
--errorColor: #f52;
|
--errorColor: #f52;
|
||||||
--borderRadius: 2px;
|
--borderRadius: 2px;
|
||||||
|
--borderRadiusLarge: 10px;
|
||||||
--topmostZindex: 99999;
|
--topmostZindex: 99999;
|
||||||
--foregroundAltColor: #fff;
|
--foregroundAltColor: #fff;
|
||||||
--backgroundAltColor: #272e30;
|
--backgroundAltColor: #272e30;
|
||||||
|
@ -3,8 +3,11 @@ import { DragSource, DropTarget, HTML5DragDrop } from 'react-simple-dnd';
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import pluralize from 'pluralize';
|
||||||
|
import { capitalize } from 'lodash'
|
||||||
import { Card, CardTitle, CardText, CardActions } from 'react-toolbox/lib/card';
|
import { Card, CardTitle, CardText, CardActions } from 'react-toolbox/lib/card';
|
||||||
import Button from 'react-toolbox/lib/button';
|
import Button from 'react-toolbox/lib/button';
|
||||||
|
import UnpublishedListingCardMeta from './UnpublishedListingCardMeta.js';
|
||||||
import { status, statusDescriptions } from '../../constants/publishModes';
|
import { status, statusDescriptions } from '../../constants/publishModes';
|
||||||
import styles from './UnpublishedListing.css';
|
import styles from './UnpublishedListing.css';
|
||||||
|
|
||||||
@ -68,6 +71,7 @@ class UnpublishedListing extends React.Component {
|
|||||||
const slug = entry.get('slug');
|
const slug = entry.get('slug');
|
||||||
const ownStatus = entry.getIn(['metaData', 'status']);
|
const ownStatus = entry.getIn(['metaData', 'status']);
|
||||||
const collection = entry.getIn(['metaData', 'collection']);
|
const collection = entry.getIn(['metaData', 'collection']);
|
||||||
|
const isModification = entry.get('isModification');
|
||||||
return (
|
return (
|
||||||
<DragSource
|
<DragSource
|
||||||
key={slug}
|
key={slug}
|
||||||
@ -77,6 +81,10 @@ class UnpublishedListing extends React.Component {
|
|||||||
>
|
>
|
||||||
<div className={styles.draggable}>
|
<div className={styles.draggable}>
|
||||||
<Card className={styles.card}>
|
<Card className={styles.card}>
|
||||||
|
<UnpublishedListingCardMeta
|
||||||
|
meta={capitalize(pluralize(collection))}
|
||||||
|
label={isModification ? "" : "New"}
|
||||||
|
/>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={entry.getIn(['data', 'title'])}
|
title={entry.getIn(['data', 'title'])}
|
||||||
subtitle={`by ${ author }`}
|
subtitle={`by ${ author }`}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
@import '../UI/theme.css';
|
||||||
|
|
||||||
|
.cardMeta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
height: 34px;
|
||||||
|
padding: 0 16px;
|
||||||
|
margin-bottom: -6px;
|
||||||
|
|
||||||
|
font-size: .75em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
background: var(--backgroundColorShaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta {}
|
||||||
|
.label {
|
||||||
|
padding: 5px 8px 4px 8px;
|
||||||
|
border-radius: var(--borderRadiusLarge);
|
||||||
|
|
||||||
|
background: var(--backgroundAltColor);
|
||||||
|
color: var(--defaultColorLight)
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import React, { PropTypes } from 'react';
|
||||||
|
import styles from './UnpublishedListingCardMeta.css';
|
||||||
|
|
||||||
|
const UnpublishedListingCardMeta = ({ meta, label }) =>
|
||||||
|
<div className={styles.cardMeta}>
|
||||||
|
<span className={styles.meta}>{meta}</span>
|
||||||
|
{(label && label.length > 0)
|
||||||
|
? <span className={styles.label}>{label}</span>
|
||||||
|
: ""}
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
UnpublishedListingCardMeta.propTypes = {
|
||||||
|
meta: PropTypes.string.isRequired,
|
||||||
|
label: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UnpublishedListingCardMeta;
|
@ -1,3 +1,23 @@
|
|||||||
|
import { zipObject } from 'lodash';
|
||||||
|
|
||||||
export const filterPromises = (arr, filter) =>
|
export const filterPromises = (arr, filter) =>
|
||||||
Promise.all(arr.map(entry => filter(entry)))
|
Promise.all(arr.map(entry => filter(entry)))
|
||||||
.then(bits => arr.filter(entry => bits.shift()));
|
.then(bits => arr.filter(entry => bits.shift()));
|
||||||
|
|
||||||
|
export const resolvePromiseProperties = obj =>
|
||||||
|
(new Promise((resolve, reject) => {
|
||||||
|
// Get the keys which represent promises
|
||||||
|
const promiseKeys = Object.keys(obj).filter(
|
||||||
|
key => obj[key] instanceof Promise);
|
||||||
|
|
||||||
|
const promises = promiseKeys.map(key => obj[key]);
|
||||||
|
|
||||||
|
// Resolve all promises
|
||||||
|
Promise.all(promises)
|
||||||
|
.then(resolvedPromises => resolve(
|
||||||
|
// Return a copy of obj with promises overwritten by their
|
||||||
|
// resolved values
|
||||||
|
Object.assign(obj, zipObject(promiseKeys, resolvedPromises))))
|
||||||
|
// Pass errors to outer promise chain
|
||||||
|
.catch(err => reject(err));
|
||||||
|
}));
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { isBoolean } from "lodash";
|
||||||
|
|
||||||
export function createEntry(collection, slug = '', path = '', options = {}) {
|
export function createEntry(collection, slug = '', path = '', options = {}) {
|
||||||
const returnObj = {};
|
const returnObj = {};
|
||||||
returnObj.collection = collection;
|
returnObj.collection = collection;
|
||||||
@ -8,5 +10,8 @@ export function createEntry(collection, slug = '', path = '', options = {}) {
|
|||||||
returnObj.data = options.data || {};
|
returnObj.data = options.data || {};
|
||||||
returnObj.label = options.label || null;
|
returnObj.label = options.label || null;
|
||||||
returnObj.metaData = options.metaData || null;
|
returnObj.metaData = options.metaData || null;
|
||||||
|
returnObj.isModification = isBoolean(options.isModification)
|
||||||
|
? options.isModification
|
||||||
|
: null;
|
||||||
return returnObj;
|
return returnObj;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user