Skip to content
Snippets Groups Projects
Commit 85ac1982 authored by Atte Keinänen's avatar Atte Keinänen
Browse files

Add loading state, fix favorites filter, sync button sizes

parent c1b6dac7
No related branches found
No related tags found
No related merge requests found
import React from "react";
const CollectionActions = ({ children }) =>
<div onClick={(e) => { e.stopPropagation(); e.preventDefault() }}>
<div className="flex align-center" onClick={(e) => { e.stopPropagation(); e.preventDefault() }}>
{React.Children.map(children, (child, index) =>
<span key={index} className="cursor-pointer text-brand-hover mx1">
<div key={index} className="cursor-pointer text-brand-hover mx1">
{child}
</span>
</div>
)}
</div>
......
......@@ -43,7 +43,7 @@ export default class ArchiveCollectionWidget extends Component {
ref="modal"
triggerElement={
<Tooltip tooltip="Archive collection">
<Icon name="archive" />
<Icon size={18} name="archive" />
</Tooltip>
}
title="Archive this collection?"
......
......@@ -50,8 +50,8 @@ export default class CollectionPage extends Component {
<div className="ml-auto">
<CollectionActions>
{ canEdit && <ArchiveCollectionWidget collectionId={this.props.collection.id} onArchived={this.props.goToQuestions}/> }
{ canEdit && <Icon name="pencil" tooltip="Edit collection" onClick={() => this.props.editCollection(this.props.collection.id)} /> }
{ canEdit && <Icon name="lock" tooltip="Set permissions" onClick={() => this.props.editPermissions(this.props.collection.id)} /> }
{ canEdit && <Icon size={18} name="pencil" tooltip="Edit collection" onClick={() => this.props.editCollection(this.props.collection.id)} /> }
{ canEdit && <Icon size={18} name="lock" tooltip="Set permissions" onClick={() => this.props.editPermissions(this.props.collection.id)} /> }
</CollectionActions>
</div>
</div>
......
......@@ -175,11 +175,13 @@ export default class EntityList extends Component {
const section = this.getSection();
const hasEntitiesInPlainState = entityIds.length > 0 || section.section !== "all";
const showActionHeader = (editable && selectedCount > 0);
const showSearchHeader = (hasEntitiesInPlainState && showSearchWidget);
const showEntityFilterWidget = onChangeSection;
return (
<div style={style}>
{ (showActionHeader || showSearchHeader || showEntityFilterWidget) &&
......
......@@ -16,11 +16,12 @@ import EntityList from "./EntityList";
import { search } from "../questions";
import { loadCollections } from "../collections";
import { getAllCollections, getAllEntities } from "../selectors";
import { getLoadingInitialEntities, getAllCollections, getAllEntities } from "../selectors";
import { getUserIsAdmin } from "metabase/selectors/user";
import { replace, push } from "react-router-redux";
import EmptyState from "metabase/components/EmptyState";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
export const CollectionEmptyState = () =>
<div className="flex align-center p2 mt4 bordered border-med border-brand rounded bg-grey-0 text-brand">
......@@ -55,26 +56,25 @@ export const QuestionIndexHeader = ({questions, collections, isAdmin, onSearch})
const hasCollections = collections && collections.length > 0;
const hasQuestionsWithoutCollection = questions && questions.length > 0;
const showTitleAndSearch = hasCollections || hasQuestionsWithoutCollection;
const showSearch = hasCollections || hasQuestionsWithoutCollection;
const showSetPermissionsLink = isAdmin && hasCollections;
return (<div className="flex align-center pt4 pb2">
{ showTitleAndSearch &&
<TitleAndDescription title={ hasCollections ? "Collections of Questions" : "Saved Questions" }/>
}
<div className="flex align-center ml-auto">
{ showTitleAndSearch &&
{ showSearch &&
<ExpandingSearchField className="mr2" onSearch={onSearch}/>
}
<CollectionActions>
{ showSetPermissionsLink &&
<Link to="/collections/permissions">
<Icon name="lock" tooltip="Set permissions for collections"/>
<Icon size={18} name="lock" tooltip="Set permissions for collections"/>
</Link>
}
<Link to="/questions/archive">
<Icon name="viewArchive" tooltip="View the archive"/>
<Icon size={20} name="viewArchive" tooltip="View the archive"/>
</Link>
</CollectionActions>
</div>
......@@ -82,9 +82,10 @@ export const QuestionIndexHeader = ({questions, collections, isAdmin, onSearch})
};
const mapStateToProps = (state, props) => ({
loading: getLoadingInitialEntities(state, props),
questions: getAllEntities(state, props),
collections: getAllCollections(state, props),
isAdmin: getUserIsAdmin(state, props),
isAdmin: getUserIsAdmin(state, props)
});
const mapDispatchToProps = ({
......@@ -101,25 +102,31 @@ export class QuestionIndex extends Component {
}
render () {
const { questions, collections, replace, push, location, isAdmin } = this.props;
const { loading, questions, collections, replace, push, location, isAdmin } = this.props;
const hasCollections = collections && collections.length > 0;
const hasQuestionsWithoutCollection = questions && questions.length > 0;
const showNoCollectionsState = isAdmin && !hasCollections;
const showNoSavedQuestionsState = !hasCollections && !hasQuestionsWithoutCollection;
const showEverythingElseTitle = hasQuestionsWithoutCollection && hasCollections;
const showNoCollectionsState = !loading && isAdmin && !hasCollections;
const showNoSavedQuestionsState = !loading && !hasCollections && !hasQuestionsWithoutCollection;
const hasEntityListSectionQuery = !!location.query.f;
const showEntityList = hasQuestionsWithoutCollection || hasEntityListSectionQuery;
const showEverythingElseTitle = showEntityList && hasCollections;
return (
<div className={cx("relative px4", {"full-height flex flex-column bg-slate-extra-light": showNoSavedQuestionsState})}>
{/* Use loading wrapper only for displaying the loading indicator as EntityList component should always be in DOM */}
{ loading && <LoadingAndErrorWrapper loading={true} noBackground /> }
{ showNoCollectionsState && <CollectionEmptyState /> }
<QuestionIndexHeader
{ !loading && <QuestionIndexHeader
questions={questions}
collections={collections}
isAdmin={isAdmin}
onSearch={this.props.search}
/>
/> }
{ hasCollections && <CollectionButtons collections={collections} isAdmin={isAdmin} push={push} /> }
......@@ -127,7 +134,7 @@ export class QuestionIndex extends Component {
{ showEverythingElseTitle && <h2 className="mt2 mb2">Everything Else</h2> }
<div className={cx({ "hide": !hasQuestionsWithoutCollection })}>
<div className={cx({ "hide": !showEntityList })}>
{/* EntityList loads `questions` according to the query specified in the url query string */}
<EntityList
entityType="cards"
......
......@@ -217,6 +217,7 @@ const initialState = {
lastEntityType: null,
lastEntityQuery: null,
entities: {},
loadingInitialEntities: true,
itemsBySection: {},
searchText: "",
selectedIds: {},
......@@ -240,6 +241,7 @@ export default function(state = initialState, { type, payload, error }) {
return assocIn(state, ["itemsBySection", payload.entityType, payload.entityQuery, "error"], payload.error);
} else {
return (chain(state)
.assoc("loadingInitialEntities", false)
.assoc("lastEntityType", payload.entityType)
.assoc("lastEntityQuery", payload.entityQuery)
.assoc("selectedIds", {})
......
......@@ -7,17 +7,18 @@ import _ from "underscore";
import visualizations from "metabase/visualizations";
import {caseInsensitiveSearch} from "metabase/lib/string"
export const getEntityType = (state, props) => props && props.entityType ? props.entityType : state.questions.lastEntityType;
export const getEntityQuery = (state, props) => props && props.entityQuery ? JSON.stringify(props.entityQuery) : state.questions.lastEntityQuery;
export const getEntityType = (state, props) => props && props.entityType ? props.entityType : state.questions.lastEntityType;
export const getEntityQuery = (state, props) => props && props.entityQuery ? JSON.stringify(props.entityQuery) : state.questions.lastEntityQuery;
export const getSection = (state, props) => props.entityQuery && JSON.stringify(props.entityQuery);
export const getEntities = (state, props) => state.questions.entities
export const getItemsBySection = (state, props) => state.questions.itemsBySection
export const getSection = (state, props) => props.entityQuery && JSON.stringify(props.entityQuery);
export const getLoadingInitialEntities = (state, props) => state.questions.loadingInitialEntities
export const getEntities = (state, props) => state.questions.entities
export const getItemsBySection = (state, props) => state.questions.itemsBySection
export const getSearchText = (state, props) => state.questions.searchText;
export const getSelectedIds = (state, props) => state.questions.selectedIds;
export const getSearchText = (state, props) => state.questions.searchText;
export const getSelectedIds = (state, props) => state.questions.selectedIds;
export const getAllCollections = (state, props) => state.collections.collections;
export const getAllCollections = (state, props) => state.collections.collections;
export const getWritableCollections = createSelector(
[getAllCollections],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment