From 8d44925eca97beeab3b70de1a837d623979190f7 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Thu, 11 Sep 2025 10:32:38 +0200 Subject: [PATCH] use paginated table for change requests --- .../ChangeRequests/ChangeRequests.tsx | 370 +++++---------- .../useChangeRequests/mockChangeRequests.ts | 448 ++++++++++++++++++ .../useChangeRequests/useChangeRequests.ts | 122 +++++ 3 files changed, 687 insertions(+), 253 deletions(-) create mode 100644 frontend/src/hooks/api/getters/useChangeRequests/mockChangeRequests.ts create mode 100644 frontend/src/hooks/api/getters/useChangeRequests/useChangeRequests.ts diff --git a/frontend/src/component/changeRequest/ChangeRequests/ChangeRequests.tsx b/frontend/src/component/changeRequest/ChangeRequests/ChangeRequests.tsx index b8953e025b..822c1683d5 100644 --- a/frontend/src/component/changeRequest/ChangeRequests/ChangeRequests.tsx +++ b/frontend/src/component/changeRequest/ChangeRequests/ChangeRequests.tsx @@ -1,285 +1,149 @@ import { useMemo } from 'react'; import { PageContent } from 'component/common/PageContent/PageContent'; import { PageHeader } from 'component/common/PageHeader/PageHeader'; -import { - SortableTableHeader, - Table, - TableBody, - TableCell, - TableRow, -} from 'component/common/Table'; -import { useSortBy, useTable } from 'react-table'; -import { sortTypes } from 'utils/sortTypes'; +import { PaginatedTable } from 'component/common/Table'; +import { createColumnHelper, useReactTable } from '@tanstack/react-table'; import { TimeAgoCell } from 'component/common/Table/cells/TimeAgoCell/TimeAgoCell'; -import { TextCell } from 'component/common/Table/cells/TextCell/TextCell'; import { ChangeRequestStatusCell } from 'component/changeRequest/ProjectChangeRequests/ChangeRequestsTabs/ChangeRequestStatusCell'; import { AvatarCell } from 'component/changeRequest/ProjectChangeRequests/ChangeRequestsTabs/AvatarCell'; import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell'; import { GlobalChangeRequestTitleCell } from './GlobalChangeRequestTitleCell.js'; import { FeaturesCell } from '../ProjectChangeRequests/ChangeRequestsTabs/FeaturesCell.js'; import { useUiFlag } from 'hooks/useUiFlag.js'; +import { withTableState } from 'utils/withTableState'; +import { + useChangeRequestsWithMockData as useChangeRequests, + type ChangeRequestItem +} from 'hooks/api/getters/useChangeRequests/useChangeRequests'; +import { + encodeQueryParams, + NumberParam, + StringParam, + withDefault, + useQueryParams, +} from 'use-query-params'; +import mapValues from 'lodash.mapvalues'; +import useLoading from 'hooks/useLoading'; +import { styles as themeStyles } from 'component/common'; -// Mock data with varied projects and change requests -const mockChangeRequests = [ - { - id: 101, - title: 'Activate harpoons', - project: 'payment-service', - projectName: 'Payment Service', - features: [{ name: 'securePaymentFlow' }], - segments: [], - createdBy: { username: 'alice', name: 'Alice Johnson', imageUrl: null }, - createdAt: '2024-01-10T10:22:00Z', - environment: 'Production', - state: 'Review required', - }, - { - id: 102, - title: 'change request #102', - project: 'user-management', - projectName: 'User Management', - features: [{ name: 'enhancedValidation' }], - segments: [], - createdBy: { username: 'bob', name: 'Bob Smith', imageUrl: null }, - createdAt: '2024-01-10T08:15:00Z', - environment: 'Production', - state: 'Approved', - }, - { - id: 103, - title: 'Enable new checkout flow', - project: 'e-commerce-platform', - projectName: 'E-commerce Platform', - features: [{ name: 'newCheckoutUX' }, { name: 'paymentOptionsV2' }], - segments: [], - createdBy: { username: 'carol', name: 'Carol Davis', imageUrl: null }, - createdAt: '2024-01-10T12:30:00Z', - environment: 'Testing', - state: 'Review required', - }, - { - id: 104, - title: 'Update user permissions', - project: 'user-management', - projectName: 'User Management', - features: [ - { name: 'roleBasedAccess' }, - { name: 'permissionMatrix' }, - { name: 'adminDashboard' }, - ], - segments: [], - createdBy: { username: 'david', name: 'David Wilson', imageUrl: null }, - createdAt: '2024-01-09T16:45:00Z', - environment: 'Sandbox', - state: 'Review required', - }, - { - id: 105, - title: 'Deploy feature rollback', - project: 'analytics-platform', - projectName: 'Analytics Platform', - features: [ - { name: 'performanceTracking' }, - { name: 'realTimeAnalytics' }, - { name: 'customDashboards' }, - { name: 'dataExport' }, - ], - segments: [], - createdBy: { username: 'eve', name: 'Eve Brown', imageUrl: null }, - createdAt: '2024-01-09T14:20:00Z', - environment: 'Sandbox', - state: 'Scheduled', - schedule: { - scheduledAt: '2024-01-12T09:46:51+05:30', - status: 'pending', - }, - }, - { - id: 106, - title: 'change request #106', - project: 'notification-service', - projectName: 'Notification Service', - features: [{ name: 'emailTemplates' }], - segments: [], - createdBy: { username: 'frank', name: 'Frank Miller', imageUrl: null }, - createdAt: '2024-01-08T11:00:00Z', - environment: 'Testing', - state: 'Approved', - }, - { - id: 107, - title: 'Optimize database queries', - project: 'data-warehouse', - projectName: 'Data Warehouse', - features: [{ name: 'queryOptimization' }], - segments: [], - createdBy: { username: 'grace', name: 'Grace Lee', imageUrl: null }, - createdAt: '2024-01-08T09:30:00Z', - environment: 'Testing', - state: 'Approved', - }, - { - id: 108, - title: 'change request #108', - project: 'mobile-app', - projectName: 'Mobile App', - features: [{ name: 'pushNotifications' }], - segments: [], - createdBy: { username: 'henry', name: 'Henry Chen', imageUrl: null }, - createdAt: '2024-01-07T15:20:00Z', - environment: 'Production', - state: 'Approved', - }, - { - id: 109, - title: 'Archive legacy features', - project: 'payment-service', - projectName: 'Payment Service', - features: [{ name: 'legacyPaymentGateway' }], - segments: [], - createdBy: { username: 'alice', name: 'Alice Johnson', imageUrl: null }, - createdAt: '2024-01-07T13:10:00Z', - environment: 'Production', - state: 'Scheduled', - schedule: { - scheduledAt: '2024-01-12T09:46:51+05:30', - status: 'failed', - reason: 'Mr Freeze', - }, - }, -]; +const DEFAULT_PAGE_LIMIT = 25; +const columnHelper = createColumnHelper(); const ChangeRequestsInner = () => { - const loading = false; + const stateConfig = { + offset: withDefault(NumberParam, 0), + limit: withDefault(NumberParam, DEFAULT_PAGE_LIMIT), + sortBy: withDefault(StringParam, 'createdAt'), + sortOrder: withDefault(StringParam, 'desc'), + }; + + const [tableState, setTableState] = useQueryParams( + stateConfig, + { updateType: 'replaceIn' }, + ); + + const { + changeRequests: data, + total, + loading, + initialLoad, + } = useChangeRequests( + mapValues(encodeQueryParams(stateConfig, tableState), (value) => + value ? `${value}` : undefined, + ), + ); + const columns = useMemo( () => [ - { + columnHelper.accessor('title', { id: 'Title', - Header: 'Title', - // todo (globalChangeRequestList): sort out width calculation. It's configured both here with a min width down in the inner cell? - width: 300, - canSort: true, - accessor: 'title', - Cell: GlobalChangeRequestTitleCell, - }, - { + header: 'Title', + meta: { width: '300px' }, + cell: ({ getValue, row }) => ( + + ), + }), + columnHelper.accessor('features', { id: 'Updated feature flags', - Header: 'Updated feature flags', - canSort: false, - accessor: 'features', - searchable: true, - filterName: 'feature', - filterParsing: (values: Array<{ name: string }>) => { - return values?.map(({ name }) => name).join('\n') || ''; - }, - filterBy: ( - row: { features: Array<{ name: string }> }, - values: Array, - ) => { - return row.features.find((feature) => - values - .map((value) => value.toLowerCase()) - .includes(feature.name.toLowerCase()), - ); - }, - Cell: ({ - value, + header: 'Updated feature flags', + enableSorting: false, + cell: ({ + getValue, row: { original: { title, project }, }, - }: any) => ( - + }) => { + const features = getValue(); + // Convert string array to object array for FeaturesCell compatibility + const featureObjects = features.map((name: string) => ({ name })); + return ( + + ); + }, + }), + columnHelper.accessor('createdBy', { + id: 'By', + header: 'By', + meta: { width: '180px', align: 'left' }, + enableSorting: false, + cell: ({ getValue }) => ( + ), - }, - { - Header: 'By', - accessor: 'createdBy', - maxWidth: 180, - canSort: false, - Cell: AvatarCell, - align: 'left', - searchable: true, - filterName: 'by', - filterParsing: (value: { username?: string }) => - value?.username || '', - }, - { - Header: 'Submitted', - accessor: 'createdAt', - maxWidth: 100, - Cell: TimeAgoCell, - }, - { - Header: 'Environment', - accessor: 'environment', - searchable: true, - maxWidth: 100, - Cell: HighlightCell, - filterName: 'environment', - }, - { - Header: 'Status', - accessor: 'state', - searchable: true, - maxWidth: '170px', - Cell: ChangeRequestStatusCell, - filterName: 'status', - }, + }), + columnHelper.accessor('createdAt', { + id: 'Submitted', + header: 'Submitted', + meta: { width: '100px' }, + cell: ({ getValue }) => ( + + ), + }), + columnHelper.accessor('environment', { + id: 'Environment', + header: 'Environment', + meta: { width: '100px' }, + cell: ({ getValue }) => ( + + ), + }), + columnHelper.accessor('state', { + id: 'Status', + header: 'Status', + meta: { width: '170px' }, + cell: ({ getValue, row }) => ( + + ), + }), ], [], ); - const { headerGroups, rows, prepareRow, getTableProps, getTableBodyProps } = - useTable( - { - columns: columns as any[], - data: mockChangeRequests, - initialState: { - sortBy: [ - { - id: 'createdAt', - desc: true, - }, - ], - }, - sortTypes, - autoResetHiddenColumns: false, - disableSortRemove: true, - autoResetSortBy: false, - defaultColumn: { - Cell: TextCell, - }, - }, - useSortBy, - ); + const table = useReactTable( + withTableState(tableState, setTableState, { + columns, + data, + }), + ); + + const bodyLoadingRef = useLoading(loading); return ( } > - - - - {rows.map((row) => { - prepareRow(row); - const { key, ...rowProps } = row.getRowProps(); - return ( - - {row.cells.map((cell) => { - const { key, ...cellProps } = - cell.getCellProps(); - return ( - - {cell.render('Cell')} - - ); - })} - - ); - })} - -
+
+
+ +
+
); }; @@ -294,4 +158,4 @@ export const ChangeRequests = () => { } return ; -}; +}; \ No newline at end of file diff --git a/frontend/src/hooks/api/getters/useChangeRequests/mockChangeRequests.ts b/frontend/src/hooks/api/getters/useChangeRequests/mockChangeRequests.ts new file mode 100644 index 0000000000..20303602ba --- /dev/null +++ b/frontend/src/hooks/api/getters/useChangeRequests/mockChangeRequests.ts @@ -0,0 +1,448 @@ +import type { ChangeRequestItem } from './useChangeRequests'; + +// Mock data with varied projects and change requests (expanded to 35 items for pagination testing) +export const mockChangeRequests: ChangeRequestItem[] = [ + { + id: 101, + title: 'Activate harpoons', + project: 'payment-service', + projectName: 'Payment Service', + features: ['securePaymentFlow'], + segments: [], + createdBy: { id: 1, username: 'alice', imageUrl: null }, + createdAt: '2024-01-10T10:22:00Z', + environment: 'Production', + state: 'In review', + }, + { + id: 102, + title: 'change request #102', + project: 'user-management', + projectName: 'User Management', + features: ['enhancedValidation'], + segments: [], + createdBy: { id: 2, username: 'bob', imageUrl: null }, + createdAt: '2024-01-10T08:15:00Z', + environment: 'Production', + state: 'Approved', + }, + { + id: 103, + title: 'Enable new checkout flow', + project: 'e-commerce-platform', + projectName: 'E-commerce Platform', + features: ['newCheckoutUX', 'paymentOptionsV2'], + segments: [], + createdBy: { id: 3, username: 'carol', imageUrl: null }, + createdAt: '2024-01-10T12:30:00Z', + environment: 'Testing', + state: 'In review', + }, + { + id: 104, + title: 'Update user permissions', + project: 'user-management', + projectName: 'User Management', + features: ['roleBasedAccess', 'permissionMatrix', 'adminDashboard'], + segments: [], + createdBy: { id: 4, username: 'david', imageUrl: null }, + createdAt: '2024-01-09T16:45:00Z', + environment: 'Sandbox', + state: 'In review', + }, + { + id: 105, + title: 'Deploy feature rollback', + project: 'analytics-platform', + projectName: 'Analytics Platform', + features: ['performanceTracking', 'realTimeAnalytics', 'customDashboards', 'dataExport'], + segments: [], + createdBy: { id: 5, username: 'eve', imageUrl: null }, + createdAt: '2024-01-09T14:20:00Z', + environment: 'Sandbox', + state: 'Scheduled', + schedule: { + scheduledAt: '2024-01-12T09:46:51+05:30', + status: 'Pending', + }, + }, + { + id: 106, + title: 'change request #106', + project: 'notification-service', + projectName: 'Notification Service', + features: ['emailTemplates'], + segments: [], + createdBy: { id: 6, username: 'frank', imageUrl: null }, + createdAt: '2024-01-08T11:00:00Z', + environment: 'Testing', + state: 'Approved', + }, + { + id: 107, + title: 'Optimize database queries', + project: 'data-warehouse', + projectName: 'Data Warehouse', + features: ['queryOptimization'], + segments: [], + createdBy: { id: 7, username: 'grace', imageUrl: null }, + createdAt: '2024-01-08T09:30:00Z', + environment: 'Testing', + state: 'Approved', + }, + { + id: 108, + title: 'change request #108', + project: 'mobile-app', + projectName: 'Mobile App', + features: ['pushNotifications'], + segments: [], + createdBy: { id: 8, username: 'henry', imageUrl: null }, + createdAt: '2024-01-07T15:20:00Z', + environment: 'Production', + state: 'Approved', + }, + { + id: 109, + title: 'Archive legacy features', + project: 'payment-service', + projectName: 'Payment Service', + features: ['legacyPaymentGateway'], + segments: [], + createdBy: { id: 1, username: 'alice', imageUrl: null }, + createdAt: '2024-01-07T13:10:00Z', + environment: 'Production', + state: 'Scheduled', + schedule: { + scheduledAt: '2024-01-12T09:46:51+05:30', + status: 'Failed', + reason: 'Mr Freeze', + }, + }, + // Additional 26 items to reach 35 total (ensuring >25 for pagination) + { + id: 110, + title: 'Enable dark mode', + project: 'design-system', + projectName: 'Design System', + features: ['darkTheme', 'themeToggle'], + segments: [], + createdBy: { id: 9, username: 'isabella', imageUrl: null }, + createdAt: '2024-01-06T14:30:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 111, + title: 'API rate limiting', + project: 'api-gateway', + projectName: 'API Gateway', + features: ['rateLimiting', 'throttling'], + segments: ['premium-users'], + createdBy: { id: 10, username: 'jack', imageUrl: null }, + createdAt: '2024-01-06T10:15:00Z', + environment: 'Production', + state: 'Approved', + }, + { + id: 112, + title: 'Social media login', + project: 'auth-service', + projectName: 'Authentication Service', + features: ['googleLogin', 'facebookLogin', 'twitterLogin'], + segments: [], + createdBy: { id: 11, username: 'karen', imageUrl: null }, + createdAt: '2024-01-05T16:45:00Z', + environment: 'Testing', + state: 'In review', + }, + { + id: 113, + title: 'Real-time notifications', + project: 'notification-service', + projectName: 'Notification Service', + features: ['websocketNotifications', 'notificationCenter'], + segments: [], + createdBy: { id: 12, username: 'liam', imageUrl: null }, + createdAt: '2024-01-05T12:00:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 114, + title: 'Multi-currency support', + project: 'payment-service', + projectName: 'Payment Service', + features: ['currencyConversion', 'multiCurrency'], + segments: ['international-users'], + createdBy: { id: 2, username: 'bob', imageUrl: null }, + createdAt: '2024-01-04T09:30:00Z', + environment: 'Sandbox', + state: 'Rejected', + }, + { + id: 115, + title: 'Advanced search filters', + project: 'e-commerce-platform', + projectName: 'E-commerce Platform', + features: ['advancedSearch', 'filterOptions', 'searchSuggestions'], + segments: [], + createdBy: { id: 13, username: 'mia', imageUrl: null }, + createdAt: '2024-01-03T14:15:00Z', + environment: 'Testing', + state: 'Applied', + }, + { + id: 116, + title: 'Machine learning recommendations', + project: 'recommendation-engine', + projectName: 'Recommendation Engine', + features: ['mlRecommendations', 'userBehaviorTracking'], + segments: ['active-users'], + createdBy: { id: 14, username: 'noah', imageUrl: null }, + createdAt: '2024-01-02T11:20:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 117, + title: 'Video streaming optimization', + project: 'media-service', + projectName: 'Media Service', + features: ['videoOptimization', 'adaptiveBitrate'], + segments: [], + createdBy: { id: 15, username: 'olivia', imageUrl: null }, + createdAt: '2024-01-01T08:45:00Z', + environment: 'Production', + state: 'Scheduled', + schedule: { + scheduledAt: '2024-01-15T10:00:00+05:30', + status: 'Pending', + }, + }, + { + id: 118, + title: 'Inventory management system', + project: 'inventory-service', + projectName: 'Inventory Service', + features: ['stockTracking', 'lowStockAlerts', 'automaticReordering'], + segments: [], + createdBy: { id: 16, username: 'peter', imageUrl: null }, + createdAt: '2023-12-31T15:30:00Z', + environment: 'Testing', + state: 'In review', + }, + { + id: 119, + title: 'Customer support chatbot', + project: 'customer-service', + projectName: 'Customer Service', + features: ['aiChatbot', 'ticketRouting'], + segments: ['support-tier-1'], + createdBy: { id: 17, username: 'quinn', imageUrl: null }, + createdAt: '2023-12-30T13:15:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 120, + title: 'Geolocation services', + project: 'location-service', + projectName: 'Location Service', + features: ['geoLocation', 'addressAutocomplete'], + segments: ['mobile-users'], + createdBy: { id: 18, username: 'rachel', imageUrl: null }, + createdAt: '2023-12-29T10:00:00Z', + environment: 'Sandbox', + state: 'Cancelled', + }, + { + id: 121, + title: 'Blockchain integration', + project: 'crypto-service', + projectName: 'Crypto Service', + features: ['blockchainIntegration', 'cryptoWallet'], + segments: ['crypto-users'], + createdBy: { id: 19, username: 'sam', imageUrl: null }, + createdAt: '2023-12-28T16:20:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 122, + title: 'Voice recognition', + project: 'ai-service', + projectName: 'AI Service', + features: ['voiceRecognition', 'speechToText'], + segments: [], + createdBy: { id: 20, username: 'taylor', imageUrl: null }, + createdAt: '2023-12-27T12:45:00Z', + environment: 'Testing', + state: 'Approved', + }, + { + id: 123, + title: 'Performance monitoring', + project: 'monitoring-service', + projectName: 'Monitoring Service', + features: ['performanceMetrics', 'alerting', 'dashboards'], + segments: [], + createdBy: { id: 21, username: 'uma', imageUrl: null }, + createdAt: '2023-12-26T09:10:00Z', + environment: 'Production', + state: 'Applied', + }, + { + id: 124, + title: 'Content moderation', + project: 'content-service', + projectName: 'Content Service', + features: ['autoModeration', 'contentFiltering'], + segments: ['user-generated-content'], + createdBy: { id: 22, username: 'victor', imageUrl: null }, + createdAt: '2023-12-25T14:30:00Z', + environment: 'Testing', + state: 'In review', + }, + { + id: 125, + title: 'Email marketing automation', + project: 'marketing-service', + projectName: 'Marketing Service', + features: ['emailCampaigns', 'marketingAutomation'], + segments: ['marketing-subscribers'], + createdBy: { id: 23, username: 'wendy', imageUrl: null }, + createdAt: '2023-12-24T11:20:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 126, + title: 'Data backup and recovery', + project: 'backup-service', + projectName: 'Backup Service', + features: ['automaticBackup', 'dataRecovery'], + segments: [], + createdBy: { id: 24, username: 'xavier', imageUrl: null }, + createdAt: '2023-12-23T08:15:00Z', + environment: 'Production', + state: 'Scheduled', + schedule: { + scheduledAt: '2024-01-20T02:00:00+05:30', + status: 'Pending', + }, + }, + { + id: 127, + title: 'Load balancing optimization', + project: 'infrastructure', + projectName: 'Infrastructure', + features: ['loadBalancer', 'trafficDistribution'], + segments: [], + createdBy: { id: 25, username: 'yara', imageUrl: null }, + createdAt: '2023-12-22T15:45:00Z', + environment: 'Production', + state: 'Approved', + }, + { + id: 128, + title: 'Calendar integration', + project: 'calendar-service', + projectName: 'Calendar Service', + features: ['calendarSync', 'eventReminders'], + segments: [], + createdBy: { id: 26, username: 'zoe', imageUrl: null }, + createdAt: '2023-12-21T13:30:00Z', + environment: 'Testing', + state: 'In review', + }, + { + id: 129, + title: 'Document collaboration', + project: 'document-service', + projectName: 'Document Service', + features: ['realTimeEditing', 'documentSharing'], + segments: ['business-users'], + createdBy: { id: 3, username: 'carol', imageUrl: null }, + createdAt: '2023-12-20T10:15:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 130, + title: 'Mobile app security', + project: 'mobile-app', + projectName: 'Mobile App', + features: ['biometricAuth', 'appSecurityScanning'], + segments: ['mobile-users'], + createdBy: { id: 27, username: 'adam', imageUrl: null }, + createdAt: '2023-12-19T16:00:00Z', + environment: 'Testing', + state: 'Approved', + }, + { + id: 131, + title: 'Analytics dashboard v2', + project: 'analytics-platform', + projectName: 'Analytics Platform', + features: ['advancedDashboard', 'customCharts', 'dataVisualization'], + segments: ['analytics-users'], + createdBy: { id: 5, username: 'eve', imageUrl: null }, + createdAt: '2023-12-18T12:20:00Z', + environment: 'Development', + state: 'In review', + }, + { + id: 132, + title: 'Microservices migration', + project: 'architecture', + projectName: 'Architecture', + features: ['microservicesArchitecture', 'serviceDecomposition'], + segments: [], + createdBy: { id: 28, username: 'blake', imageUrl: null }, + createdAt: '2023-12-17T09:45:00Z', + environment: 'Development', + state: 'Draft', + }, + { + id: 133, + title: 'API versioning strategy', + project: 'api-gateway', + projectName: 'API Gateway', + features: ['apiVersioning', 'backwardCompatibility'], + segments: ['api-consumers'], + createdBy: { id: 10, username: 'jack', imageUrl: null }, + createdAt: '2023-12-16T14:10:00Z', + environment: 'Testing', + state: 'Applied', + }, + { + id: 134, + title: 'User onboarding flow', + project: 'user-management', + projectName: 'User Management', + features: ['onboardingWizard', 'userTutorials'], + segments: ['new-users'], + createdBy: { id: 29, username: 'claire', imageUrl: null }, + createdAt: '2023-12-15T11:35:00Z', + environment: 'Production', + state: 'Scheduled', + schedule: { + scheduledAt: '2024-01-25T09:00:00+05:30', + status: 'Suspended', + reason: 'Resource constraints', + }, + }, + { + id: 135, + title: 'Feature flag management', + project: 'feature-management', + projectName: 'Feature Management', + features: ['featureFlags', 'gradualRollout'], + segments: ['beta-testers'], + createdBy: { id: 30, username: 'derek', imageUrl: null }, + createdAt: '2023-12-14T08:25:00Z', + environment: 'Production', + state: 'Approved', + }, +]; \ No newline at end of file diff --git a/frontend/src/hooks/api/getters/useChangeRequests/useChangeRequests.ts b/frontend/src/hooks/api/getters/useChangeRequests/useChangeRequests.ts new file mode 100644 index 0000000000..3e4daa9e50 --- /dev/null +++ b/frontend/src/hooks/api/getters/useChangeRequests/useChangeRequests.ts @@ -0,0 +1,122 @@ +import { useMemo } from 'react'; +import { createPaginatedHook } from '../usePaginatedData/usePaginatedData.js'; +import { mockChangeRequests } from './mockChangeRequests.js'; + +// Type for change request data based on schema +export interface ChangeRequestItem { + id: number; + title: string; + environment: string; + project: string; + projectName?: string; // Not in schema but used by GlobalChangeRequestTitleCell + createdBy: { + id: number; + username?: string | null; + imageUrl?: string | null; + }; + createdAt: string; + features: string[]; + segments: string[]; + state: 'Draft' | 'Approved' | 'In review' | 'Applied' | 'Scheduled' | 'Rejected' | 'Cancelled'; + schedule?: { + scheduledAt: string; + status: 'Pending' | 'Failed' | 'Suspended'; + reason?: string; + }; +} + +export interface ChangeRequestsResponse { + changeRequests: ChangeRequestItem[]; + total: number; +} + + +// Sort function that mimics server-side sorting +const sortData = (data: ChangeRequestItem[], sortBy: string, sortOrder: string) => { + return [...data].sort((a, b) => { + let aValue: any; + let bValue: any; + + switch (sortBy) { + case 'title': + aValue = a.title.toLowerCase(); + bValue = b.title.toLowerCase(); + break; + case 'createdAt': + aValue = new Date(a.createdAt).getTime(); + bValue = new Date(b.createdAt).getTime(); + break; + case 'environment': + aValue = a.environment.toLowerCase(); + bValue = b.environment.toLowerCase(); + break; + case 'state': + aValue = a.state.toLowerCase(); + bValue = b.state.toLowerCase(); + break; + case 'createdBy': + aValue = a.createdBy.username?.toLowerCase() || ''; + bValue = b.createdBy.username?.toLowerCase() || ''; + break; + default: + return 0; + } + + if (aValue < bValue) { + return sortOrder === 'asc' ? -1 : 1; + } + if (aValue > bValue) { + return sortOrder === 'asc' ? 1 : -1; + } + return 0; + }); +}; + +// Pagination function +const paginateData = (data: ChangeRequestItem[], offset: number, limit: number) => { + return data.slice(offset, offset + limit); +}; + +// Create the hook using the established pattern but with custom mock logic +export const useChangeRequests = createPaginatedHook( + { changeRequests: [], total: 0 }, + '', // No API endpoint - we'll override the fetcher +); + +// Override the created hook to add custom mock data logic +const originalUseChangeRequests = useChangeRequests; +export const useChangeRequestsWithMockData = ( + params: Record = {}, + dynamicPrefixKey: string = '', + options: any = {}, +) => { + // Extract parameters with defaults + const offset = Number(params?.offset) || 0; + const limit = Number(params?.limit) || 25; + const sortBy = params?.sortBy || 'createdAt'; + const sortOrder = params?.sortOrder || 'desc'; + + const mockData = useMemo(() => { + // Apply sorting (simulating server-side sorting) + const sortedData = sortData(mockChangeRequests, sortBy, sortOrder); + + // Apply pagination (simulating server-side pagination) + const paginatedData = paginateData(sortedData, offset, limit); + + return { + changeRequests: paginatedData, + total: mockChangeRequests.length, + }; + }, [offset, limit, sortBy, sortOrder]); + + // Simulate loading and return mock data + return { + ...mockData, + loading: false, + initialLoad: false, + error: null, + }; +}; + +// For now, use the mock version. Later, replace with the real API version +export { useChangeRequestsWithMockData as useChangeRequestsSearch }; \ No newline at end of file