client/app/pages/queries-list/QueriesList.jsx (218 lines of code) (raw):
import React, { useEffect, useRef } from "react";
import cx from "classnames";
import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession";
import Link from "@/components/Link";
import PageHeader from "@/components/PageHeader";
import Paginator from "@/components/Paginator";
import DynamicComponent from "@/components/DynamicComponent";
import { QueryTagsControl } from "@/components/tags-control/TagsControl";
import SchedulePhrase from "@/components/queries/SchedulePhrase";
import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList";
import useItemsListExtraActions from "@/components/items-list/hooks/useItemsListExtraActions";
import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource";
import { UrlStateStorage } from "@/components/items-list/classes/StateStorage";
import * as Sidebar from "@/components/items-list/components/Sidebar";
import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTable";
import Layout from "@/components/layouts/ContentWithSidebar";
import { Query } from "@/services/query";
import { currentUser } from "@/services/auth";
import location from "@/services/location";
import routes from "@/services/routes";
import QueriesListEmptyState from "./QueriesListEmptyState";
import "./queries-list.css";
const sidebarMenu = [
{
key: "all",
href: "queries",
title: "All Queries",
icon: () => <Sidebar.MenuIcon icon="fa fa-code" />,
},
{
key: "my",
href: "queries/my",
title: "My Queries",
icon: () => <Sidebar.ProfileImage user={currentUser} />,
},
{
key: "favorites",
href: "queries/favorites",
title: "Favorites",
icon: () => <Sidebar.MenuIcon icon="fa fa-star" />,
},
{
key: "archive",
href: "queries/archive",
title: "Archived",
icon: () => <Sidebar.MenuIcon icon="fa fa-archive" />,
},
];
const listColumns = [
Columns.favorites({ className: "p-r-0" }),
Columns.custom.sortable(
(text, item) => (
<React.Fragment>
<Link className="table-main-title" href={"queries/" + item.id}>
{item.name}
</Link>
<QueryTagsControl className="d-block" tags={item.tags} isDraft={item.is_draft} isArchived={item.is_archived} />
</React.Fragment>
),
{
title: "Name",
field: "name",
width: null,
}
),
Columns.custom((text, item) => item.user.name, { title: "Created By", width: "1%" }),
Columns.dateTime.sortable({ title: "Created At", field: "created_at", width: "1%" }),
Columns.dateTime.sortable({
title: "Last Executed At",
field: "retrieved_at",
orderByField: "executed_at",
width: "1%",
}),
Columns.custom.sortable((text, item) => <SchedulePhrase schedule={item.schedule} isNew={item.isNew()} />, {
title: "Refresh Schedule",
field: "schedule",
width: "1%",
}),
];
function QueriesListExtraActions(props) {
return <DynamicComponent name="QueriesList.Actions" {...props} />;
}
function QueriesList({ controller }) {
const controllerRef = useRef();
controllerRef.current = controller;
useEffect(() => {
const unlistenLocationChanges = location.listen((unused, action) => {
const searchTerm = location.search.q || "";
if (action === "PUSH" && searchTerm !== controllerRef.current.searchTerm) {
controllerRef.current.updateSearch(searchTerm);
}
});
return () => {
unlistenLocationChanges();
};
}, []);
const {
areExtraActionsAvailable,
listColumns: tableColumns,
Component: ExtraActionsComponent,
selectedItems,
} = useItemsListExtraActions(controller, listColumns, QueriesListExtraActions);
return (
<div className="page-queries-list">
<div className="container">
<PageHeader
title={controller.params.pageTitle}
actions={
currentUser.hasPermission("create_query") ? (
<Link.Button block type="primary" href="queries/new">
<i className="fa fa-plus m-r-5" aria-hidden="true" />
New Query
</Link.Button>
) : null
}
/>
<Layout>
<Layout.Sidebar className="m-b-0">
<Sidebar.SearchInput
placeholder="Search Queries..."
label="Search queries"
value={controller.searchTerm}
onChange={controller.updateSearch}
/>
<Sidebar.Menu items={sidebarMenu} selected={controller.params.currentPage} />
<Sidebar.Tags url="api/queries/tags" onChange={controller.updateSelectedTags} showUnselectAll />
</Layout.Sidebar>
<Layout.Content>
{controller.isLoaded && controller.isEmpty ? (
<QueriesListEmptyState
page={controller.params.currentPage}
searchTerm={controller.searchTerm}
selectedTags={controller.selectedTags}
/>
) : (
<React.Fragment>
<div className={cx({ "m-b-10": areExtraActionsAvailable })}>
<ExtraActionsComponent selectedItems={selectedItems} />
</div>
<div className="bg-white tiled table-responsive">
<ItemsTable
items={controller.pageItems}
loading={!controller.isLoaded}
columns={tableColumns}
orderByField={controller.orderByField}
orderByReverse={controller.orderByReverse}
toggleSorting={controller.toggleSorting}
/>
<Paginator
showPageSizeSelect
totalCount={controller.totalItemsCount}
pageSize={controller.itemsPerPage}
onPageSizeChange={itemsPerPage => controller.updatePagination({ itemsPerPage })}
page={controller.page}
onChange={page => controller.updatePagination({ page })}
/>
</div>
</React.Fragment>
)}
</Layout.Content>
</Layout>
</div>
</div>
);
}
QueriesList.propTypes = {
controller: ControllerType.isRequired,
};
const QueriesListPage = itemsList(
QueriesList,
() =>
new ResourceItemsSource({
getResource({ params: { currentPage } }) {
return {
all: Query.query.bind(Query),
my: Query.myQueries.bind(Query),
favorites: Query.favorites.bind(Query),
archive: Query.archive.bind(Query),
}[currentPage];
},
getItemProcessor() {
return item => new Query(item);
},
}),
() => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true })
);
routes.register(
"Queries.List",
routeWithUserSession({
path: "/queries",
title: "Queries",
render: pageProps => <QueriesListPage {...pageProps} currentPage="all" />,
})
);
routes.register(
"Queries.Favorites",
routeWithUserSession({
path: "/queries/favorites",
title: "Favorite Queries",
render: pageProps => <QueriesListPage {...pageProps} currentPage="favorites" />,
})
);
routes.register(
"Queries.Archived",
routeWithUserSession({
path: "/queries/archive",
title: "Archived Queries",
render: pageProps => <QueriesListPage {...pageProps} currentPage="archive" />,
})
);
routes.register(
"Queries.My",
routeWithUserSession({
path: "/queries/my",
title: "My Queries",
render: pageProps => <QueriesListPage {...pageProps} currentPage="my" />,
})
);