client/app/pages/query-snippets/QuerySnippetsList.jsx (213 lines of code) (raw):
import { get } from "lodash";
import React from "react";
import Button from "antd/lib/button";
import Modal from "antd/lib/modal";
import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession";
import navigateTo from "@/components/ApplicationArea/navigateTo";
import Paginator from "@/components/Paginator";
import QuerySnippetDialog from "@/components/query-snippets/QuerySnippetDialog";
import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList";
import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource";
import { StateStorage } from "@/components/items-list/classes/StateStorage";
import LoadingState from "@/components/items-list/components/LoadingState";
import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTable";
import wrapSettingsTab from "@/components/SettingsWrapper";
import QuerySnippet from "@/services/query-snippet";
import { currentUser } from "@/services/auth";
import { policy } from "@/services/policy";
import notification from "@/services/notification";
import routes from "@/services/routes";
import "./QuerySnippetsList.less";
const canEditQuerySnippet = querySnippet => currentUser.isAdmin || currentUser.id === get(querySnippet, "user.id");
class QuerySnippetsList extends React.Component {
static propTypes = {
controller: ControllerType.isRequired,
};
listColumns = [
Columns.custom.sortable(
(text, querySnippet) => (
<div>
<a className="table-main-title clickable" onClick={() => this.showSnippetDialog(querySnippet)}>
{querySnippet.trigger}
</a>
</div>
),
{
title: "Trigger",
field: "trigger",
className: "text-nowrap",
}
),
Columns.custom.sortable(text => text, {
title: "Description",
field: "description",
className: "text-nowrap",
}),
Columns.custom(snippet => <code className="snippet-content">{snippet}</code>, {
title: "Snippet",
field: "snippet",
}),
Columns.avatar({ field: "user", className: "p-l-0 p-r-0" }, name => `Created by ${name}`),
Columns.date.sortable({
title: "Created At",
field: "created_at",
className: "text-nowrap",
width: "1%",
}),
Columns.custom(
(text, querySnippet) =>
canEditQuerySnippet(querySnippet) && (
<Button type="danger" className="w-100" onClick={e => this.deleteQuerySnippet(e, querySnippet)}>
Delete
</Button>
),
{
width: "1%",
}
),
];
componentDidMount() {
const { isNewOrEditPage, querySnippetId } = this.props.controller.params;
if (isNewOrEditPage) {
if (querySnippetId === "new") {
if (policy.isCreateQuerySnippetEnabled()) {
this.showSnippetDialog();
} else {
navigateTo("query_snippets", true);
}
} else {
QuerySnippet.get({ id: querySnippetId })
.then(this.showSnippetDialog)
.catch(error => {
this.props.controller.handleError(error);
});
}
}
}
saveQuerySnippet = querySnippet => {
const saveSnippet = querySnippet.id ? QuerySnippet.save : QuerySnippet.create;
return saveSnippet(querySnippet);
};
deleteQuerySnippet = (event, querySnippet) => {
Modal.confirm({
title: "Delete Query Snippet",
content: "Are you sure you want to delete this query snippet?",
okText: "Yes",
okType: "danger",
cancelText: "No",
onOk: () => {
QuerySnippet.delete(querySnippet)
.then(() => {
notification.success("Query snippet deleted successfully.");
this.props.controller.update();
})
.catch(() => {
notification.error("Failed deleting query snippet.");
});
},
});
};
showSnippetDialog = (querySnippet = null) => {
const canSave = !querySnippet || canEditQuerySnippet(querySnippet);
navigateTo("query_snippets/" + get(querySnippet, "id", "new"), true);
const goToSnippetsList = () => navigateTo("query_snippets", true);
QuerySnippetDialog.showModal({
querySnippet,
readOnly: !canSave,
})
.onClose(querySnippet =>
this.saveQuerySnippet(querySnippet).then(() => {
this.props.controller.update();
goToSnippetsList();
})
)
.onDismiss(goToSnippetsList);
};
render() {
const { controller } = this.props;
return (
<div>
<div className="m-b-15">
<Button
type="primary"
onClick={() => this.showSnippetDialog()}
disabled={!policy.isCreateQuerySnippetEnabled()}>
<i className="fa fa-plus m-r-5" />
New Query Snippet
</Button>
</div>
{!controller.isLoaded && <LoadingState className="" />}
{controller.isLoaded && controller.isEmpty && (
<div className="text-center">
There are no query snippets yet.
{policy.isCreateQuerySnippetEnabled() && (
<div className="m-t-5">
<a className="clickable" onClick={() => this.showSnippetDialog()}>
Click here
</a>{" "}
to add one.
</div>
)}
</div>
)}
{controller.isLoaded && !controller.isEmpty && (
<div className="table-responsive">
<ItemsTable
items={controller.pageItems}
columns={this.listColumns}
context={this.actions}
orderByField={controller.orderByField}
orderByReverse={controller.orderByReverse}
toggleSorting={controller.toggleSorting}
/>
<Paginator
totalCount={controller.totalItemsCount}
itemsPerPage={controller.itemsPerPage}
page={controller.page}
onChange={page => controller.updatePagination({ page })}
/>
</div>
)}
</div>
);
}
}
const QuerySnippetsListPage = wrapSettingsTab(
"QuerySnippets.List",
{
permission: "create_query",
title: "Query Snippets",
path: "query_snippets",
order: 5,
},
itemsList(
QuerySnippetsList,
() =>
new ResourceItemsSource({
isPlainList: true,
getRequest() {
return {};
},
getResource() {
return QuerySnippet.query.bind(QuerySnippet);
},
}),
() => new StateStorage({ orderByField: "trigger", itemsPerPage: 10 })
)
);
routes.register(
"QuerySnippets.List",
routeWithUserSession({
path: "/query_snippets",
title: "Query Snippets",
render: pageProps => <QuerySnippetsListPage {...pageProps} currentPage="query_snippets" />,
})
);
routes.register(
"QuerySnippets.NewOrEdit",
routeWithUserSession({
path: "/query_snippets/:querySnippetId",
title: "Query Snippets",
render: pageProps => <QuerySnippetsListPage {...pageProps} currentPage="query_snippets" isNewOrEditPage />,
})
);