Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dashboard list filters & favouriting & archival [WIP] #4868

Merged
merged 27 commits into from
Apr 28, 2017
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
91b6560
Rename FilterWidget => ListFilterWidget because FilterWidget exists a…
attekei Apr 24, 2017
d472b8a
Merge branch 'master' of https://github.com/metabase/metabase into da…
attekei Apr 25, 2017
7645460
Add a filter list and ability to change its value
attekei Apr 25, 2017
b8e6a27
Create section filter for showing user's own dashboards
attekei Apr 25, 2017
7dde285
Favorites filter, rudimentary favoriting button
attekei Apr 25, 2017
00751d3
Polish, massage and nurture the favorite button
attekei Apr 25, 2017
7d4ebc2
Mock the favoriting API call
attekei Apr 25, 2017
0d176cc
Dashboard archival with undo
attekei Apr 25, 2017
6b7276d
Dashboard archive list
attekei Apr 26, 2017
4d04fc6
Merge branch 'master' of https://github.com/metabase/metabase into da…
attekei Apr 26, 2017
4df781f
Add missing :archived clause to dashboards-list
attekei Apr 26, 2017
ec43735
Use real API, create a separate archive list page
attekei Apr 26, 2017
d903f19
Fix the margin between archive/favourites buttons and ellipsified title
attekei Apr 26, 2017
c27ef25
Use dashboard icon for 'All dashboards' filter item
attekei Apr 26, 2017
f275da1
Merge branch 'master' of https://github.com/metabase/metabase into da…
attekei Apr 27, 2017
fb5dbb5
Correctly formatted archive page, empty state for filters
attekei Apr 27, 2017
a62ab78
Add empty state ui to dashboards archive
attekei Apr 27, 2017
e03e778
Ensure that dashboards are always listed in alphabetic order
attekei Apr 27, 2017
0f03557
Replace dashboard remove button with archive button
attekei Apr 27, 2017
f2e5f98
Fix flickering by giving to the empty search result image an explicit…
attekei Apr 27, 2017
c21c635
Dashboard item UI changes
attekei Apr 27, 2017
f5929aa
Cool archival animation
attekei Apr 27, 2017
99f14c5
Experimental list item crossfade
attekei Apr 27, 2017
3e0dd15
Refactor and comment animation code
attekei Apr 27, 2017
280339f
Flow types
attekei Apr 28, 2017
ece54ff
Fix and extend E2E tests (still disabled in CI due to Sauce problems)
attekei Apr 28, 2017
d3ca537
Fix style, merge classNames in Icon
attekei Apr 28, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/interfaces/underscore.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ declare module "underscore" {

// TODO: improve this
declare function chain<S>(obj: S): any;

declare function constant<S>(obj: S): () => S;
}
5 changes: 3 additions & 2 deletions frontend/src/metabase/components/EmptyState.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ type EmptyStateProps = {
title?: string,
icon?: string,
image?: string,
imageHeight?: string, // for reducing ui flickering when the image is loading
imageClassName?: string,
action?: string,
link?: string,
onActionClick?: () => void,
smallDescription?: boolean
}

const EmptyState = ({title, message, icon, image, imageClassName, action, link, onActionClick, smallDescription = false}: EmptyStateProps) =>
const EmptyState = ({title, message, icon, image, imageHeight, imageClassName, action, link, onActionClick, smallDescription = false}: EmptyStateProps) =>
<div className="text-centered text-brand-light my2" style={smallDescription ? {} : {width: "350px"}}>
{ title &&
<h2 className="text-brand mb4">{title}</h2>
Expand All @@ -31,7 +32,7 @@ const EmptyState = ({title, message, icon, image, imageClassName, action, link,
<Icon name={icon} size={40}/>
}
{ image &&
<img src={`${image}.png`} width="300px" alt={message} srcSet={`${image}@2x.png 2x`}
<img src={`${image}.png`} width="300px" height={imageHeight} alt={message} srcSet={`${image}@2x.png 2x`}
className={imageClassName}/>
}
<div className="flex justify-center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import React, { Component } from "react";
import Icon from "metabase/components/Icon";
import PopoverWithTrigger from "./PopoverWithTrigger";

type FilterWidgetItem = {
export type ListFilterWidgetItem = {
id: string,
name: string,
icon: string
}

export default class FilterWidget extends Component {
export default class ListFilterWidget extends Component {
props: {
items: FilterWidgetItem[],
activeItem: FilterWidgetItem,
onChange: (FilterWidgetItem) => void
items: ListFilterWidgetItem[],
activeItem: ListFilterWidgetItem,
onChange: (ListFilterWidgetItem) => void
};

popoverRef: PopoverWithTrigger;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/metabase/css/core/colors.css
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,4 @@
color: #CFE4F5
}
.text-slate { color: #606E7B; }

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from "prop-types";

import ModalContent from "metabase/components/ModalContent.jsx";

export default class DeleteDashboardModal extends Component {
export default class ArchiveDashboardModal extends Component {
constructor(props, context) {
super(props, context);

Expand All @@ -16,12 +16,12 @@ export default class DeleteDashboardModal extends Component {
dashboard: PropTypes.object.isRequired,

onClose: PropTypes.func,
onDelete: PropTypes.func
onArchive: PropTypes.func
};

async deleteDashboard() {
async archiveDashboard() {
try {
this.props.onDelete(this.props.dashboard);
this.props.onArchive(this.props.dashboard);
} catch (error) {
this.setState({ error });
}
Expand All @@ -46,15 +46,15 @@ export default class DeleteDashboardModal extends Component {

return (
<ModalContent
title="Delete Dashboard"
title="Archive Dashboard"
onClose={this.props.onClose}
>
<div className="Form-inputs mb4">
<p>Are you sure you want to do this?</p>
</div>

<div className="Form-actions">
<button className="Button Button--danger" onClick={() => this.deleteDashboard()}>Yes</button>
<button className="Button Button--danger" onClick={() => this.archiveDashboard()}>Yes</button>
<button className="Button Button--primary ml1" onClick={this.props.onClose}>No</button>
{formError}
</div>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/metabase/dashboard/components/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type Props = {

initialize: () => Promise<void>,
addCardToDashboard: ({ dashId: DashCardId, cardId: CardId }) => void,
deleteDashboard: (dashboardId: DashboardId) => void,
archiveDashboard: (dashboardId: DashboardId) => void,
fetchCards: (filterMode?: string) => void,
fetchDashboard: (dashboardId: DashboardId, queryParams: ?QueryParams) => void,
fetchRevisions: ({ entity: string, id: number }) => void,
Expand Down Expand Up @@ -91,7 +91,7 @@ export default class Dashboard extends Component<*, Props, State> {
parameters: PropTypes.array,

addCardToDashboard: PropTypes.func.isRequired,
deleteDashboard: PropTypes.func.isRequired,
archiveDashboard: PropTypes.func.isRequired,
fetchCards: PropTypes.func.isRequired,
fetchDashboard: PropTypes.func.isRequired,
fetchRevisions: PropTypes.func.isRequired,
Expand Down
24 changes: 12 additions & 12 deletions frontend/src/metabase/dashboard/components/DashboardHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import PropTypes from "prop-types";

import ActionButton from "metabase/components/ActionButton.jsx";
import AddToDashSelectQuestionModal from "./AddToDashSelectQuestionModal.jsx";
import DeleteDashboardModal from "./DeleteDashboardModal.jsx";
import ArchiveDashboardModal from "./ArchiveDashboardModal.jsx";
import Header from "metabase/components/Header.jsx";
import HistoryModal from "metabase/components/HistoryModal.jsx";
import Icon from "metabase/components/Icon.jsx";
Expand Down Expand Up @@ -47,7 +47,7 @@ type Props = {
parameters: React$Element<*>[],

addCardToDashboard: ({ dashId: DashCardId, cardId: CardId }) => void,
deleteDashboard: (dashboardId: DashboardId) => void,
archiveDashboard: (dashboardId: DashboardId) => void,
fetchCards: (filterMode?: string) => void,
fetchDashboard: (dashboardId: DashboardId, queryParams: ?QueryParams) => void,
fetchRevisions: ({ entity: string, id: number }) => void,
Expand Down Expand Up @@ -87,7 +87,7 @@ export default class DashboardHeader extends Component<*, Props, State> {
refreshElapsed: PropTypes.number,

addCardToDashboard: PropTypes.func.isRequired,
deleteDashboard: PropTypes.func.isRequired,
archiveDashboard: PropTypes.func.isRequired,
fetchCards: PropTypes.func.isRequired,
fetchDashboard: PropTypes.func.isRequired,
fetchRevisions: PropTypes.func.isRequired,
Expand Down Expand Up @@ -123,9 +123,9 @@ export default class DashboardHeader extends Component<*, Props, State> {
this.onDoneEditing();
}

async onDelete() {
await this.props.deleteDashboard(this.props.dashboard.id);
this.props.onChangeLocation("/dashboard");
async onArchive() {
await this.props.archiveDashboard(this.props.dashboard.id);
this.props.onChangeLocation("/dashboards");
}

// 1. fetch revisions
Expand All @@ -150,15 +150,15 @@ export default class DashboardHeader extends Component<*, Props, State> {
Cancel
</a>,
<ModalWithTrigger
key="delete"
ref="deleteDashboardModal"
key="archive"
ref="archiveDashboardModal"
triggerClasses="Button Button--small"
triggerElement="Delete"
triggerElement="Archive"
>
<DeleteDashboardModal
<ArchiveDashboardModal
dashboard={this.props.dashboard}
onClose={() => this.refs.deleteDashboardModal.toggle()}
onDelete={() => this.onDelete()}
onClose={() => this.refs.ArchiveDashboardModal.toggle()}
onArchive={() => this.onArchive()}
/>
</ModalWithTrigger>,
<ActionButton
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/metabase/dashboard/containers/DashboardApp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { getIsEditing, getIsEditingParameter, getIsDirty, getDashboardComplete,
import { getUserIsAdmin } from "metabase/selectors/user";

import * as dashboardActions from "../dashboard";
import {deleteDashboard} from "metabase/dashboards/dashboards"
import {archiveDashboard} from "metabase/dashboards/dashboards"

const mapStateToProps = (state, props) => {
return {
Expand All @@ -40,7 +40,7 @@ const mapStateToProps = (state, props) => {

const mapDispatchToProps = {
...dashboardActions,
deleteDashboard,
archiveDashboard,
fetchDatabaseMetadata,
setErrorPage,
onChangeLocation: push
Expand Down
Loading