Skip to content

feat(dpi): refactor DPI UI - #815

Draft
m-dilorenzi wants to merge 4 commits into
mainfrom
refactor_dpi
Draft

m-dilorenzi wants to merge 4 commits into
mainfrom
refactor_dpi

Conversation

@m-dilorenzi

Copy link
Copy Markdown
Collaborator

This PR contains a rework of the DPI Filter UI, replacing the old card-based rule editor with a table-driven interface and introducing application groups as a first-class concept.

Main changes

  • DPI rules: rules are now shown in a sortable table with drag & drop reordering, inline enable/disable, and dedicated create/edit and rename drawers replacing the previous multi-purpose modal.
  • Application groups: new tab (replacing Exceptions) to create, edit and delete reusable groups of applications, protocols and their categories, with a guided multi-step creation flow, search and pagination.
  • Data layer: DPI logic moved out of components into dedicated composables (useDpiRules, useApplicationGroups, useDpiCatalog) built on TanStack Query, with typed payloads, shared query keys and centralized cache invalidation. The catalog composable merges the netifyd catalog with the loaded applications/protocols and exposes categories with icons and availability info.
  • Subscription awareness: loaded application/protocol queries are invalidated when the subscription status changes, so the catalog reflects what is actually available.
  • Shared components: NeMultiTextInput gains a helperText prop and improved spacing; NeStepper gains configurable bar size and color classes.
  • Tests: added unit tests for the three new composables.
  • i18n: new English and Italian strings for rules and application groups.

@m-dilorenzi m-dilorenzi self-assigned this Sep 8, 2026

@Tbaile Tbaile left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notes I've left in the useApplicationGroups are valid for all the new composables, also there's no point to test looping functions, tests only things that eventually will break if data underneath changes or edge cases.
Validation should stick to the backend unless needed, the only validation I could get behind is the step-by-step one, and I'm starting to think that is better to hit a backend API for validation only.

Comment on lines +32 to +39
const active = res.data.active ?? false

if (active !== isActive.value) {
queryClient.invalidateQueries({ queryKey: DPI_LOADED_APPLICATIONS_KEY })
queryClient.invalidateQueries({ queryKey: DPI_LOADED_PROTOCOLS_KEY })
}

isActive.value = active

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just invalidate the queries, it's data saved in the machine, not a big issue

totalSteps: number
currentStep: number
stepLabel: string
barSize?: 'sm' | 'md' | 'lg' | 'xl'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep just what we use

Suggested change
barSize?: 'sm' | 'md' | 'lg' | 'xl'
barSize?: 'sm' | 'md'

totalSteps: number
currentStep: number
stepLabel: string
barSize?: 'sm' | 'md' | 'lg' | 'xl'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why generating more than we need?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated fix, let's not change what we don't need

Comment on lines +40 to +70
export function useApplicationGroups() {
return useQuery({
queryKey: [...APPLICATION_GROUPS_KEY, 'all'],
queryFn: ({ signal }) =>
ubusCall<ListAppGroupsResponse>('ns.dpi', 'list-appgroups', {}, { signal }),
select: (res) => res.data.values.data
})
}

export function useApplicationGroupsPage(params: {
search: Ref<string>
page: Ref<number>
pageSize: Ref<number>
}) {
return useQuery({
queryKey: [...APPLICATION_GROUPS_KEY, 'page', params.search, params.page, params.pageSize],
queryFn: ({ signal }) =>
ubusCall<ListAppGroupsResponse>(
'ns.dpi',
'list-appgroups',
{
search: params.search.value || undefined,
limit: params.pageSize.value,
page: params.page.value
},
{ signal }
),
select: (res) => res.data.values,
placeholderData: keepPreviousData
})
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not liking this separation, should be one single call with optional parameters

const loading = ref({
deleteRule: false
})
const deleteError = ref<Error>()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be extracted by error inside the mutation

Comment on lines +77 to +85
const nameSchema = v.object({
name: v.pipe(
v.string(),
v.trim(),
v.minLength(1, 'required'),
v.maxLength(NAME_MAX_LENGTH, 'name_too_long')
)
})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this into backend

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach might not be the best. While all code seem fine we are having a single component behave completely differently by it's state, probably extracting a presentation component and then two components that apply logic (create/edit) is the best approach here


const { t } = useI18n()

const deleteError = ref<Error>()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error can be extracted by the mutation, if you need different behaviours you can just apply a watch function

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might have the same "issue" of the CreateApplicationModal, single component for multiple usages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants