Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion public/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,6 @@
"INVALID_XML_ZIP_EXTENSION_ALERT": "<strong>Sorry!<\/strong> SEED doesn't currently support that file format. Only <strong>.xml<\/strong> and <strong>.zip<\/strong> files are supported.",
"IRREVERSIBLE_OPERATION_WARNING": "This operation is irreversible.",
"ITEMS_WILL_NOT_CHANGE": "these will not change",
"I agree with the": "I agree with the",
"If Enabled": "If Enabled",
"If you are unable to scan the QR code, select a different method below.": "If you are unable to scan the QR code, select a different method below.",
"If you wish to generate stub Audit Template reports from SEED data, select which Audit Template Report Type SEED should generate.": "If you wish to generate stub Audit Template reports from SEED data, select which Audit Template Report Type SEED should generate.",
Expand Down Expand Up @@ -1184,6 +1183,7 @@
"Options": "Options",
"Or Create New (With User as Head):": "Or Create New (With User as Head):",
"Or select a field to add to the table. Selecting a field adds it to the table above so it can be shared.": "Or select a field to add to the table. Selecting a field adds it to the table above so it can be shared.",
"Order": "Order",
"Organization": "Organization",
"Organization \"{{orgName}}\" created": "Organization \"{{orgName}}\" created",
"Organization \"{{orgName}}\" deleted": "Organization \"{{orgName}}\" deleted",
Expand Down Expand Up @@ -1256,6 +1256,7 @@
"Percentage (%)": "Percentage (%)",
"Performance Data": "Performance Data",
"Permanently delete extra_data columns and all associated data": "Permanently delete extra_data columns and all associated data",
"Pin column to the left": "Pin column to the left",
"Please enter your new password twice so we can verify you typed it in correctly.": "Please enter your new password twice so we can verify you typed it in correctly.",
"Please go to the following page and choose a new password:": "Please go to the following page and choose a new password:",
"Please go to the following page and setup your account:": "Please go to the following page and setup your account:",
Expand Down Expand Up @@ -1844,6 +1845,7 @@
"Unknown": "Unknown",
"Unmerge Last": "Unmerge Last",
"Unmerge complete.": "Unmerge complete.",
"Unpin column": "Unpin column",
"Unsatisfactory": "Unsatisfactory",
"Unsuccessful Exports": "Unsuccessful Exports",
"Until last date of": "Until last date of",
Expand Down
3 changes: 3 additions & 0 deletions public/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,7 @@
"Options": "Opciones",
"Or Create New (With User as Head):": "O Crear Nuevo (Con Usuario como Cabecera):",
"Or select a field to add to the table. Selecting a field adds it to the table above so it can be shared.": "O bien, seleccione un campo para agregarlo a la tabla. Al seleccionar un campo, este se agregará a la tabla superior para que pueda compartirse.",
"Order": "Orden",
"Organization": "Organización",
"Organization \"{{orgName}}\" created": "Organización \"{{orgName}}\" creado",
"Organization \"{{orgName}}\" deleted": "Organización \"{{orgName}}\" eliminado",
Expand Down Expand Up @@ -1255,6 +1256,7 @@
"Percentage (%)": "Porcentaje (%)",
"Performance Data": "Datos de rendimiento",
"Permanently delete extra_data columns and all associated data": "Eliminar permanentemente las columnas extra_data y todos los datos asociados",
"Pin column to the left": "Columna de alfileres a la izquierda",
"Please enter your new password twice so we can verify you typed it in correctly.": "Por favor, introduzca su nueva contraseña dos veces para que podamos verificar que la ha escrito correctamente.",
"Please go to the following page and choose a new password:": "Vaya a la página siguiente y elija una nueva contraseña:",
"Please go to the following page and setup your account:": "Vaya a la siguiente página y cree su cuenta:",
Expand Down Expand Up @@ -1843,6 +1845,7 @@
"Unknown": "Desconocido",
"Unmerge Last": "Fusión final",
"Unmerge complete.": "Descombinación completada.",
"Unpin column": "Desanclar columna",
"Unsatisfactory": "Insatisfactorio",
"Unsuccessful Exports": "Exportaciones fallidas",
"Until last date of": "Hasta la última fecha de",
Expand Down
3 changes: 3 additions & 0 deletions public/i18n/fr_CA.json
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,7 @@
"Options": "Options",
"Or Create New (With User as Head):": "Ou Créer Nouveau (avec l'utilisateur en tant que chef):",
"Or select a field to add to the table. Selecting a field adds it to the table above so it can be shared.": "Vous pouvez également sélectionner un champ à ajouter au tableau. La sélection d'un champ l'ajoute au tableau ci-dessus afin qu'il puisse être partagé.",
"Order": "Commande",
"Organization": "Organisation",
"Organization \"{{orgName}}\" created": "Organisation \"{{orgName}}\" créé",
"Organization \"{{orgName}}\" deleted": "Organisation \"{{orgName}}\" supprimé",
Expand Down Expand Up @@ -1255,6 +1256,7 @@
"Percentage (%)": "Pourcentage (%)",
"Performance Data": "Données de performance",
"Permanently delete extra_data columns and all associated data": "Supprimer définitivement les colonnes extra_data et toutes les données associées",
"Pin column to the left": "Colonne d'épingles à gauche",
"Please enter your new password twice so we can verify you typed it in correctly.": "Entrez votre nouveau mot de passe deux fois afin que nous puissions vérifier que vous l'avez tapé correctement.",
"Please go to the following page and choose a new password:": "Passez à la page suivante et choisissez un nouveau mot de passe:",
"Please go to the following page and setup your account:": "Passez à la page suivante et configurez votre compte:",
Expand Down Expand Up @@ -1843,6 +1845,7 @@
"Unknown": "Inconnue",
"Unmerge Last": "Défaire la fusion Dernière",
"Unmerge complete.": "Fusion terminée.",
"Unpin column": "Colonne décrochée",
"Unsatisfactory": "Insatisfaisant",
"Unsuccessful Exports": "Exportations infructueuses",
"Until last date of": "Jusqu'à la dernière date de",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="h-full-page-tabs flex flex-col gap-2">
<div class="m-5 flex gap-2">
<div>
<div class="m-5 flex flex-wrap items-center gap-2">
<div class="flex flex-wrap items-center gap-2">
<mat-label class="text-secondary mr-4 text-sm">Column List Profile</mat-label>
<mat-select
class="h-10 w-60 rounded border border-gray-500 p-3 text-sm"
Expand Down
161 changes: 161 additions & 0 deletions src/@seed/components/column-profiles/column-profiles.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { TestBed } from '@angular/core/testing'
import { MatDialog } from '@angular/material/dialog'
import { TranslocoService } from '@jsverse/transloco'
import type { GridApi, IRowNode, RowSelectedEvent } from 'ag-grid-community'
import { of } from 'rxjs'
import type { Column } from '@seed/api'
import { ColumnService, InventoryService, OrganizationService, UserService } from '@seed/api'
import { ConfigService } from '@seed/services'
import type { ProfileColumn } from 'app/modules/inventory/inventory.types'
import { ColumnProfilesComponent } from './column-profiles.component'

describe('ColumnProfilesComponent profile settings', () => {
let component: ColumnProfilesComponent

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: ColumnService, useValue: {} },
{ provide: InventoryService, useValue: {} },
{ provide: OrganizationService, useValue: {} },
{ provide: UserService, useValue: {} },
{ provide: MatDialog, useValue: {} },
{ provide: ConfigService, useValue: { gridTheme$: of(null) } },
{ provide: TranslocoService, useValue: { translate: (key: string) => key } },
],
})
component = TestBed.runInInjectionContext(() => new ColumnProfilesComponent())
component.profileType = 'list'
component.columns = [
{ id: 1, column_name: 'alpha', display_name: 'Alpha' },
{ id: 2, column_name: 'beta', display_name: 'Beta' },
{ id: 3, column_name: 'gamma', display_name: 'Gamma' },
] as Column[]
})

afterEach(() => {
component.ngOnDestroy()
})

it('loads saved order and puts pinned columns first', () => {
component.setRowData(new Set([1, 2, 3]), [
{ id: 3, order: 1, pinned: false },
{ id: 2, order: 2, pinned: true },
{ id: 1, order: 3, pinned: false },
])

expect(component.getSelectedProfileColumns().map((row) => [row.id, row.order, row.pinned])).toEqual([
[2, 1, true],
[3, 2, false],
[1, 3, false],
])
})

it('preserves order and pins when adding or removing a column', () => {
component.setRowData(new Set([1, 3]), [
{ id: 3, order: 1, pinned: true },
{ id: 1, order: 2, pinned: false },
])
component.setRowData(new Set([1, 2, 3]))
expect(component.getSelectedProfileColumns().map((row) => row.id)).toEqual([3, 1, 2])
expect(component.rowData[0].pinned).toBeTrue()

component.setRowData(new Set([1, 2]))
component.setRowData(new Set([1, 2, 3]))
expect(component.getSelectedProfileColumns().map((row) => row.id)).toEqual([1, 2, 3])
expect(component.rowData.find((row) => row.id === 3).pinned).toBeFalse()
})

it('saves drag order rather than stale order values', () => {
component.setRowData(new Set([1, 2, 3]))
const [first, second, third] = component.rowData
component.gridApi = {
forEachNodeAfterFilterAndSort: (callback) => {
for (const [index, data] of [third, first, second].entries()) callback({ data } as IRowNode, index)
},
getSelectedRows: () => [first, second, third],
} as GridApi
spyOn(component, 'setSelectedRows')

component.onRowDragEnd()

expect(component.getSelectedProfileColumns().map((row) => [row.id, row.order])).toEqual([[3, 1], [1, 2], [2, 3]])
})

it('supports numeric keyboard ordering within the selected columns', () => {
component.setRowData(new Set([1, 2, 3]))
component.setColumnOrder(component.rowData[2], 1)
expect(component.getSelectedProfileColumns().map((row) => row.id)).toEqual([3, 1, 2])
})

it('allows derived columns to be pinned and selects them automatically', () => {
component.setRowData(new Set())
const row = component.rowData[0]
row.derived_column = 1
const setSelected = jasmine.createSpy('setSelected')
component.gridApi = {
getSelectedRows: () => [],
} as unknown as GridApi
spyOn(component, 'setRowData')

component.togglePinned(row, setSelected)

expect(setSelected).toHaveBeenCalledOnceWith(true)
expect(row.pinned).toBeTrue()
expect(component.getSelectedProfileColumns().map((column) => column.id)).toContain(row.id)
expect(component.setRowData).toHaveBeenCalledWith(new Set([row.id]), component.rowData)
})

it('pins the focused pin cell with Enter or Space and suppresses grid shortcuts', () => {
component.setRowData(new Set([1]))
component.gridApi = {
getSelectedRows: () => [],
} as unknown as GridApi
spyOn(component, 'setRowData')

for (const key of ['Enter', ' ']) {
const row = { ...component.rowData[0] }
const event = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key })
const setSelected = jasmine.createSpy('setSelected')
spyOn(event, 'stopPropagation')

const suppressed = component.onPinCellKeyDown(event, row, setSelected)

expect(suppressed).toBeTrue()
expect(event.defaultPrevented).toBeTrue()
expect(event.stopPropagation).toHaveBeenCalled()
expect(setSelected).toHaveBeenCalledOnceWith(true)
expect(row.pinned).toBeTrue()
}
})

it('does not suppress other pin-cell keyboard events', () => {
const event = new KeyboardEvent('keydown', { key: 'ArrowDown' })
const setSelected = jasmine.createSpy('setSelected')
spyOn(component, 'togglePinned')

const suppressed = component.onPinCellKeyDown(event, {} as ProfileColumn, setSelected)

expect(suppressed).toBeFalse()
expect(event.defaultPrevented).toBeFalse()
expect(setSelected).not.toHaveBeenCalled()
expect(component.togglePinned).not.toHaveBeenCalled()
})

it('captures deselection and clears pins before the delayed refresh', () => {
component.setRowData(new Set([1]), [{ id: 1, order: 1, pinned: true }])
const row = component.rowData[0]
component.onRowSelected({ data: row, source: 'checkboxSelected', node: { isSelected: () => false } } as RowSelectedEvent)
expect(component.getSelectedProfileColumns()).toEqual([])
expect(row.pinned).toBeFalse()
})

it('retains detail profile order without enabling list-only pins', () => {
component.profileType = 'detail'
component.setRowData(new Set([1, 2]), [
{ id: 2, order: 1, pinned: true },
{ id: 1, order: 2, pinned: false },
])
expect(component.getSelectedProfileColumns().map((row) => [row.id, row.pinned])).toEqual([[2, false], [1, false]])
})
})
Loading
Loading