From 4c2de80f927543aa44c46070f10cd0a2a6e54d29 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Tue, 17 Mar 2026 11:49:35 +0100 Subject: [PATCH 1/6] fix sorting by "modified_by" column in gateways and edges tables --- web/src/pages/EdgesPage/EdgesTable.tsx | 6 +++--- web/src/pages/LocationsPage/components/GatewaysTable.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/src/pages/EdgesPage/EdgesTable.tsx b/web/src/pages/EdgesPage/EdgesTable.tsx index 0bb409ca5d..34b3e6cf83 100644 --- a/web/src/pages/EdgesPage/EdgesTable.tsx +++ b/web/src/pages/EdgesPage/EdgesTable.tsx @@ -175,15 +175,15 @@ export const EdgesTable = () => { ), }), - columnHelper.display({ - id: 'modified_by', + columnHelper.accessor('modified_by', { size: 200, minSize: 175, header: m.edges_col_modified_by(), enableSorting: true, + sortingFn: 'text', cell: (info) => ( - {displayModifiedBy(info.row.original)} + {info.getValue()} ), }), diff --git a/web/src/pages/LocationsPage/components/GatewaysTable.tsx b/web/src/pages/LocationsPage/components/GatewaysTable.tsx index f39cd7c549..b173a9886c 100644 --- a/web/src/pages/LocationsPage/components/GatewaysTable.tsx +++ b/web/src/pages/LocationsPage/components/GatewaysTable.tsx @@ -145,15 +145,15 @@ export const GatewaysTable = () => { ), }), - columnHelper.display({ - id: 'modified_by', + columnHelper.accessor('modified_by', { size: 175, minSize: 175, header: m.edges_col_modified_by(), enableSorting: true, + sortingFn: 'text', cell: (info) => ( - {displayModifiedBy(info.row.original)} + {info.getValue()} ), }), From 8aea04d0f05a443bd7b2e20beb62186fa97daf75 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Tue, 17 Mar 2026 12:07:21 +0100 Subject: [PATCH 2/6] properly close the AddUserModal --- .../UsersOverviewPage/modals/AddUserModal/AddUserModal.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/src/pages/UsersOverviewPage/modals/AddUserModal/AddUserModal.tsx b/web/src/pages/UsersOverviewPage/modals/AddUserModal/AddUserModal.tsx index 0f735ad947..0f42bfabbd 100644 --- a/web/src/pages/UsersOverviewPage/modals/AddUserModal/AddUserModal.tsx +++ b/web/src/pages/UsersOverviewPage/modals/AddUserModal/AddUserModal.tsx @@ -479,7 +479,9 @@ const AddUserModalForm = () => { cancelProps={{ disabled: isSubmitting, text: m.controls_cancel(), - onClick: () => {}, + onClick: () => { + useAddUserModal.setState({ isOpen: false }); + }, }} submitProps={{ text: m.modal_add_user_submit(), From 1cb70fa970921626a5b11ac3f09b31be4efaf65c Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Tue, 17 Mar 2026 13:19:37 +0100 Subject: [PATCH 3/6] fix errors when user doesn't select any destinations for ACL --- web/messages/en/form.json | 2 ++ web/src/pages/CERulePage/CERulePage.tsx | 26 ++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/web/messages/en/form.json b/web/messages/en/form.json index 0775653714..79c45f073f 100644 --- a/web/messages/en/form.json +++ b/web/messages/en/form.json @@ -13,6 +13,8 @@ "form_error_required": "Field is required", "form_error_token": "Token is not valid", "form_error_invalid": "Field is invalid", + "form_error_no_destination": "Select a predefined destination or add manual destination.", + "form_error_no_predefined_destination": "No predefined destinations available. Add manual destination or create a destination first.", "form_error_forbidden_char": "Field contains forbidden characters", "form_error_username_taken": "Username is already in use", "form_error_email_reserved": "Email is already in use", diff --git a/web/src/pages/CERulePage/CERulePage.tsx b/web/src/pages/CERulePage/CERulePage.tsx index 72b91d9347..d7e8eff960 100644 --- a/web/src/pages/CERulePage/CERulePage.tsx +++ b/web/src/pages/CERulePage/CERulePage.tsx @@ -618,7 +618,6 @@ const Content = ({ rule: initialRule }: Props) => { }); }} /> - {selectedDestinations.length > 0 && (
@@ -649,6 +648,15 @@ const Content = ({ rule: initialRule }: Props) => { }} )} + + {() => ( + 0, + )} + /> + )} +

{`Manually configure destinations parameters for this rule.`}

@@ -1118,10 +1126,22 @@ const AliasDataBlock = ({ values }: AliasDataBlockProps) => { ); }; -const DestinationSelectionError = () => { +const DestinationSelectionError = ({ + hasPredefinedDestinations, +}: { + hasPredefinedDestinations: boolean; +}) => { const error = useFormFieldError(); + if (!error) return null; + return ( - + ); }; From 98b186c32a3982a7102479d188c0d33005d88041 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Tue, 17 Mar 2026 13:19:59 +0100 Subject: [PATCH 4/6] fix edges and gateways filtering --- web/src/pages/EdgesPage/EdgesTable.tsx | 9 ++++++--- web/src/pages/LocationsPage/components/GatewaysTable.tsx | 4 +--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/web/src/pages/EdgesPage/EdgesTable.tsx b/web/src/pages/EdgesPage/EdgesTable.tsx index 34b3e6cf83..d608f823e8 100644 --- a/web/src/pages/EdgesPage/EdgesTable.tsx +++ b/web/src/pages/EdgesPage/EdgesTable.tsx @@ -43,8 +43,6 @@ const isConnected = (edge: EdgeInfo) => { return connected > disconnected; }; -const displayModifiedBy = (edge: EdgeInfo) => `${edge.modified_by}`; - const getStatusBadge = (edge: EdgeInfo) => { if (!edge.enabled) { return ( @@ -112,7 +110,12 @@ export const EdgesTable = () => { const transformedData = useMemo(() => { let data = edges; if (search.length) { - data = data.filter((u) => u.name.toLowerCase().includes(search.toLowerCase())); + const query = search.toLowerCase(); + data = data.filter( + (edge) => + edge.name.toLowerCase().includes(query) || + edge.modified_by.toLowerCase().includes(query), + ); } return data; diff --git a/web/src/pages/LocationsPage/components/GatewaysTable.tsx b/web/src/pages/LocationsPage/components/GatewaysTable.tsx index b173a9886c..fa8276994b 100644 --- a/web/src/pages/LocationsPage/components/GatewaysTable.tsx +++ b/web/src/pages/LocationsPage/components/GatewaysTable.tsx @@ -28,8 +28,6 @@ type RowData = GatewayInfo; const columnHelper = createColumnHelper(); -const displayModifiedBy = (gateway: GatewayInfo) => `${gateway.modified_by}`; - const getStatusBadge = (gateway: GatewayInfo) => { if (!gateway.enabled) { return ( @@ -69,7 +67,7 @@ export const GatewaysTable = () => { if (query.length > 0) { data = data.filter((gateway) => { - const modifiedBy = displayModifiedBy(gateway).toLowerCase(); + const modifiedBy = gateway.modified_by.toLowerCase(); return ( gateway.name.toLowerCase().includes(query) || gateway.location_name.toLowerCase().includes(query) || From 522ae758aad18a8ccec9376bbccfb31e2c2e376a Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Wed, 18 Mar 2026 07:27:20 +0100 Subject: [PATCH 5/6] correct ACL rules validation errors --- web/messages/en/form.json | 4 +-- web/src/pages/CERulePage/CERulePage.tsx | 41 ++++++++++++------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/web/messages/en/form.json b/web/messages/en/form.json index 79c45f073f..aa172e8ab9 100644 --- a/web/messages/en/form.json +++ b/web/messages/en/form.json @@ -13,8 +13,8 @@ "form_error_required": "Field is required", "form_error_token": "Token is not valid", "form_error_invalid": "Field is invalid", - "form_error_no_destination": "Select a predefined destination or add manual destination.", - "form_error_no_predefined_destination": "No predefined destinations available. Add manual destination or create a destination first.", + "form_error_no_destination": "Select one of the options.", + "form_error_no_predefined_destination": "Configure manual destination.", "form_error_forbidden_char": "Field contains forbidden characters", "form_error_username_taken": "Username is already in use", "form_error_email_reserved": "Email is already in use", diff --git a/web/src/pages/CERulePage/CERulePage.tsx b/web/src/pages/CERulePage/CERulePage.tsx index d7e8eff960..37ff1ee039 100644 --- a/web/src/pages/CERulePage/CERulePage.tsx +++ b/web/src/pages/CERulePage/CERulePage.tsx @@ -184,6 +184,7 @@ const Content = ({ rule: initialRule }: Props) => { }, [users]); const { data: destinations } = useQuery(getAppliedDestinationsQueryOptions); + const hasPredefinedDestinations = Boolean(destinations && destinations.length > 0); const destinationsOptions = useMemo(() => { if (isPresent(destinations)) { @@ -438,13 +439,19 @@ const Content = ({ rule: initialRule }: Props) => { } } else if (vals.destinations.size === 0) { ctx.addIssue({ - path: ['destinations'], + path: [ + hasPredefinedDestinations + ? 'destinations' + : 'use_manual_destination_settings', + ], code: 'custom', - message: m.form_error_required(), + message: hasPredefinedDestinations + ? m.form_error_no_destination() + : m.form_error_no_predefined_destination(), }); } }), - [restrictDevices, restrictGroups, restrictUsers], + [hasPredefinedDestinations, restrictDevices, restrictGroups, restrictUsers], ); type FormFields = z.infer; @@ -648,15 +655,6 @@ const Content = ({ rule: initialRule }: Props) => { }} )} - - {() => ( - 0, - )} - /> - )} -

{`Manually configure destinations parameters for this rule.`}

@@ -821,6 +819,13 @@ const Content = ({ rule: initialRule }: Props) => { )} + + {() => ( + + )} + @@ -1133,15 +1138,7 @@ const DestinationSelectionError = ({ }) => { const error = useFormFieldError(); - if (!error) return null; + if (!hasPredefinedDestinations || !error) return null; - return ( - - ); + return ; }; From 16572a4a4df7817da1d1f8c974e0e1bf5f5738a5 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Wed, 18 Mar 2026 07:43:21 +0100 Subject: [PATCH 6/6] add comment --- web/src/pages/CERulePage/CERulePage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/src/pages/CERulePage/CERulePage.tsx b/web/src/pages/CERulePage/CERulePage.tsx index 37ff1ee039..86ada2e903 100644 --- a/web/src/pages/CERulePage/CERulePage.tsx +++ b/web/src/pages/CERulePage/CERulePage.tsx @@ -438,6 +438,8 @@ const Content = ({ rule: initialRule }: Props) => { }); } } else if (vals.destinations.size === 0) { + // If no predefined destinations exist, show error under the "Add manual destination settings" checkbox. + // If predefined destinations exist - show it at the end of "Destination" section. ctx.addIssue({ path: [ hasPredefinedDestinations