diff --git a/frontend/src/components/audit/SqlAuditWorkbench.css b/frontend/src/components/audit/SqlAuditWorkbench.css index 4f213f28..d68aaa2f 100644 --- a/frontend/src/components/audit/SqlAuditWorkbench.css +++ b/frontend/src/components/audit/SqlAuditWorkbench.css @@ -160,7 +160,34 @@ margin: auto; } +/* Prevent intrinsic row height from consuming the pagination slot. */ .gn-sql-audit-table-panel .ant-table-wrapper { + display: flex; + height: 0; + min-height: 0; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} + +.gn-sql-audit-table-panel .ant-table-wrapper > .ant-spin-nested-loading, +.gn-sql-audit-table-panel .ant-table-wrapper > .ant-spin-nested-loading > .ant-spin-container, +.gn-sql-audit-table-panel .ant-table-wrapper .ant-table, +.gn-sql-audit-table-panel .ant-table-wrapper .ant-table-container { + height: 100%; + min-height: 0; +} + +.gn-sql-audit-table-panel .ant-table-wrapper .ant-table-container { + display: flex; + flex-direction: column; +} + +.gn-sql-audit-table-panel .ant-table-wrapper .ant-table-header { + flex: 0 0 auto; +} + +.gn-sql-audit-table-panel .ant-table-wrapper .ant-table-body { min-height: 0; flex: 1 1 auto; } diff --git a/frontend/src/components/audit/SqlAuditWorkbench.test.tsx b/frontend/src/components/audit/SqlAuditWorkbench.test.tsx index e47dee60..da89d56c 100644 --- a/frontend/src/components/audit/SqlAuditWorkbench.test.tsx +++ b/frontend/src/components/audit/SqlAuditWorkbench.test.tsx @@ -54,6 +54,35 @@ describe('SqlAuditWorkbench', () => { expect(styleSource).toMatch(/\.gn-sql-audit-table-panel\s*\{[\s\S]*?min-height:\s*280px;/); }); + it('keeps pagination outside the table scroll region when records fill the panel', () => { + const source = readFileSync(new URL('./SqlAuditWorkbench.tsx', import.meta.url), 'utf8'); + const styleSource = readFileSync(new URL('./SqlAuditWorkbench.css', import.meta.url), 'utf8'); + + expect(source).toContain("scroll={{ x: 1444, y: '100%' }}"); + expect(source).not.toContain("y: 'calc(100vh - 540px)'"); + expect(styleSource).toMatch( + /\.gn-sql-audit-table-panel \.ant-table-wrapper\s*\{[^}]*display:\s*flex;[^}]*height:\s*0;[^}]*min-height:\s*0;[^}]*flex:\s*1 1 auto;[^}]*flex-direction:\s*column;[^}]*overflow:\s*hidden;/, + ); + expect(styleSource).toContain('.gn-sql-audit-table-panel .ant-table-wrapper > .ant-spin-nested-loading,'); + expect(styleSource).toContain('.gn-sql-audit-table-panel .ant-table-wrapper > .ant-spin-nested-loading > .ant-spin-container,'); + expect(styleSource).toContain('.gn-sql-audit-table-panel .ant-table-wrapper .ant-table,'); + expect(styleSource).toMatch( + /\.gn-sql-audit-table-panel \.ant-table-wrapper \.ant-table-container\s*\{[^}]*height:\s*100%;[^}]*min-height:\s*0;/, + ); + expect(styleSource).toMatch( + /\.gn-sql-audit-table-panel \.ant-table-wrapper \.ant-table-container\s*\{[^}]*display:\s*flex;[^}]*flex-direction:\s*column;/, + ); + expect(styleSource).toMatch( + /\.gn-sql-audit-table-panel \.ant-table-wrapper \.ant-table-header\s*\{[^}]*flex:\s*0 0 auto;/, + ); + expect(styleSource).toMatch( + /\.gn-sql-audit-table-panel \.ant-table-wrapper \.ant-table-body\s*\{[^}]*min-height:\s*0;[^}]*flex:\s*1 1 auto;/, + ); + expect(styleSource).toMatch( + /\.gn-sql-audit-pagination\s*\{[^}]*flex:\s*0 0 auto;/, + ); + }); + it('keeps the fixed action column opaque while rows are hovered', () => { const styleSource = readFileSync(new URL('./SqlAuditWorkbench.css', import.meta.url), 'utf8'); diff --git a/frontend/src/components/audit/SqlAuditWorkbench.tsx b/frontend/src/components/audit/SqlAuditWorkbench.tsx index 72dac7c8..cf1bf612 100644 --- a/frontend/src/components/audit/SqlAuditWorkbench.tsx +++ b/frontend/src/components/audit/SqlAuditWorkbench.tsx @@ -655,7 +655,7 @@ export default function SqlAuditWorkbench({ tab, backend: backendOverride, isAct pagination={false} size="small" tableLayout="fixed" - scroll={{ x: 1444, y: 'calc(100vh - 540px)' }} + scroll={{ x: 1444, y: '100%' }} rowClassName="gn-sql-audit-table-row" /> ) : (