function CssTemplatesList()

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>
    </>
  );
}