in superset-frontend/src/pages/CssTemplateList/index.tsx [54:328]
function CssTemplatesList({
addDangerToast,
addSuccessToast,
user,
}: CssTemplatesListProps) {
const theme = useTheme();
const {
state: {
loading,
resourceCount: templatesCount,
resourceCollection: templates,
bulkSelectEnabled,
},
hasPerm,
fetchData,
refreshData,
toggleBulkSelect,
} = useListViewResource<TemplateObject>(
'css_template',
t('CSS templates'),
addDangerToast,
);
const [cssTemplateModalOpen, setCssTemplateModalOpen] =
useState<boolean>(false);
const [currentCssTemplate, setCurrentCssTemplate] =
useState<TemplateObject | null>(null);
const canCreate = hasPerm('can_write');
const canEdit = hasPerm('can_write');
const canDelete = hasPerm('can_write');
const [templateCurrentlyDeleting, setTemplateCurrentlyDeleting] =
useState<TemplateObject | null>(null);
const handleTemplateDelete = ({ id, template_name }: TemplateObject) => {
SupersetClient.delete({
endpoint: `/api/v1/css_template/${id}`,
}).then(
() => {
refreshData();
setTemplateCurrentlyDeleting(null);
addSuccessToast(t('Deleted: %s', template_name));
},
createErrorHandler(errMsg =>
addDangerToast(
t('There was an issue deleting %s: %s', template_name, errMsg),
),
),
);
};
const handleBulkTemplateDelete = (templatesToDelete: TemplateObject[]) => {
SupersetClient.delete({
endpoint: `/api/v1/css_template/?q=${rison.encode(
templatesToDelete.map(({ id }) => id),
)}`,
}).then(
({ json = {} }) => {
refreshData();
addSuccessToast(json.message);
},
createErrorHandler(errMsg =>
addDangerToast(
t('There was an issue deleting the selected templates: %s', errMsg),
),
),
);
};
function handleCssTemplateEdit(cssTemplate: TemplateObject) {
setCurrentCssTemplate(cssTemplate);
setCssTemplateModalOpen(true);
}
const initialSort = [{ id: 'template_name', desc: true }];
const columns = useMemo(
() => [
{
accessor: 'template_name',
Header: t('Name'),
},
{
Cell: ({
row: {
original: {
changed_on_delta_humanized: changedOn,
changed_by: changedBy,
},
},
}: any) => <ModifiedInfo date={changedOn} user={changedBy} />,
Header: t('Last modified'),
accessor: 'changed_on_delta_humanized',
size: 'xl',
disableSortBy: true,
},
{
Cell: ({ row: { original } }: any) => {
const handleEdit = () => handleCssTemplateEdit(original);
const handleDelete = () => setTemplateCurrentlyDeleting(original);
const actions = [
canEdit
? {
label: 'edit-action',
tooltip: t('Edit template'),
placement: 'bottom',
icon: 'EditOutlined',
onClick: handleEdit,
}
: null,
canDelete
? {
label: 'delete-action',
tooltip: t('Delete template'),
placement: 'bottom',
icon: 'DeleteOutlined',
onClick: handleDelete,
}
: null,
].filter(item => !!item);
return <ActionsBar actions={actions as ActionProps[]} />;
},
Header: t('Actions'),
id: 'actions',
disableSortBy: true,
hidden: !canEdit && !canDelete,
size: 'xl',
},
{
accessor: QueryObjectColumns.ChangedBy,
hidden: true,
},
],
[canDelete, canCreate],
);
const menuData: SubMenuProps = {
name: t('CSS templates'),
};
const subMenuButtons: SubMenuProps['buttons'] = [];
if (canCreate) {
subMenuButtons.push({
name: (
<>
<Icons.PlusOutlined
iconColor={theme.colors.primary.light5}
iconSize="m"
css={css`
margin: 'auto ${theme.gridUnit * 2}px auto 0';
vertical-align: text-top;
`}
/>
{t('CSS template')}
</>
),
buttonStyle: 'primary',
onClick: () => {
setCurrentCssTemplate(null);
setCssTemplateModalOpen(true);
},
});
}
if (canDelete) {
subMenuButtons.push({
name: t('Bulk select'),
onClick: toggleBulkSelect,
buttonStyle: 'secondary',
});
}
menuData.buttons = subMenuButtons;
const filters: Filters = useMemo(
() => [
{
Header: t('Name'),
key: 'search',
id: 'template_name',
input: 'search',
operator: FilterOperator.Contains,
},
{
Header: t('Modified by'),
key: 'changed_by',
id: 'changed_by',
input: 'select',
operator: FilterOperator.RelationOneMany,
unfilteredLabel: t('All'),
fetchSelects: createFetchRelated(
'css_template',
'changed_by',
createErrorHandler(errMsg =>
t(
'An error occurred while fetching dataset datasource values: %s',
errMsg,
),
),
user,
),
paginate: true,
},
],
[],
);
return (
<>
<SubMenu {...menuData} />
<CssTemplateModal
addDangerToast={addDangerToast}
cssTemplate={currentCssTemplate}
onCssTemplateAdd={() => refreshData()}
onHide={() => setCssTemplateModalOpen(false)}
show={cssTemplateModalOpen}
/>
{templateCurrentlyDeleting && (
<DeleteModal
description={t('This action will permanently delete the template.')}
onConfirm={() => {
if (templateCurrentlyDeleting) {
handleTemplateDelete(templateCurrentlyDeleting);
}
}}
onHide={() => setTemplateCurrentlyDeleting(null)}
open
title={t('Delete Template?')}
/>
)}
<ConfirmStatusChange
title={t('Please confirm')}
description={t(
'Are you sure you want to delete the selected templates?',
)}
onConfirm={handleBulkTemplateDelete}
>
{confirmDelete => {
const bulkActions: ListViewProps['bulkActions'] = canDelete
? [
{
key: 'delete',
name: t('Delete'),
onSelect: confirmDelete,
type: 'danger',
},
]
: [];
return (
<ListView<TemplateObject>
className="css-templates-list-view"
columns={columns}
count={templatesCount}
data={templates}
fetchData={fetchData}
filters={filters}
initialSort={initialSort}
loading={loading}
pageSize={PAGE_SIZE}
bulkActions={bulkActions}
bulkSelectEnabled={bulkSelectEnabled}
disableBulkSelect={toggleBulkSelect}
addDangerToast={addDangerToast}
addSuccessToast={addSuccessToast}
refreshData={refreshData}
/>
);
}}
</ConfirmStatusChange>
</>
);
}