fix: persistent view style (#4138)

This commit is contained in:
andreascm 2020-08-13 19:21:47 +08:00 committed by GitHub
parent 5baa20bf67
commit 017883f0dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 36 deletions

View File

@ -73,6 +73,8 @@ export const ENTRY_DELETE_FAILURE = 'ENTRY_DELETE_FAILURE';
export const ADD_DRAFT_ENTRY_MEDIA_FILE = 'ADD_DRAFT_ENTRY_MEDIA_FILE';
export const REMOVE_DRAFT_ENTRY_MEDIA_FILE = 'REMOVE_DRAFT_ENTRY_MEDIA_FILE';
export const CHANGE_VIEW_STYLE = 'CHANGE_VIEW_STYLE';
/*
* Simple Action Creators (Internal)
* We still need to export them for tests
@ -240,6 +242,15 @@ export function filterByField(collection: Collection, filter: ViewFilter) {
};
}
export function changeViewStyle(viewStyle: string) {
return {
type: CHANGE_VIEW_STYLE,
payload: {
style: viewStyle,
},
};
}
export function entryPersisting(collection: Collection, entry: EntryMap) {
return {
type: ENTRY_PERSIST_REQUEST,

View File

@ -11,10 +11,9 @@ import CollectionTop from './CollectionTop';
import EntriesCollection from './Entries/EntriesCollection';
import EntriesSearch from './Entries/EntriesSearch';
import CollectionControls from './CollectionControls';
import { sortByField, filterByField } from '../../actions/entries';
import { sortByField, filterByField, changeViewStyle } from '../../actions/entries';
import { selectSortableFields, selectViewFilters } from '../../reducers/collections';
import { selectEntriesSort, selectEntriesFilter } from '../../reducers/entries';
import { VIEW_STYLE_LIST } from '../../constants/collectionViews';
import { selectEntriesSort, selectEntriesFilter, selectViewStyle } from '../../reducers/entries';
const CollectionContainer = styled.div`
margin: ${lengths.pageMargin};
@ -46,18 +45,10 @@ export class Collection extends React.Component {
onSortClick: PropTypes.func.isRequired,
};
state = {
viewStyle: VIEW_STYLE_LIST,
};
renderEntriesCollection = () => {
const { collection, filterTerm } = this.props;
const { collection, filterTerm, viewStyle } = this.props;
return (
<EntriesCollection
collection={collection}
viewStyle={this.state.viewStyle}
filterTerm={filterTerm}
/>
<EntriesCollection collection={collection} viewStyle={viewStyle} filterTerm={filterTerm} />
);
};
@ -71,12 +62,6 @@ export class Collection extends React.Component {
);
};
handleChangeViewStyle = viewStyle => {
if (this.state.viewStyle !== viewStyle) {
this.setState({ viewStyle });
}
};
render() {
const {
collection,
@ -93,6 +78,8 @@ export class Collection extends React.Component {
t,
onFilterClick,
filter,
onChangeViewStyle,
viewStyle,
} = this.props;
let newEntryUrl = collection.get('create') ? getNewEntryUrl(collectionName) : '';
@ -125,8 +112,8 @@ export class Collection extends React.Component {
<>
<CollectionTop collection={collection} newEntryUrl={newEntryUrl} />
<CollectionControls
viewStyle={this.state.viewStyle}
onChangeViewStyle={this.handleChangeViewStyle}
viewStyle={viewStyle}
onChangeViewStyle={onChangeViewStyle}
sortableFields={sortableFields}
onSortClick={onSortClick}
sort={sort}
@ -153,6 +140,7 @@ function mapStateToProps(state, ownProps) {
const sortableFields = selectSortableFields(collection, t);
const viewFilters = selectViewFilters(collection);
const filter = selectEntriesFilter(state.entries, collection.get('name'));
const viewStyle = selectViewStyle(state.entries);
return {
collection,
@ -165,12 +153,14 @@ function mapStateToProps(state, ownProps) {
sortableFields,
viewFilters,
filter,
viewStyle,
};
}
const mapDispatchToProps = {
sortByField,
filterByField,
changeViewStyle,
};
const mergeProps = (stateProps, dispatchProps, ownProps) => {
@ -180,6 +170,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
onSortClick: (key, direction) =>
dispatchProps.sortByField(stateProps.collection, key, direction),
onFilterClick: filter => dispatchProps.filterByField(stateProps.collection, filter),
onChangeViewStyle: viewStyle => dispatchProps.changeViewStyle(viewStyle),
};
};

View File

@ -30,12 +30,10 @@ exports[`Collection should render connected component 1`] = `
filter="Map {}"
sortablefields=""
viewfilters=""
viewstyle="VIEW_STYLE_LIST"
/>
<mock-entries-collection
collection="Map { \\"name\\": \\"pages\\", \\"sortableFields\\": List [], \\"view_filters\\": List [] }"
filterterm=""
viewstyle="VIEW_STYLE_LIST"
/>
</main>
</div>
@ -66,12 +64,9 @@ exports[`Collection should render with collection with create url 1`] = `
collection="Map { \\"name\\": \\"pages\\", \\"sortableFields\\": List [], \\"view_filters\\": List [], \\"create\\": true }"
newentryurl="/collections/pages/new"
/>
<mock-collection-controls
viewstyle="VIEW_STYLE_LIST"
/>
<mock-collection-controls />
<mock-entries-collection
collection="Map { \\"name\\": \\"pages\\", \\"sortableFields\\": List [], \\"view_filters\\": List [], \\"create\\": true }"
viewstyle="VIEW_STYLE_LIST"
/>
</main>
</div>
@ -103,13 +98,10 @@ exports[`Collection should render with collection with create url and path 1`] =
collection="Map { \\"name\\": \\"pages\\", \\"sortableFields\\": List [], \\"view_filters\\": List [], \\"create\\": true }"
newentryurl="/collections/pages/new?path=dir1/dir2"
/>
<mock-collection-controls
viewstyle="VIEW_STYLE_LIST"
/>
<mock-collection-controls />
<mock-entries-collection
collection="Map { \\"name\\": \\"pages\\", \\"sortableFields\\": List [], \\"view_filters\\": List [], \\"create\\": true }"
filterterm="dir1/dir2"
viewstyle="VIEW_STYLE_LIST"
/>
</main>
</div>
@ -140,12 +132,9 @@ exports[`Collection should render with collection without create url 1`] = `
collection="Map { \\"name\\": \\"pages\\", \\"sortableFields\\": List [], \\"view_filters\\": List [], \\"create\\": false }"
newentryurl=""
/>
<mock-collection-controls
viewstyle="VIEW_STYLE_LIST"
/>
<mock-collection-controls />
<mock-entries-collection
collection="Map { \\"name\\": \\"pages\\", \\"sortableFields\\": List [], \\"view_filters\\": List [], \\"create\\": false }"
viewstyle="VIEW_STYLE_LIST"
/>
</main>
</div>

View File

@ -14,6 +14,7 @@ import {
FILTER_ENTRIES_REQUEST,
FILTER_ENTRIES_SUCCESS,
FILTER_ENTRIES_FAILURE,
CHANGE_VIEW_STYLE,
} from '../actions/entries';
import { SEARCH_ENTRIES_SUCCESS } from '../actions/search';
import {
@ -42,12 +43,14 @@ import {
FilterMap,
EntriesFilterRequestPayload,
EntriesFilterFailurePayload,
ChangeViewStylePayload,
} from '../types/redux';
import { folderFormatter } from '../lib/formatters';
import { isAbsolutePath, basename } from 'netlify-cms-lib-util';
import { trim, once, sortBy, set, orderBy } from 'lodash';
import { selectSortDataPath } from './collections';
import { stringTemplate } from 'netlify-cms-lib-widgets';
import { VIEW_STYLE_LIST } from '../constants/collectionViews';
const { keyToPathArray } = stringTemplate;
@ -58,6 +61,7 @@ let page: number;
let slug: string;
const storageSortKey = 'netlify-cms.entries.sort';
const viewStyleKey = 'netlify-cms.entries.viewStyle';
type StorageSortObject = SortObject & { index: number };
type StorageSort = { [collection: string]: { [key: string]: StorageSortObject } };
@ -107,8 +111,30 @@ const persistSort = (sort: Sort | undefined) => {
}
};
const loadViewStyle = once(() => {
const viewStyle = localStorage.getItem(viewStyleKey);
if (viewStyle) {
return viewStyle;
}
localStorage.setItem(viewStyleKey, VIEW_STYLE_LIST);
return VIEW_STYLE_LIST;
});
const clearViewStyle = () => {
localStorage.removeItem(viewStyleKey);
};
const persistViewStyle = (viewStyle: string | undefined) => {
if (viewStyle) {
localStorage.setItem(viewStyleKey, viewStyle);
} else {
clearViewStyle();
}
};
const entries = (
state = Map({ entities: Map(), pages: Map(), sort: loadSort() }),
state = Map({ entities: Map(), pages: Map(), sort: loadSort(), viewStyle: loadViewStyle() }),
action: EntriesAction,
) => {
switch (action.type) {
@ -272,6 +298,16 @@ const entries = (
return newState;
}
case CHANGE_VIEW_STYLE: {
const payload = (action.payload as unknown) as ChangeViewStylePayload;
const { style } = payload;
const newState = state.withMutations(map => {
map.setIn(['viewStyle'], style);
});
persistViewStyle(newState.get('viewStyle') as string);
return newState;
}
default:
return state;
}
@ -308,6 +344,10 @@ export const selectEntriesFilterFields = (entries: Entries, collection: string)
return values;
};
export const selectViewStyle = (entries: Entries) => {
return entries.get('viewStyle');
};
export const selectEntry = (state: Entries, collection: string, slug: string) =>
state.getIn(['entities', `${collection}.${slug}`]);

View File

@ -75,6 +75,7 @@ export type Entries = StaticallyTypedRecord<{
entities: Entities & EntitiesObject;
sort: Sort;
filter: Filter;
viewStyle: string;
}>;
export type Deploys = StaticallyTypedRecord<{}>;
@ -348,6 +349,10 @@ export interface EntriesFilterFailurePayload {
error: Error;
}
export interface ChangeViewStylePayload {
style: string;
}
export interface EntriesMoveSuccessPayload extends EntryPayload {
entries: EntryObject[];
}