diff --git a/client/coral-admin/src/components/ui/Layout.css b/client/coral-admin/src/components/ui/Layout.css index 792440d97..a3cc7b7b6 100644 --- a/client/coral-admin/src/components/ui/Layout.css +++ b/client/coral-admin/src/components/ui/Layout.css @@ -1,6 +1,5 @@ .layout { max-width: 1280px; margin: 0 auto; - overflow: hidden; background-color: #FAFAFA; } diff --git a/client/coral-admin/src/routes/Moderation/components/Moderation.js b/client/coral-admin/src/routes/Moderation/components/Moderation.js index a0a5b3705..c2036247d 100644 --- a/client/coral-admin/src/routes/Moderation/components/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/components/Moderation.js @@ -11,6 +11,7 @@ import NotFoundAsset from './NotFoundAsset'; import ModerationKeysModal from '../../../components/ModerationKeysModal'; import UserDetail from '../containers/UserDetail'; import StorySearch from '../containers/StorySearch'; +import {Spinner} from 'coral-ui'; export default class Moderation extends Component { state = { @@ -102,18 +103,22 @@ export default class Moderation extends Component { } render () { - const {root, moderation, settings, assets, viewUserDetail, hideUserDetail, ...props} = this.props; + const {root, moderation, settings, viewUserDetail, hideUserDetail, ...props} = this.props; const providedAssetId = this.props.params.id; const activeTab = this.props.route.path === ':id' ? 'premod' : this.props.route.path; - - let asset; + const {asset} = root; if (providedAssetId) { - asset = assets.find((asset) => asset.id === this.props.params.id); + if (asset === null) { - if (!asset) { + // Not found. return ; } + if (asset === undefined || asset.id !== providedAssetId) { + + // Still loading. + return ; + } } const comments = root[activeTab]; diff --git a/client/coral-admin/src/routes/Moderation/components/Story.js b/client/coral-admin/src/routes/Moderation/components/Story.js index b87611b24..6c3a4b02f 100644 --- a/client/coral-admin/src/routes/Moderation/components/Story.js +++ b/client/coral-admin/src/routes/Moderation/components/Story.js @@ -9,12 +9,12 @@ const formatDate = (date) => { const Story = ({author, title, createdAt, open, id, goToStory}) => { return (
  • goToStory(id)}> -

    {title}

    -

    + {title} +

    By {author} {formatDate(createdAt)} {open ? 'Open' : 'Closed'} -

    +
  • ); }; diff --git a/client/coral-admin/src/routes/Moderation/components/StorySearch.css b/client/coral-admin/src/routes/Moderation/components/StorySearch.css index 9ea56df0d..f0503f6b9 100644 --- a/client/coral-admin/src/routes/Moderation/components/StorySearch.css +++ b/client/coral-admin/src/routes/Moderation/components/StorySearch.css @@ -12,7 +12,7 @@ .container { position: absolute; background-color: white; - top: 100px; + top: 106px; left: 0; right: 0; margin-left: auto; @@ -29,8 +29,7 @@ .headInput { background-color: #efefef; - padding: 17px 56px; - height: 80px; + padding: 10px 27px; box-sizing: border-box; } @@ -41,12 +40,13 @@ font-size: 16px; margin-right: 5px; position: relative; - top: 2px; + top: 3px; box-sizing: border-box; border-radius: 3px; border: solid 1px #dfdfdf; max-height: 45px; max-width: 600px; + font-weight: 300; } .cta { @@ -59,20 +59,22 @@ font-size: 15px; font-weight: 500; padding: 12px 30px; - letter-spacing: 0.7px; + letter-spacing: 0.25px; } -.storyList { +/*.storyList { border-top: 1px solid #ddd; -} +}*/ .story { - padding: 10px 63px; + padding: 7px 50px; border-bottom: 1px solid #ddd; cursor: pointer; display: block; text-decoration: none; height: 50px; + box-sizing: border-box; + transition: background-color 400ms; &:hover { background-color: #efefef; @@ -86,7 +88,7 @@ .title, .meta { margin: 0; color: black; - font-size: 17px; + font-size: 15px; } .author, .createdAt, .status { @@ -117,7 +119,8 @@ } .searchResults { - padding: 10px 24px; + padding: 7px 27px; + background: #F5F5F5; } .searchResults i { @@ -132,12 +135,11 @@ .headlineRecent { font-size: 15px; font-weight: 500; - letter-spacing: 0.7px; + letter-spacing: 0.25px; vertical-align: middle; - margin-left: 10px; + margin-left: 8px; } .noResults { padding: 10px 24px 15px 49px; } - diff --git a/client/coral-admin/src/routes/Moderation/components/StorySearch.js b/client/coral-admin/src/routes/Moderation/components/StorySearch.js index c174c892f..f42ceaadd 100644 --- a/client/coral-admin/src/routes/Moderation/components/StorySearch.js +++ b/client/coral-admin/src/routes/Moderation/components/StorySearch.js @@ -19,7 +19,7 @@ const StorySearch = (props) => { return (
    -
    +
    { this.props.hideSuspendUserDialog(); try { @@ -175,7 +166,7 @@ const commentConnectionFragment = gql` `; const withModQueueQuery = withQuery(gql` - query CoralAdmin_Moderation($asset_id: ID, $sort: SORT_ORDER) { + query CoralAdmin_Moderation($asset_id: ID, $sort: SORT_ORDER, $allAssets: Boolean!) { all: comments(query: { statuses: [NONE, PREMOD, ACCEPTED, REJECTED], asset_id: $asset_id, @@ -212,7 +203,7 @@ const withModQueueQuery = withQuery(gql` }) { ...CoralAdmin_Moderation_CommentConnection } - assets: assets(query: {}) { + asset(id: $asset_id) @skip(if: $allAssets) { id title url @@ -248,6 +239,7 @@ const withModQueueQuery = withQuery(gql` variables: { asset_id: id, sort: sortOrder, + allAssets: id === null } }; }, @@ -291,14 +283,12 @@ const mapStateToProps = (state) => ({ moderation: state.moderation.toJS(), settings: state.settings.toJS(), auth: state.auth.toJS(), - assets: state.assets.get('assets') }); const mapDispatchToProps = (dispatch) => ({ ...bindActionCreators({ toggleModal, singleView, - updateAssets, fetchSettings, showBanUserDialog, hideBanUserDialog, diff --git a/client/coral-admin/src/routes/Moderation/containers/StorySearch.js b/client/coral-admin/src/routes/Moderation/containers/StorySearch.js index f52c290b5..cf47ca662 100644 --- a/client/coral-admin/src/routes/Moderation/containers/StorySearch.js +++ b/client/coral-admin/src/routes/Moderation/containers/StorySearch.js @@ -20,6 +20,13 @@ class StorySearchContainer extends React.Component { }); } + handleEsc = (e) => { + if (e.key === 'Escape') { + e.preventDefault(); + this.props.closeSearch(); + } + } + handleEnter = (e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -43,6 +50,7 @@ class StorySearchContainer extends React.Component { AssetModel.find({ /** * [getAssetsByQuery description] * @param {Object} context the context of the request - * @param {String} value text string to search agains the documents - * @param {Number} limit limit the number of results + * @param {Object} query the query * @return {Promise} resolves the assets */ -const getAssetsByQuery = (context, value, limit) => { - return AssetsService.search(value, null, limit); +const getAssetsByQuery = (context, query) => { + return AssetsService.search(query); }; /** @@ -76,7 +75,7 @@ module.exports = (context) => ({ // this operation create a new asset if one isn't found. getByURL: (url) => findOrCreateAssetByURL(context, url), - search: (value, limit) => getAssetsByQuery(context, value, limit), + search: (query) => getAssetsByQuery(context, query), getByID: new DataLoader((ids) => genAssetsByID(context, ids)), getForMetrics: () => getAssetsForMetrics(context), getAll: new util.SingletonResolver(() => AssetModel.find({})) diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js index 637af9018..9889b62f2 100644 --- a/graph/resolvers/root_query.js +++ b/graph/resolvers/root_query.js @@ -11,9 +11,7 @@ const RootQuery = { return null; } - const {value = '', limit} = query; - - return Assets.search(value, limit); + return Assets.search(query); }, asset(_, query, {loaders: {Assets}}) { if (query.id) { diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index a4c4b8c5c..c946cca94 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -634,7 +634,7 @@ type RootQuery { comment(id: ID!): Comment # All assets. Requires the `ADMIN` role. - assets(query: AssetsQuery!): [Asset] + assets(query: AssetsQuery): [Asset] # Find or create an asset by url, or just find with the ID. asset(id: ID, url: String): Asset diff --git a/routes/api/assets/index.js b/routes/api/assets/index.js index 3bb3ef778..f02b49f7e 100644 --- a/routes/api/assets/index.js +++ b/routes/api/assets/index.js @@ -48,13 +48,13 @@ router.get('/', (req, res, next) => { Promise.all([ // Find the actuall assets. - FilterOpenAssets(AssetsService.search(search), filter) + FilterOpenAssets(AssetsService.search({value: search}), filter) .sort({[field]: (sort === 'asc') ? 1 : -1}) .skip(parseInt(skip)) .limit(parseInt(limit)), // Get the count of actual assets. - FilterOpenAssets(AssetsService.search(search), filter) + FilterOpenAssets(AssetsService.search({value: search}), filter) .count() ]) .then(([result, count]) => { diff --git a/services/assets.js b/services/assets.js index b81513b72..74bc1aa3a 100644 --- a/services/assets.js +++ b/services/assets.js @@ -104,13 +104,12 @@ module.exports = class AssetsService { } /** - * Finds assets matching keywords on the model. If `value` is an empty string, - * then it will not even perform a text search query. + * Finds assets matching keywords on the model. * @param {String} value string to search by. * @return {Promise} */ - static search(value = '', skip = null, limit = null) { - if (value.length === 0) { + static search({value, skip, limit} = {}) { + if (!value) { return AssetsService.all(skip, limit); } else { return AssetModel diff --git a/test/server/routes/api/assets/index.js b/test/server/routes/api/assets/index.js index 80708688b..63d3acb75 100644 --- a/test/server/routes/api/assets/index.js +++ b/test/server/routes/api/assets/index.js @@ -43,7 +43,7 @@ describe('/api/v1/assets', () => { .set(passport.inject({roles: ['ADMIN']})) .then((res) => { const body = res.body; - + expect(body).to.have.property('count', 2); expect(body).to.have.property('result');