Skip to content

Commit

Permalink
Import site metadata into admin interface (#543)
Browse files Browse the repository at this point in the history
To allow selecting existing categories, layouts and tags via the interface.

The idea is to fetch the *data* related to above every time a page / draft / document is created / edited so that the `Metafields` component always reflects the latest status (i.e. a category added to one post will be available for the next post being edited).
  • Loading branch information
ashmaroli committed Mar 1, 2020
1 parent 02dccff commit ea81df9
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 6 deletions.
3 changes: 3 additions & 0 deletions lib/jekyll-admin/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,6 @@ def restored_front_matter

# load individual route configurations
JekyllAdmin::Server::ROUTES.each { |name| require_relative File.join("server", name) }

# load namespaces outside route configurations
require_relative "server/site_meta"
25 changes: 25 additions & 0 deletions lib/jekyll-admin/server/site_meta.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module JekyllAdmin
class Server < Sinatra::Base
# Jekyll::Site instance method names that return a Hash.
META_KEYS = [:categories, :layouts, :tags].freeze
private_constant :META_KEYS

namespace "/site_meta" do
get "/?" do
json site_meta
end

private

# Stash a Hash generated with pre-determined keys.
def site_meta
@site_meta ||= META_KEYS.zip(META_KEYS.map { |k| site.send(k).keys }).to_h
end

# Reset memoization of `#site_meta` when the site regenerates
Jekyll::Hooks.register(:site, :after_reset) { @site_meta = nil }
end
end
end
2 changes: 2 additions & 0 deletions src/constants/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export const API =
? '/_api'
: 'http://localhost:4000/_api';

export const getSiteMetaUrl = () => `${API}/site_meta`;

export const getConfigurationUrl = () => `${API}/configuration`;
export const putConfigurationUrl = () => `${API}/configuration`;

Expand Down
7 changes: 6 additions & 1 deletion src/containers/MetaFields.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import {
moveArrayItem,
convertField,
} from '../ducks/metadata';
import { fetchSiteMeta } from '../ducks/siteMeta';

export class MetaFields extends Component {
componentDidMount() {
const { storeContentFields, fields } = this.props;
const { storeContentFields, fields, fetchSiteMeta, dataview } = this.props;
if (!dataview) fetchSiteMeta();
storeContentFields(fields);
}

Expand Down Expand Up @@ -119,18 +121,21 @@ MetaFields.propTypes = {
updateFieldValue: PropTypes.func.isRequired,
moveArrayItem: PropTypes.func.isRequired,
convertField: PropTypes.func.isRequired,
fetchSiteMeta: PropTypes.func.isRequired,
dataview: PropTypes.bool,
};

const mapStateToProps = state => ({
metadata: state.metadata.metadata,
key_prefix: state.metadata.key_prefix,
site: state.meta.site,
});

const mapDispatchToProps = dispatch =>
bindActionCreators(
{
storeContentFields,
fetchSiteMeta,
addField,
removeField,
updateFieldKey,
Expand Down
21 changes: 16 additions & 5 deletions src/containers/tests/metafields.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const defaultProps = {

const actions = {
storeContentFields: jest.fn(),
fetchSiteMeta: jest.fn(),
addField: jest.fn(),
removeField: jest.fn(),
updateFieldKey: jest.fn(),
Expand All @@ -34,6 +35,21 @@ function setup(props = defaultProps) {
}

describe('Containers::MetaFields', () => {
it('does not call fetchSiteMeta before mount in dataview', () => {
const { actions } = setup({ ...defaultProps, dataview: true });
expect(actions.fetchSiteMeta).not.toHaveBeenCalled();
});

it('calls fetchSiteMeta before mount', () => {
const { actions } = setup();
expect(actions.fetchSiteMeta).toHaveBeenCalled();
});

it('calls storeContentFields before mount', () => {
const { actions } = setup();
expect(actions.storeContentFields).toHaveBeenCalled();
});

it('renders MetaFields correctly', () => {
let { component, addFieldButton, addDataFieldButton } = setup();

Expand Down Expand Up @@ -63,11 +79,6 @@ describe('Containers::MetaFields', () => {
expect(component.prop('metadata')).toEqual(content);
});

it('calls storeContentFields before mount', () => {
const { actions } = setup();
expect(actions.storeContentFields).toHaveBeenCalled();
});

it('calls addField when the button is clicked', () => {
const { actions, addFieldButton } = setup();
addFieldButton.simulate('click');
Expand Down
2 changes: 2 additions & 0 deletions src/ducks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import drafts from './drafts';
import datafiles from './datafiles';
import staticfiles from './staticfiles';
import utils from './utils';
import siteMeta from './siteMeta';
import notifications from './notifications';

export default combineReducers({
routing: routerReducer,
meta: siteMeta,
config,
pages,
collections,
Expand Down
48 changes: 48 additions & 0 deletions src/ducks/siteMeta.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { getSiteMetaUrl } from '../constants/api';
import { get } from '../utils/fetch';

// Action Types
export const FETCH_SITE_META_REQUEST = 'FETCH_SITE_META_REQUEST';
export const FETCH_SITE_META_SUCCESS = 'FETCH_SITE_META_SUCCESS';
export const FETCH_SITE_META_FAILURE = 'FETCH_SITE_META_FAILURE';

// Actions
export const fetchSiteMeta = () => dispatch => {
dispatch({ type: FETCH_SITE_META_REQUEST });
return get(
getSiteMetaUrl(),
{ type: FETCH_SITE_META_SUCCESS, name: 'site' },
{ type: FETCH_SITE_META_FAILURE, name: 'error' },
dispatch
);
};

// Reducer
export default function siteMeta(
state = {
site: {},
isFetching: false,
},
action
) {
switch (action.type) {
case FETCH_SITE_META_REQUEST:
return {
...state,
isFetching: true,
};
case FETCH_SITE_META_SUCCESS:
return {
...state,
site: action.site,
isFetching: false,
};
case FETCH_SITE_META_FAILURE:
return {
...state,
isFetching: false,
};
default:
return state;
}
}

0 comments on commit ea81df9

Please sign in to comment.