diff --git a/authentik/admin/templates/administration/flow/list.html b/authentik/admin/templates/administration/flow/list.html deleted file mode 100644 index c6db5c17a..000000000 --- a/authentik/admin/templates/administration/flow/list.html +++ /dev/null @@ -1,139 +0,0 @@ -{% extends "administration/base.html" %} - -{% load i18n %} -{% load authentik_utils %} - -{% block content %} -
-
-

- - {% trans 'Flows' %} -

-

{% trans "Flows describe a chain of Stages to authenticate, enroll or recover a user. Stages are chosen based on policies applied to them." %}

-
-
-
-
- {% if object_list %} -
-
- {% include 'partials/toolbar_search.html' %} -
- - - {% trans 'Create' %} - -
-
- - - {% trans 'Import' %} - -
-
- -
- {% include 'partials/pagination.html' %} -
-
- - - - - - - - - - - - {% for flow in object_list %} - - - - - - - - {% endfor %} - -
{% trans 'Identifier' %}{% trans 'Designation' %}{% trans 'Stages' %}{% trans 'Policies' %}
- -
{{ flow.slug }}
- {{ flow.name }} -
-
- - {{ flow.designation }} - - - - {{ flow.stages.all|length }} - - - - {{ flow.policies.all|length }} - - - - - {% trans 'Edit' %} - -
-
- - - {% trans 'Delete' %} - -
-
- - {% trans 'Execute' %} - - - {% trans 'Export' %} - -
-
- {% include 'partials/pagination.html' %} -
- {% else %} -
-
- {% include 'partials/toolbar_search.html' %} -
-
-
-
- -

- {% trans 'No Flows.' %} -

-
- {% if request.GET.search != "" %} - {% trans "Your search query doesn't match any flows." %} - {% else %} - {% trans 'Currently no flows exist. Click the button below to create one.' %} - {% endif %} -
- - - {% trans 'Create' %} - -
-
- - - {% trans 'Import' %} - -
-
-
-
- {% endif %} -
-
-{% endblock %} diff --git a/authentik/admin/urls.py b/authentik/admin/urls.py index 5193cee71..499c89947 100644 --- a/authentik/admin/urls.py +++ b/authentik/admin/urls.py @@ -204,7 +204,6 @@ urlpatterns = [ name="stage-invitation-delete", ), # Flows - path("flows/", flows.FlowListView.as_view(), name="flows"), path( "flows/create/", flows.FlowCreateView.as_view(), diff --git a/authentik/admin/views/flows.py b/authentik/admin/views/flows.py index 2c9d4f199..bc0dc530b 100644 --- a/authentik/admin/views/flows.py +++ b/authentik/admin/views/flows.py @@ -29,22 +29,6 @@ from authentik.lib.utils.urls import redirect_with_qs from authentik.lib.views import CreateAssignPermView, bad_request_message -class FlowListView( - LoginRequiredMixin, - PermissionListMixin, - UserPaginateListMixin, - SearchListMixin, - ListView, -): - """Show list of all flows""" - - model = Flow - permission_required = "authentik_flows.view_flow" - ordering = "name" - template_name = "administration/flow/list.html" - search_fields = ["name", "slug", "designation", "title"] - - class FlowCreateView( SuccessMessageMixin, BackSuccessUrlMixin, @@ -59,7 +43,7 @@ class FlowCreateView( permission_required = "authentik_flows.add_flow" template_name = "generic/create.html" - success_url = reverse_lazy("authentik_admin:flows") + success_url = "/" success_message = _("Successfully created Flow") @@ -77,7 +61,7 @@ class FlowUpdateView( permission_required = "authentik_flows.change_flow" template_name = "generic/update.html" - success_url = reverse_lazy("authentik_admin:flows") + success_url = "/" success_message = _("Successfully updated Flow") @@ -88,7 +72,7 @@ class FlowDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageV permission_required = "authentik_flows.delete_flow" template_name = "generic/delete.html" - success_url = reverse_lazy("authentik_admin:flows") + success_url = "/" success_message = _("Successfully deleted Flow") @@ -128,7 +112,7 @@ class FlowImportView(LoginRequiredMixin, FormView): form_class = FlowImportForm template_name = "administration/flow/import.html" - success_url = reverse_lazy("authentik_admin:flows") + success_url = "/" def dispatch(self, request, *args, **kwargs): if not request.user.is_superuser: diff --git a/web/src/api/Flows.ts b/web/src/api/Flows.ts index 49ac4c7d4..0084f36a9 100644 --- a/web/src/api/Flows.ts +++ b/web/src/api/Flows.ts @@ -43,6 +43,9 @@ export class Flow { return r.pagination.count; }); } + static adminUrl(rest: string): string { + return `/administration/flows/${rest}`; + } } export class Stage { diff --git a/web/src/interfaces/AdminInterface.ts b/web/src/interfaces/AdminInterface.ts index b176cd694..d05633365 100644 --- a/web/src/interfaces/AdminInterface.ts +++ b/web/src/interfaces/AdminInterface.ts @@ -39,7 +39,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [ return User.me().then(u => u.is_superuser); }), new SidebarItem("Flows").children( - new SidebarItem("Flows", "/administration/flows/").activeWhen(`^/flows/(?${SLUG_REGEX})$`), + new SidebarItem("Flows", "/flows").activeWhen(`^/flows/(?${SLUG_REGEX})$`), new SidebarItem("Stages", "/administration/stages/"), new SidebarItem("Prompts", "/administration/stages_prompts/"), new SidebarItem("Invitations", "/administration/stages/invitations/"), diff --git a/web/src/pages/flows/FlowListPage.ts b/web/src/pages/flows/FlowListPage.ts new file mode 100644 index 000000000..fe2887697 --- /dev/null +++ b/web/src/pages/flows/FlowListPage.ts @@ -0,0 +1,97 @@ +import { gettext } from "django"; +import { customElement, html, property, TemplateResult } from "lit-element"; +import { Flow } from "../../api/Flows"; +import { AKResponse } from "../../api/Client"; +import { TablePage } from "../../elements/table/TablePage"; + +import "../../elements/buttons/ModalButton"; +import "../../elements/buttons/SpinnerButton"; +import { TableColumn } from "../../elements/table/Table"; + +@customElement("ak-flow-list") +export class FlowListPage extends TablePage { + searchEnabled(): boolean { + return true; + } + pageTitle(): string { + return gettext("Flows"); + } + pageDescription(): string { + return gettext("Flows describe a chain of Stages to authenticate, enroll or recover a user. Stages are chosen based on policies applied to them."); + } + pageIcon(): string { + return gettext("pf-icon pf-icon-process-automation"); + } + + @property() + order = "slug"; + + apiEndpoint(page: number): Promise> { + return Flow.list({ + ordering: this.order, + page: page, + search: this.search || "", + }); + } + + columns(): TableColumn[] { + return [ + new TableColumn("Identifier", "slug"), + new TableColumn("Name", "name"), + new TableColumn("Designation", "designation"), + new TableColumn("Stages"), + new TableColumn("Policies"), + new TableColumn(""), + ]; + } + + row(item: Flow): TemplateResult[] { + return [ + html` + ${item.slug} + `, + html`${item.name}`, + html`${item.designation}`, + html`${item.stages.length}`, + html`${item.policies.length}`, + html` + + + ${gettext("Edit")} + +
+
  + + + ${gettext("Delete")} + +
+
  + + ${gettext("Execute")} +   + + ${gettext("Export")} + + `, + ]; + } + + renderToolbar(): TemplateResult { + return html` + + + ${gettext("Create")} + +
+
  + + + ${gettext("Import")} + +
+
+ ${super.renderToolbar()} + `; + } +} diff --git a/web/src/pages/providers/ProviderViewPage.ts b/web/src/pages/providers/ProviderViewPage.ts index db7686820..20726c8ce 100644 --- a/web/src/pages/providers/ProviderViewPage.ts +++ b/web/src/pages/providers/ProviderViewPage.ts @@ -4,7 +4,7 @@ import { COMMON_STYLES } from "../../common/styles"; import "../../elements/buttons/ModalButton"; import "../../elements/buttons/SpinnerButton"; -import "./elements/utils/LoadingState"; +import "../../elements/utils/LoadingState"; import "./SAMLProviderViewPage"; import "./OAuth2ProviderViewPage"; diff --git a/web/src/routes.ts b/web/src/routes.ts index a56d75510..62b876862 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -7,6 +7,7 @@ import "./pages/applications/ApplicationListPage"; import "./pages/applications/ApplicationViewPage"; import "./pages/sources/SourcesListPage"; import "./pages/sources/SourceViewPage"; +import "./pages/flows/FlowListPage"; import "./pages/flows/FlowViewPage"; import "./pages/events/EventListPage"; import "./pages/events/EventInfoPage"; @@ -35,6 +36,7 @@ export const ROUTES: Route[] = [ new Route(new RegExp(`^/sources/(?${SLUG_REGEX})$`)).then((args) => { return html``; }), + new Route(new RegExp(`^/flows$`), html``), new Route(new RegExp(`^/flows/(?${SLUG_REGEX})$`)).then((args) => { return html``; }),