Browse Source

chore(dashboard): Code cleanup (#3632)

Michael Bromley 6 months ago
parent
commit
9bf365cb55
100 changed files with 158 additions and 160 deletions
  1. 11 1
      .cursor/rules/dashboard.mdc
  2. 1 0
      packages/dashboard/scripts/generate-index.js
  3. 1 1
      packages/dashboard/src/app/routes/_authenticated/_administrators/components/administrator-bulk-actions.tsx
  4. 1 1
      packages/dashboard/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx
  5. 1 1
      packages/dashboard/src/app/routes/_authenticated/_channels/components/channel-bulk-actions.tsx
  6. 1 2
      packages/dashboard/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx
  7. 1 1
      packages/dashboard/src/app/routes/_authenticated/_collections/components/collection-contents-table.tsx
  8. 1 1
      packages/dashboard/src/app/routes/_authenticated/_collections/components/collection-filters-selector.tsx
  9. 1 1
      packages/dashboard/src/app/routes/_authenticated/_countries/components/country-bulk-actions.tsx
  10. 1 1
      packages/dashboard/src/app/routes/_authenticated/_customer-groups/components/customer-group-bulk-actions.tsx
  11. 1 1
      packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-address-form.tsx
  12. 1 1
      packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-bulk-actions.tsx
  13. 1 1
      packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-container.tsx
  14. 1 1
      packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-order-table.tsx
  15. 1 1
      packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-status-badge.tsx
  16. 1 1
      packages/dashboard/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx
  17. 1 2
      packages/dashboard/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx
  18. 1 1
      packages/dashboard/src/app/routes/_authenticated/_facets/components/facet-values-sheet.tsx
  19. 1 1
      packages/dashboard/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx
  20. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/customer-address-selector.tsx
  21. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/money-gross-net.tsx
  22. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/order-address.tsx
  23. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/order-history/order-history-container.tsx
  24. 6 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/order-history/order-history.tsx
  25. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/order-line-custom-fields-form.tsx
  26. 3 3
      packages/dashboard/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx
  27. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/order-table.tsx
  28. 2 2
      packages/dashboard/src/app/routes/_authenticated/_orders/components/order-tax-summary.tsx
  29. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/payment-details.tsx
  30. 1 1
      packages/dashboard/src/app/routes/_authenticated/_orders/components/shipping-method-selector.tsx
  31. 1 1
      packages/dashboard/src/app/routes/_authenticated/_payment-methods/components/payment-handler-selector.tsx
  32. 1 2
      packages/dashboard/src/app/routes/_authenticated/_payment-methods/components/payment-method-bulk-actions.tsx
  33. 1 2
      packages/dashboard/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx
  34. 4 1
      packages/dashboard/src/app/routes/_authenticated/_products/components/create-product-variants.tsx
  35. 5 1
      packages/dashboard/src/app/routes/_authenticated/_products/components/option-value-input.tsx
  36. 1 2
      packages/dashboard/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx
  37. 6 1
      packages/dashboard/src/app/routes/_authenticated/_products/components/product-option-select.tsx
  38. 1 1
      packages/dashboard/src/app/routes/_authenticated/_promotions/components/promotion-actions-selector.tsx
  39. 1 2
      packages/dashboard/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx
  40. 1 1
      packages/dashboard/src/app/routes/_authenticated/_promotions/components/promotion-conditions-selector.tsx
  41. 1 1
      packages/dashboard/src/app/routes/_authenticated/_roles/components/expandable-permissions.tsx
  42. 1 1
      packages/dashboard/src/app/routes/_authenticated/_roles/components/permissions-grid.tsx
  43. 1 1
      packages/dashboard/src/app/routes/_authenticated/_roles/components/role-bulk-actions.tsx
  44. 1 1
      packages/dashboard/src/app/routes/_authenticated/_sellers/components/seller-bulk-actions.tsx
  45. 1 1
      packages/dashboard/src/app/routes/_authenticated/_shipping-methods/components/fulfillment-handler-selector.tsx
  46. 1 1
      packages/dashboard/src/app/routes/_authenticated/_shipping-methods/components/shipping-calculator-selector.tsx
  47. 1 2
      packages/dashboard/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-bulk-actions.tsx
  48. 1 2
      packages/dashboard/src/app/routes/_authenticated/_stock-locations/components/stock-location-bulk-actions.tsx
  49. 1 1
      packages/dashboard/src/app/routes/_authenticated/_system/components/payload-dialog.tsx
  50. 1 1
      packages/dashboard/src/app/routes/_authenticated/_tax-categories/components/tax-category-bulk-actions.tsx
  51. 1 1
      packages/dashboard/src/app/routes/_authenticated/_tax-rates/components/tax-rate-bulk-actions.tsx
  52. 1 1
      packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-bulk-actions.tsx
  53. 1 1
      packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-countries-sheet.tsx
  54. 1 1
      packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-countries-table.tsx
  55. 1 1
      packages/dashboard/src/app/routes/_authenticated/index.tsx
  56. 1 1
      packages/dashboard/src/lib/components/data-display/boolean.tsx
  57. 1 1
      packages/dashboard/src/lib/components/data-display/date-time.tsx
  58. 1 1
      packages/dashboard/src/lib/components/data-display/json.tsx
  59. 1 1
      packages/dashboard/src/lib/components/data-input/affixed-input.tsx
  60. 1 1
      packages/dashboard/src/lib/components/data-input/richt-text-input.tsx
  61. 1 1
      packages/dashboard/src/lib/components/data-table/add-filter-menu.tsx
  62. 1 1
      packages/dashboard/src/lib/components/data-table/data-table-bulk-actions.tsx
  63. 1 1
      packages/dashboard/src/lib/components/data-table/data-table-column-header.tsx
  64. 1 1
      packages/dashboard/src/lib/components/data-table/data-table-filter-dialog.tsx
  65. 1 1
      packages/dashboard/src/lib/components/data-table/data-table.tsx
  66. 4 1
      packages/dashboard/src/lib/components/data-table/filters/data-table-boolean-filter.tsx
  67. 4 1
      packages/dashboard/src/lib/components/data-table/filters/data-table-datetime-filter.tsx
  68. 1 1
      packages/dashboard/src/lib/components/data-table/filters/data-table-id-filter.tsx
  69. 5 1
      packages/dashboard/src/lib/components/data-table/filters/data-table-number-filter.tsx
  70. 4 1
      packages/dashboard/src/lib/components/data-table/filters/data-table-string-filter.tsx
  71. 4 1
      packages/dashboard/src/lib/components/data-table/refresh-button.tsx
  72. 1 1
      packages/dashboard/src/lib/components/layout/nav-main.tsx
  73. 1 1
      packages/dashboard/src/lib/components/shared/asset/asset-bulk-actions.tsx
  74. 1 1
      packages/dashboard/src/lib/components/shared/asset/asset-preview-selector.tsx
  75. 1 1
      packages/dashboard/src/lib/components/shared/asset/asset-preview.tsx
  76. 1 1
      packages/dashboard/src/lib/components/shared/asset/asset-properties.tsx
  77. 1 1
      packages/dashboard/src/lib/components/shared/asset/focal-point-control.tsx
  78. 1 1
      packages/dashboard/src/lib/components/shared/channel-code-label.tsx
  79. 2 3
      packages/dashboard/src/lib/components/shared/copyable-text.tsx
  80. 1 1
      packages/dashboard/src/lib/components/shared/custom-fields-form.tsx
  81. 1 1
      packages/dashboard/src/lib/components/shared/error-page.tsx
  82. 7 1
      packages/dashboard/src/lib/components/shared/history-timeline/history-entry.tsx
  83. 1 1
      packages/dashboard/src/lib/components/shared/history-timeline/history-note-checkbox.tsx
  84. 1 1
      packages/dashboard/src/lib/components/shared/history-timeline/history-note-input.tsx
  85. 1 1
      packages/dashboard/src/lib/components/shared/history-timeline/history-timeline.tsx
  86. 1 1
      packages/dashboard/src/lib/components/shared/option-value-input.tsx
  87. 1 1
      packages/dashboard/src/lib/components/shared/paginated-list-data-table.tsx
  88. 1 1
      packages/dashboard/src/lib/components/shared/permission-guard.tsx
  89. 1 1
      packages/dashboard/src/lib/components/shared/product-variant-selector.tsx
  90. 1 1
      packages/dashboard/src/lib/components/shared/role-code-label.tsx
  91. 5 5
      packages/dashboard/src/lib/components/shared/stock-level-label.tsx
  92. 1 1
      packages/dashboard/src/lib/components/shared/tax-category-selector.tsx
  93. 1 1
      packages/dashboard/src/lib/components/shared/zone-selector.tsx
  94. 2 3
      packages/dashboard/src/lib/framework/alert/alert-extensions.tsx
  95. 2 1
      packages/dashboard/src/lib/framework/alert/alert-item.tsx
  96. 0 13
      packages/dashboard/src/lib/framework/alert/types.ts
  97. 2 10
      packages/dashboard/src/lib/framework/dashboard-widget/base-widget.tsx
  98. 0 22
      packages/dashboard/src/lib/framework/dashboard-widget/types.ts
  99. 1 1
      packages/dashboard/src/lib/framework/dashboard-widget/widget-extensions.tsx
  100. 1 1
      packages/dashboard/src/lib/framework/data-table/data-table-extensions.ts

+ 11 - 1
.cursor/rules/dashboard.mdc

@@ -1,5 +1,5 @@
 ---
-description: Dashboard package 
+description: Dashboard package
 globs: packages/dashboard/**/*
 alwaysApply: false
 ---
@@ -155,4 +155,14 @@ export function MyComponent() {
         </div>
     )
 }
+```
+
+## Typing React Components
+
+React components should have their props objects set to `Readonly<>`, for instance:
+
+```ts
+export function PaymentDetails({ payment, currencyCode }: Readonly<PaymentDetailsProps>) {
+  //...
+}
 ```

+ 1 - 0
packages/dashboard/scripts/generate-index.js

@@ -20,6 +20,7 @@ function getAllFiles(dir, fileList = []) {
             getAllFiles(filePath, fileList);
         } else if (
             file.match(/\.(ts|tsx|js|jsx)$/) &&
+            !file.startsWith('index.') && // Exclude index files
             !file.endsWith('.d.ts') &&
             !file.endsWith('.spec.ts')
         ) {

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_administrators/components/administrator-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteAdministratorsDocument } from '../administrators.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx

@@ -28,7 +28,7 @@ interface RolePermissionsDisplayProps {
     value: string[];
 }
 
-export function RolePermissionsDisplay({ value = [] }: RolePermissionsDisplayProps) {
+export function RolePermissionsDisplay({ value = [] }: Readonly<RolePermissionsDisplayProps>) {
     const { i18n } = useLingui();
     const groupedPermissions = useGroupedPermissions();
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_channels/components/channel-bulk-actions.tsx

@@ -1,6 +1,6 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteChannelsDocument } from '../channels.graphql.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 
 export const DeleteChannelsBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
     return (

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx

@@ -2,9 +2,8 @@ import { useQueryClient } from '@tanstack/react-query';
 
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
-import { useChannel } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel } from '@/vdb/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { DuplicateBulkAction } from '../../../../common/duplicate-bulk-action.js';
 import {

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_collections/components/collection-contents-table.tsx

@@ -28,7 +28,7 @@ export interface CollectionContentsTableProps {
     collectionId?: string;
 }
 
-export function CollectionContentsTable({ collectionId }: CollectionContentsTableProps) {
+export function CollectionContentsTable({ collectionId }: Readonly<CollectionContentsTableProps>) {
     const [sorting, setSorting] = useState<SortingState>([]);
     const [page, setPage] = useState(1);
     const [pageSize, setPageSize] = useState(10);

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_collections/components/collection-filters-selector.tsx

@@ -19,7 +19,7 @@ export interface CollectionFiltersSelectorProps {
     onChange: (filters: ConfigurableOperationInputType[]) => void;
 }
 
-export function CollectionFiltersSelector({ value, onChange }: CollectionFiltersSelectorProps) {
+export function CollectionFiltersSelector({ value, onChange }: Readonly<CollectionFiltersSelectorProps>) {
     const { data: filtersData } = useQuery(getCollectionFiltersQueryOptions);
 
     const filters = filtersData?.collectionFilters;

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_countries/components/country-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteCountriesDocument } from '../countries.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_customer-groups/components/customer-group-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteCustomerGroupsDocument } from '../customer-groups.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-address-form.tsx

@@ -58,7 +58,7 @@ interface CustomerAddressFormProps {
     onCancel?: () => void;
 }
 
-export function CustomerAddressForm({ address, onSubmit, onCancel }: CustomerAddressFormProps) {
+export function CustomerAddressForm({ address, onSubmit, onCancel }: Readonly<CustomerAddressFormProps>) {
     const { i18n } = useLingui();
 
     // Fetch available countries

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteCustomersDocument } from '../customers.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-container.tsx

@@ -10,7 +10,7 @@ interface CustomerHistoryContainerProps {
     customerId: string;
 }
 
-export function CustomerHistoryContainer({ customerId }: CustomerHistoryContainerProps) {
+export function CustomerHistoryContainer({ customerId }: Readonly<CustomerHistoryContainerProps>) {
     const {
         historyEntries,
         customer,

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-order-table.tsx

@@ -11,7 +11,7 @@ interface CustomerOrderTableProps {
     customerId: string;
 }
 
-export function CustomerOrderTable({ customerId }: CustomerOrderTableProps) {
+export function CustomerOrderTable({ customerId }: Readonly<CustomerOrderTableProps>) {
     const [page, setPage] = useState(1);
     const [pageSize, setPageSize] = useState(10);
     const [sorting, setSorting] = useState<SortingState>([{ id: 'orderPlacedAt', desc: true }]);

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-status-badge.tsx

@@ -8,7 +8,7 @@ export interface CustomerStatusBadgeProps {
     user?: { verified: boolean } | null;
 }
 
-export function CustomerStatusBadge({ user }: CustomerStatusBadgeProps) {
+export function CustomerStatusBadge({ user }: Readonly<CustomerStatusBadgeProps>) {
     const status = user ? (user.verified ? 'verified' : 'registered') : 'guest';
     return (
         <Badge variant="outline">

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx

@@ -40,7 +40,7 @@ export interface EditFacetValueProps {
     onSuccess?: () => void;
 }
 
-export function EditFacetValue({ facetValueId, onSuccess }: EditFacetValueProps) {
+export function EditFacetValue({ facetValueId, onSuccess }: Readonly<EditFacetValueProps>) {
     const {
         settings: { contentLanguage },
     } = useUserSettings();

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx

@@ -2,10 +2,9 @@ import { toast } from 'sonner';
 
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
 import { ResultOf } from '@/vdb/graphql/graphql.js';
-import { useChannel } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel } from '@/vdb/index.js';
 import { useLingui } from '@/vdb/lib/trans.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { DuplicateBulkAction } from '../../../../common/duplicate-bulk-action.js';

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_facets/components/facet-values-sheet.tsx

@@ -17,7 +17,7 @@ export interface FacetValuesSheetProps {
     children?: React.ReactNode;
 }
 
-export function FacetValuesSheet({ facetName, facetId, children }: FacetValuesSheetProps) {
+export function FacetValuesSheet({ facetName, facetId, children }: Readonly<FacetValuesSheetProps>) {
     return (
         <Sheet>
             <SheetTrigger asChild>

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx

@@ -28,7 +28,7 @@ export interface FacetValuesTableProps {
     facetId: string;
 }
 
-export function FacetValuesTable({ facetId }: FacetValuesTableProps) {
+export function FacetValuesTable({ facetId }: Readonly<FacetValuesTableProps>) {
     const [sorting, setSorting] = useState<SortingState>([]);
     const [page, setPage] = useState(1);
     const [pageSize, setPageSize] = useState(10);

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/customer-address-selector.tsx

@@ -31,7 +31,7 @@ interface CustomerAddressSelectorProps {
     onSelect: (address: ResultOf<typeof addressFragment>) => void;
 }
 
-export function CustomerAddressSelector({ customerId, onSelect }: CustomerAddressSelectorProps) {
+export function CustomerAddressSelector({ customerId, onSelect }: Readonly<CustomerAddressSelectorProps>) {
     const { i18n } = useLingui();
     const [open, setOpen] = useState(false);
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/money-gross-net.tsx

@@ -6,7 +6,7 @@ export interface MoneyGrossNetProps {
     currencyCode: string;
 }
 
-export function MoneyGrossNet({ priceWithTax, price, currencyCode }: MoneyGrossNetProps) {
+export function MoneyGrossNet({ priceWithTax, price, currencyCode }: Readonly<MoneyGrossNetProps>) {
     return (
         <div className="flex flex-col gap-1">
             <div>

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/order-address.tsx

@@ -5,7 +5,7 @@ import { orderAddressFragment } from '../orders.graphql.js';
 
 type OrderAddress = ResultOf<typeof orderAddressFragment>;
 
-export function OrderAddress({ address }: { address?: OrderAddress }) {
+export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>) {
     if (!address) {
         return null;
     }

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/order-history/order-history-container.tsx

@@ -10,7 +10,7 @@ interface OrderHistoryContainerProps {
     orderId: string;
 }
 
-export function OrderHistoryContainer({ orderId }: OrderHistoryContainerProps) {
+export function OrderHistoryContainer({ orderId }: Readonly<OrderHistoryContainerProps>) {
     const {
         historyEntries,
         order,

+ 6 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/order-history/order-history.tsx

@@ -17,7 +17,12 @@ interface OrderHistoryProps {
     onDeleteNote?: (entryId: string) => void;
 }
 
-export function OrderHistory({ historyEntries, onAddNote, onUpdateNote, onDeleteNote }: OrderHistoryProps) {
+export function OrderHistory({
+    historyEntries,
+    onAddNote,
+    onUpdateNote,
+    onDeleteNote,
+}: Readonly<OrderHistoryProps>) {
     const getTimelineIcon = (entry: OrderHistoryProps['historyEntries'][0]) => {
         switch (entry.type) {
             case 'ORDER_PAYMENT_TRANSITION':

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/order-line-custom-fields-form.tsx

@@ -10,7 +10,7 @@ interface OrderLineCustomFieldsFormProps {
     form: UseFormReturn<any>;
 }
 
-export function OrderLineCustomFieldsForm({ onUpdate, form }: OrderLineCustomFieldsFormProps) {
+export function OrderLineCustomFieldsForm({ onUpdate, form }: Readonly<OrderLineCustomFieldsFormProps>) {
     const onSubmit = (values: any) => {
         onUpdate(values.input?.customFields);
     };

+ 3 - 3
packages/dashboard/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx

@@ -11,14 +11,14 @@ export interface OrderTableTotalsProps {
     columnCount: number;
 }
 
-export function OrderTableTotals({ order, columnCount }: OrderTableTotalsProps) {
+export function OrderTableTotals({ order, columnCount }: Readonly<OrderTableTotalsProps>) {
     const currencyCode = order.currencyCode;
 
     return (
         <>
             {order.discounts?.length > 0
-                ? order.discounts.map(discount => (
-                      <TableRow>
+                ? order.discounts.map((discount, index) => (
+                      <TableRow key={`${discount.description}-${index}`}>
                           <TableCell colSpan={columnCount - 1} className="h-12">
                               <Trans>Discount</Trans>: {discount.description}
                           </TableCell>

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/order-table.tsx

@@ -20,7 +20,7 @@ export interface OrderTableProps {
     order: OrderFragment;
 }
 
-export function OrderTable({ order }: OrderTableProps) {
+export function OrderTable({ order }: Readonly<OrderTableProps>) {
     const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
 
     const currencyCode = order.currencyCode;

+ 2 - 2
packages/dashboard/src/app/routes/_authenticated/_orders/components/order-tax-summary.tsx

@@ -1,10 +1,10 @@
 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/vdb/components/ui/table.js';
 import { useLocalFormat } from '@/vdb/hooks/use-local-format.js';
-import { Trans } from '@/vdb/lib/trans';
+import { Trans } from '@/vdb/lib/trans.js';
 import { ResultOf } from 'gql.tada';
 import { orderDetailFragment } from '../orders.graphql.js';
 
-export function OrderTaxSummary({ order }: { order: ResultOf<typeof orderDetailFragment> }) {
+export function OrderTaxSummary({ order }: Readonly<{ order: ResultOf<typeof orderDetailFragment> }>) {
     const { formatCurrency } = useLocalFormat();
     return (
         <div>

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/payment-details.tsx

@@ -8,7 +8,7 @@ type PaymentDetailsProps = {
     currencyCode: string;
 };
 
-export function PaymentDetails({ payment, currencyCode }: PaymentDetailsProps) {
+export function PaymentDetails({ payment, currencyCode }: Readonly<PaymentDetailsProps>) {
     const { formatCurrency, formatDate } = useLocalFormat();
     const t = (key: string) => key;
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_orders/components/shipping-method-selector.tsx

@@ -20,7 +20,7 @@ export function ShippingMethodSelector({
     selectedShippingMethodId,
     currencyCode,
     onSelect,
-}: ShippingMethodSelectorProps) {
+}: Readonly<ShippingMethodSelectorProps>) {
     return (
         <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
             {eligibleShippingMethods?.length ? (

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_payment-methods/components/payment-handler-selector.tsx

@@ -33,7 +33,7 @@ interface PaymentHandlerSelectorProps {
     onChange: (value: ConfigurableOperationInputType | undefined) => void;
 }
 
-export function PaymentHandlerSelector({ value, onChange }: PaymentHandlerSelectorProps) {
+export function PaymentHandlerSelector({ value, onChange }: Readonly<PaymentHandlerSelectorProps>) {
     const { data: handlersData } = useQuery({
         queryKey: ['paymentMethodHandlers'],
         queryFn: () => api.query(paymentHandlersDocument),

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_payment-methods/components/payment-method-bulk-actions.tsx

@@ -1,8 +1,7 @@
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
-import { useChannel } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel } from '@/vdb/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 
 import {

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx

@@ -5,9 +5,8 @@ import { DataTableBulkActionItem } from '@/vdb/components/data-table/data-table-
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { usePriceFactor } from '@/vdb/components/shared/assign-to-channel-dialog.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
-import { useChannel, usePaginatedList } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel, usePaginatedList } from '@/vdb/index.js';
 import { Trans } from '@/vdb/lib/trans.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 

+ 4 - 1
packages/dashboard/src/app/routes/_authenticated/_products/components/create-product-variants.tsx

@@ -97,7 +97,10 @@ interface CreateProductVariantsProps {
     onChange?: ({ data }: { data: VariantConfiguration }) => void;
 }
 
-export function CreateProductVariants({ currencyCode = 'USD', onChange }: CreateProductVariantsProps) {
+export function CreateProductVariants({
+    currencyCode = 'USD',
+    onChange,
+}: Readonly<CreateProductVariantsProps>) {
     const { data: stockLocationsResult } = useQuery({
         queryKey: ['stockLocations'],
         queryFn: () => api.query(getStockLocationsDocument, { options: { take: 100 } }),

+ 5 - 1
packages/dashboard/src/app/routes/_authenticated/_products/components/option-value-input.tsx

@@ -32,7 +32,11 @@ interface OptionValueInputProps {
     disabled?: boolean;
 }
 
-export function OptionValueInput({ groupName, groupIndex, disabled = false }: OptionValueInputProps) {
+export function OptionValueInput({
+    groupName,
+    groupIndex,
+    disabled = false,
+}: Readonly<OptionValueInputProps>) {
     const { control, watch } = useFormContext<FormValues>();
     const { fields, append, remove } = useFieldArray({
         control,

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx

@@ -5,9 +5,8 @@ import { DataTableBulkActionItem } from '@/vdb/components/data-table/data-table-
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { usePriceFactor } from '@/vdb/components/shared/assign-to-channel-dialog.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
-import { useChannel, usePaginatedList } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel, usePaginatedList } from '@/vdb/index.js';
 import { Trans } from '@/vdb/lib/trans.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { DuplicateBulkAction } from '../../../../common/duplicate-bulk-action.js';

+ 6 - 1
packages/dashboard/src/app/routes/_authenticated/_products/components/product-option-select.tsx

@@ -33,7 +33,12 @@ interface ProductOptionSelectProps {
     onCreateOption: (name: string) => void;
 }
 
-export function ProductOptionSelect({ group, value, onChange, onCreateOption }: ProductOptionSelectProps) {
+export function ProductOptionSelect({
+    group,
+    value,
+    onChange,
+    onCreateOption,
+}: Readonly<ProductOptionSelectProps>) {
     const [open, setOpen] = useState(false);
     const [newOptionInput, setNewOptionInput] = useState('');
     const { i18n } = useLingui();

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_promotions/components/promotion-actions-selector.tsx

@@ -34,7 +34,7 @@ interface PromotionActionsSelectorProps {
     onChange: (value: ConfigurableOperationInputType[]) => void;
 }
 
-export function PromotionActionsSelector({ value, onChange }: PromotionActionsSelectorProps) {
+export function PromotionActionsSelector({ value, onChange }: Readonly<PromotionActionsSelectorProps>) {
     const { data: actionsData } = useQuery({
         queryKey: ['promotionActions'],
         queryFn: () => api.query(promotionActionsDocument),

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx

@@ -1,8 +1,7 @@
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
-import { useChannel } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel } from '@/vdb/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { DuplicateBulkAction } from '../../../../common/duplicate-bulk-action.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_promotions/components/promotion-conditions-selector.tsx

@@ -34,7 +34,7 @@ interface PromotionConditionsSelectorProps {
     onChange: (value: ConfigurableOperationInputType[]) => void;
 }
 
-export function PromotionConditionsSelector({ value, onChange }: PromotionConditionsSelectorProps) {
+export function PromotionConditionsSelector({ value, onChange }: Readonly<PromotionConditionsSelectorProps>) {
     const { data: conditionsData } = useQuery({
         queryKey: ['promotionConditions'],
         queryFn: () => api.query(promotionConditionsDocument),

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_roles/components/expandable-permissions.tsx

@@ -13,7 +13,7 @@ import { ResultOf } from 'gql.tada';
 import { PlusIcon } from 'lucide-react';
 import { roleItemFragment } from '../roles.graphql.js';
 
-export function ExpandablePermissions({ role }: { role: ResultOf<typeof roleItemFragment> }) {
+export function ExpandablePermissions({ role }: Readonly<{ role: ResultOf<typeof roleItemFragment> }>) {
     const permissionsToPreview = role.permissions.slice(0, 3);
 
     return (

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_roles/components/permissions-grid.tsx

@@ -18,7 +18,7 @@ interface PermissionsGridProps {
     readonly?: boolean;
 }
 
-export function PermissionsGrid({ value, onChange, readonly = false }: PermissionsGridProps) {
+export function PermissionsGrid({ value, onChange, readonly = false }: Readonly<PermissionsGridProps>) {
     const { i18n } = useLingui();
     const groupedPermissions = useGroupedPermissions();
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_roles/components/role-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteRolesDocument } from '../roles.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_sellers/components/seller-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteSellersDocument } from '../sellers.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_shipping-methods/components/fulfillment-handler-selector.tsx

@@ -20,7 +20,7 @@ interface FulfillmentHandlerSelectorProps {
     onChange: (value: string | undefined) => void;
 }
 
-export function FulfillmentHandlerSelector({ value, onChange }: FulfillmentHandlerSelectorProps) {
+export function FulfillmentHandlerSelector({ value, onChange }: Readonly<FulfillmentHandlerSelectorProps>) {
     const { data: fulfillmentHandlersData } = useQuery({
         queryKey: ['fulfillmentHandlers'],
         queryFn: () => api.query(fulfillmentHandlersDocument),

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_shipping-methods/components/shipping-calculator-selector.tsx

@@ -33,7 +33,7 @@ interface ShippingCalculatorSelectorProps {
     onChange: (value: ConfigurableOperationInputType | undefined) => void;
 }
 
-export function ShippingCalculatorSelector({ value, onChange }: ShippingCalculatorSelectorProps) {
+export function ShippingCalculatorSelector({ value, onChange }: Readonly<ShippingCalculatorSelectorProps>) {
     const { data: calculatorsData } = useQuery({
         queryKey: ['shippingCalculators'],
         queryFn: () => api.query(shippingCalculatorsDocument),

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-bulk-actions.tsx

@@ -1,8 +1,7 @@
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
-import { useChannel } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel } from '@/vdb/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 
 import {

+ 1 - 2
packages/dashboard/src/app/routes/_authenticated/_stock-locations/components/stock-location-bulk-actions.tsx

@@ -1,8 +1,7 @@
 import { AssignToChannelBulkAction } from '@/vdb/components/shared/assign-to-channel-bulk-action.js';
 import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from-channel-bulk-action.js';
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
 import { api } from '@/vdb/graphql/api.js';
-import { useChannel } from '@/vdb/index.js';
+import { BulkActionComponent, useChannel } from '@/vdb/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 
 import {

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_system/components/payload-dialog.tsx

@@ -16,7 +16,7 @@ type PayloadDialogProps = {
     description?: string | React.ReactNode;
 };
 
-export function PayloadDialog({ payload, trigger, title, description }: PayloadDialogProps) {
+export function PayloadDialog({ payload, trigger, title, description }: Readonly<PayloadDialogProps>) {
     return (
         <Dialog>
             <DialogTrigger asChild>{trigger}</DialogTrigger>

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_tax-categories/components/tax-category-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteTaxCategoriesDocument } from '../tax-categories.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_tax-rates/components/tax-rate-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteTaxRatesDocument } from '../tax-rates.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-bulk-actions.tsx

@@ -1,4 +1,4 @@
-import { BulkActionComponent } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkActionComponent } from '@/vdb/framework/extension-api/types/index.js';
 import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
 import { deleteZonesDocument } from '../zones.graphql.js';
 

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-countries-sheet.tsx

@@ -9,7 +9,7 @@ interface ZoneCountriesSheetProps {
     children?: React.ReactNode;
 }
 
-export function ZoneCountriesSheet({ zoneId, zoneName, children }: ZoneCountriesSheetProps) {
+export function ZoneCountriesSheet({ zoneId, zoneName, children }: Readonly<ZoneCountriesSheetProps>) {
     return (
         <Sheet>
             <SheetTrigger asChild>

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/_zones/components/zone-countries-table.tsx

@@ -15,7 +15,7 @@ interface ZoneCountriesTableProps {
     canAddCountries?: boolean;
 }
 
-export function ZoneCountriesTable({ zoneId, canAddCountries = false }: ZoneCountriesTableProps) {
+export function ZoneCountriesTable({ zoneId, canAddCountries = false }: Readonly<ZoneCountriesTableProps>) {
     const { data, refetch } = useQuery({
         queryKey: ['zone', zoneId],
         queryFn: () => api.query(zoneMembersQuery, { zoneId }),

+ 1 - 1
packages/dashboard/src/app/routes/_authenticated/index.tsx

@@ -1,9 +1,9 @@
 import { Button } from '@/vdb/components/ui/button.js';
-import { DashboardWidgetInstance } from '@/vdb/framework/dashboard-widget/types.js';
 import {
     getDashboardWidget,
     getDashboardWidgetRegistry,
 } from '@/vdb/framework/dashboard-widget/widget-extensions.js';
+import { DashboardWidgetInstance } from '@/vdb/framework/extension-api/types/widgets.js';
 import {
     FullWidthPageBlock,
     Page,

+ 1 - 1
packages/dashboard/src/lib/components/data-display/boolean.tsx

@@ -2,7 +2,7 @@ import { CheckIcon, XIcon } from 'lucide-react';
 import React from 'react';
 import { Badge } from '../ui/badge.js';
 
-export function BooleanDisplayCheckbox({ value }: { value: boolean }) {
+export function BooleanDisplayCheckbox({ value }: Readonly<{ value: boolean }>) {
     return value ? <CheckIcon className="opacity-70" /> : <XIcon className="opacity-70" />;
 }
 

+ 1 - 1
packages/dashboard/src/lib/components/data-display/date-time.tsx

@@ -1,6 +1,6 @@
 import { useLocalFormat } from '@/vdb/hooks/use-local-format.js';
 
-export function DateTime({ value }: { value: string | Date }) {
+export function DateTime({ value }: Readonly<{ value: string | Date }>) {
     const { formatDate } = useLocalFormat();
     let renderedDate: string;
     try {

+ 1 - 1
packages/dashboard/src/lib/components/data-display/json.tsx

@@ -1,5 +1,5 @@
 import { JsonEditor } from 'json-edit-react';
 
-export function Json({ value }: { value: any }) {
+export function Json({ value }: Readonly<{ value: any }>) {
     return <JsonEditor data={value} />;
 }

+ 1 - 1
packages/dashboard/src/lib/components/data-input/affixed-input.tsx

@@ -6,7 +6,7 @@ interface AffixedInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
     suffix?: ReactNode;
 }
 
-export function AffixedInput({ prefix, suffix, className = '', ...props }: AffixedInputProps) {
+export function AffixedInput({ prefix, suffix, className = '', ...props }: Readonly<AffixedInputProps>) {
     const prefixRef = useRef<HTMLSpanElement>(null);
     const suffixRef = useRef<HTMLSpanElement>(null);
     const [prefixWidth, setPrefixWidth] = useState(0);

+ 1 - 1
packages/dashboard/src/lib/components/data-input/richt-text-input.tsx

@@ -26,7 +26,7 @@ export interface RichTextInputProps {
     onChange: (value: string) => void;
 }
 
-export function RichTextInput({ value, onChange }: RichTextInputProps) {
+export function RichTextInput({ value, onChange }: Readonly<RichTextInputProps>) {
     const editor = useEditor({
         parseOptions: {
             preserveWhitespace: 'full',

+ 1 - 1
packages/dashboard/src/lib/components/data-table/add-filter-menu.tsx

@@ -17,7 +17,7 @@ export interface AddFilterMenuProps {
     columns: Column<any, unknown>[];
 }
 
-export function AddFilterMenu({ columns }: AddFilterMenuProps) {
+export function AddFilterMenu({ columns }: Readonly<AddFilterMenuProps>) {
     const [selectedColumn, setSelectedColumn] = useState<ColumnDef<any> | null>(null);
     const [isDialogOpen, setIsDialogOpen] = useState(false);
 

+ 1 - 1
packages/dashboard/src/lib/components/data-table/data-table-bulk-actions.tsx

@@ -8,7 +8,7 @@ import {
     DropdownMenuTrigger,
 } from '@/vdb/components/ui/dropdown-menu.js';
 import { getBulkActions } from '@/vdb/framework/data-table/data-table-extensions.js';
-import { BulkAction } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
 import { usePageBlock } from '@/vdb/hooks/use-page-block.js';
 import { usePage } from '@/vdb/hooks/use-page.js';
 import { Trans } from '@/vdb/lib/trans.js';

+ 1 - 1
packages/dashboard/src/lib/components/data-table/data-table-column-header.tsx

@@ -8,7 +8,7 @@ export interface DataTableColumnHeaderProps {
     headerContext: HeaderContext<any, any>;
 }
 
-export function DataTableColumnHeader({ headerContext, customConfig }: DataTableColumnHeaderProps) {
+export function DataTableColumnHeader({ headerContext, customConfig }: Readonly<DataTableColumnHeaderProps>) {
     const { column } = headerContext;
     const isSortable = column.getCanSort();
 

+ 1 - 1
packages/dashboard/src/lib/components/data-table/data-table-filter-dialog.tsx

@@ -21,7 +21,7 @@ export interface DataTableFilterDialogProps {
     column: Column<any>;
 }
 
-export function DataTableFilterDialog({ column }: DataTableFilterDialogProps) {
+export function DataTableFilterDialog({ column }: Readonly<DataTableFilterDialogProps>) {
     const columnFilter = column.getFilterValue() as Record<string, string> | undefined;
     const [filter, setFilter] = useState(columnFilter);
 

+ 1 - 1
packages/dashboard/src/lib/components/data-table/data-table.tsx

@@ -6,7 +6,7 @@ import { RefreshButton } from '@/vdb/components/data-table/refresh-button.js';
 import { Input } from '@/vdb/components/ui/input.js';
 import { Skeleton } from '@/vdb/components/ui/skeleton.js';
 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/vdb/components/ui/table.js';
-import { BulkAction } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
 import { useChannel } from '@/vdb/hooks/use-channel.js';
 import {
     ColumnDef,

+ 4 - 1
packages/dashboard/src/lib/components/data-table/filters/data-table-boolean-filter.tsx

@@ -13,7 +13,10 @@ export interface DataTableBooleanFilterProps {
 
 export const BOOLEAN_OPERATORS = ['eq', 'isNull'] as const;
 
-export function DataTableBooleanFilter({ value: incomingValue, onChange }: DataTableBooleanFilterProps) {
+export function DataTableBooleanFilter({
+    value: incomingValue,
+    onChange,
+}: Readonly<DataTableBooleanFilterProps>) {
     const initialOperator = incomingValue ? (Object.keys(incomingValue)[0] ?? 'eq') : 'eq';
     const initialValue = incomingValue ? Object.values(incomingValue)[0] : true;
     const [operator, setOperator] = useState<string>(initialOperator ?? 'eq');

+ 4 - 1
packages/dashboard/src/lib/components/data-table/filters/data-table-datetime-filter.tsx

@@ -10,7 +10,10 @@ export interface DataTableDateTimeFilterProps {
 
 export const DATETIME_OPERATORS = ['eq', 'before', 'after', 'between', 'isNull'] as const;
 
-export function DataTableDateTimeFilter({ value: incomingValue, onChange }: DataTableDateTimeFilterProps) {
+export function DataTableDateTimeFilter({
+    value: incomingValue,
+    onChange,
+}: Readonly<DataTableDateTimeFilterProps>) {
     const initialOperator = incomingValue ? Object.keys(incomingValue)[0] : 'eq';
     const initialValue = incomingValue ? Object.values(incomingValue)[0] : '';
     const [operator, setOperator] = useState<string>(initialOperator ?? 'eq');

+ 1 - 1
packages/dashboard/src/lib/components/data-table/filters/data-table-id-filter.tsx

@@ -12,7 +12,7 @@ export interface DataTableIdFilterProps {
 
 export const ID_OPERATORS = ['eq', 'notEq', 'in', 'notIn', 'isNull'] as const;
 
-export function DataTableIdFilter({ value: incomingValue, onChange }: DataTableIdFilterProps) {
+export function DataTableIdFilter({ value: incomingValue, onChange }: Readonly<DataTableIdFilterProps>) {
     const initialOperator = incomingValue ? Object.keys(incomingValue)[0] : 'eq';
     const initialValue = incomingValue ? Object.values(incomingValue)[0] : '';
     const [operator, setOperator] = useState<string>(initialOperator ?? 'eq');

+ 5 - 1
packages/dashboard/src/lib/components/data-table/filters/data-table-number-filter.tsx

@@ -13,7 +13,11 @@ export interface DataTableNumberFilterProps {
 
 export const NUMBER_OPERATORS = ['eq', 'gt', 'gte', 'lt', 'lte', 'isNull', 'between'] as const;
 
-export function DataTableNumberFilter({ mode, value: incomingValue, onChange }: DataTableNumberFilterProps) {
+export function DataTableNumberFilter({
+    mode,
+    value: incomingValue,
+    onChange,
+}: Readonly<DataTableNumberFilterProps>) {
     const { activeChannel } = useChannel();
     const initialOperator = incomingValue ? Object.keys(incomingValue)[0] : 'eq';
     const initialValue = incomingValue ? Object.values(incomingValue)[0] : 0;

+ 4 - 1
packages/dashboard/src/lib/components/data-table/filters/data-table-string-filter.tsx

@@ -21,7 +21,10 @@ export const STRING_OPERATORS = [
     'isNull',
 ] as const;
 
-export function DataTableStringFilter({ value: incomingValue, onChange }: DataTableStringFilterProps) {
+export function DataTableStringFilter({
+    value: incomingValue,
+    onChange,
+}: Readonly<DataTableStringFilterProps>) {
     const initialOperator = incomingValue ? Object.keys(incomingValue)[0] : 'contains';
     const initialValue = incomingValue ? Object.values(incomingValue)[0] : '';
     const [operator, setOperator] = useState<string>(initialOperator ?? 'contains');

+ 4 - 1
packages/dashboard/src/lib/components/data-table/refresh-button.tsx

@@ -22,7 +22,10 @@ function useDelayedLoading(isLoading: boolean, delayMs: number = 100) {
     return delayedLoading;
 }
 
-export function RefreshButton({ onRefresh, isLoading }: { onRefresh: () => void; isLoading: boolean }) {
+export function RefreshButton({
+    onRefresh,
+    isLoading,
+}: Readonly<{ onRefresh: () => void; isLoading: boolean }>) {
     const delayedLoading = useDelayedLoading(isLoading, 100);
 
     const handleClick = () => {

+ 1 - 1
packages/dashboard/src/lib/components/layout/nav-main.tsx

@@ -28,7 +28,7 @@ function sortByOrder<T extends { order?: number; title: string }>(a: T, b: T) {
     return orderA - orderB;
 }
 
-export function NavMain({ items }: { items: Array<NavMenuSection | NavMenuItem> }) {
+export function NavMain({ items }: Readonly<{ items: Array<NavMenuSection | NavMenuItem> }>) {
     const location = useLocation();
     // State to track which bottom section is currently open
     const [openBottomSectionId, setOpenBottomSectionId] = React.useState<string | null>(null);

+ 1 - 1
packages/dashboard/src/lib/components/shared/asset/asset-bulk-actions.tsx

@@ -32,7 +32,7 @@ interface AssetBulkActionsProps {
     refetch: () => void;
 }
 
-export function AssetBulkActions({ selection, bulkActions, refetch }: AssetBulkActionsProps) {
+export function AssetBulkActions({ selection, bulkActions, refetch }: Readonly<AssetBulkActionsProps>) {
     const { pageId } = usePage();
     const { blockId } = usePageBlock();
 

+ 1 - 1
packages/dashboard/src/lib/components/shared/asset/asset-preview-selector.tsx

@@ -8,7 +8,7 @@ export interface AssetPreviewSelectorProps {
     height: number;
 }
 
-export function AssetPreviewSelector({ size, setSize, width, height }: AssetPreviewSelectorProps) {
+export function AssetPreviewSelector({ size, setSize, width, height }: Readonly<AssetPreviewSelectorProps>) {
     return (
         <div className="flex items-center gap-2">
             <Select value={size} onValueChange={value => setSize(value as PreviewPreset)}>

+ 1 - 1
packages/dashboard/src/lib/components/shared/asset/asset-preview.tsx

@@ -19,7 +19,7 @@ interface AssetPreviewProps {
     customFields?: any[];
 }
 
-export function AssetPreview({ asset, assets, customFields = [] }: AssetPreviewProps) {
+export function AssetPreview({ asset, assets, customFields = [] }: Readonly<AssetPreviewProps>) {
     const [size, setSize] = useState<PreviewPreset>('medium');
     const [width, setWidth] = useState(0);
     const [height, setHeight] = useState(0);

+ 1 - 1
packages/dashboard/src/lib/components/shared/asset/asset-properties.tsx

@@ -8,7 +8,7 @@ export interface AssetPropertiesProps {
     asset: AssetFragment;
 }
 
-export function AssetProperties({ asset }: AssetPropertiesProps) {
+export function AssetProperties({ asset }: Readonly<AssetPropertiesProps>) {
     return (
         <div className="space-y-4">
             <div>

+ 1 - 1
packages/dashboard/src/lib/components/shared/asset/focal-point-control.tsx

@@ -13,7 +13,7 @@ interface FocalPointControlProps {
     onChange: (point: Point) => void;
 }
 
-export function FocalPointControl({ width, height, point, onChange }: FocalPointControlProps) {
+export function FocalPointControl({ width, height, point, onChange }: Readonly<FocalPointControlProps>) {
     const [dragging, setDragging] = useState(false);
 
     useEffect(() => {

+ 1 - 1
packages/dashboard/src/lib/components/shared/channel-code-label.tsx

@@ -1,6 +1,6 @@
 import { DEFAULT_CHANNEL_CODE } from '@/vdb/constants.js';
 import { Trans } from '@/vdb/lib/trans.js';
 
-export function ChannelCodeLabel({ code }: { code: string } | { code: undefined }) {
+export function ChannelCodeLabel({ code }: Readonly<{ code: string }> | Readonly<{ code: undefined }>) {
     return code === DEFAULT_CHANNEL_CODE ? <Trans>Default channel</Trans> : code;
 }

+ 2 - 3
packages/dashboard/src/lib/components/shared/copyable-text.tsx

@@ -1,9 +1,8 @@
 import { useCopyToClipboard } from '@uidotdev/usehooks';
-import { CopyIcon } from 'lucide-react';
+import { CheckIcon, CopyIcon } from 'lucide-react';
 import { useState } from 'react';
-import { CheckIcon } from 'lucide-react';
 
-export function CopyableText({ text }: { text: string }) {
+export function CopyableText({ text }: Readonly<{ text: string }>) {
     const [copiedId, setCopiedId] = useState<string | null>(null);
     const [, copy] = useCopyToClipboard();
 

+ 1 - 1
packages/dashboard/src/lib/components/shared/custom-fields-form.tsx

@@ -28,7 +28,7 @@ interface CustomFieldsFormProps {
     formPathPrefix?: string;
 }
 
-export function CustomFieldsForm({ entityType, control, formPathPrefix }: CustomFieldsFormProps) {
+export function CustomFieldsForm({ entityType, control, formPathPrefix }: Readonly<CustomFieldsFormProps>) {
     const {
         settings: { displayLanguage },
     } = useUserSettings();

+ 1 - 1
packages/dashboard/src/lib/components/shared/error-page.tsx

@@ -11,7 +11,7 @@ export interface ErrorPageProps {
  * @description
  * A generic error page that displays an error message.
  */
-export function ErrorPage({ message }: ErrorPageProps) {
+export function ErrorPage({ message }: Readonly<ErrorPageProps>) {
     return (
         <Page pageId="error-page">
             <PageTitle>

+ 7 - 1
packages/dashboard/src/lib/components/shared/history-timeline/history-entry.tsx

@@ -33,7 +33,13 @@ interface HistoryEntryProps {
     children: React.ReactNode;
 }
 
-export function HistoryEntry({ entry, isNoteEntry, timelineIcon, title, children }: HistoryEntryProps) {
+export function HistoryEntry({
+    entry,
+    isNoteEntry,
+    timelineIcon,
+    title,
+    children,
+}: Readonly<HistoryEntryProps>) {
     const { formatDate } = useLocalFormat();
     const { editNote, deleteNote } = useHistoryTimeline();
 

+ 1 - 1
packages/dashboard/src/lib/components/shared/history-timeline/history-note-checkbox.tsx

@@ -6,7 +6,7 @@ interface HistoryNoteCheckboxProps {
     onChange: (value: boolean) => void;
 }
 
-export function HistoryNoteCheckbox({ value, onChange }: HistoryNoteCheckboxProps) {
+export function HistoryNoteCheckbox({ value, onChange }: Readonly<HistoryNoteCheckboxProps>) {
     return (
         <div className="flex items-center space-x-2">
             <Checkbox

+ 1 - 1
packages/dashboard/src/lib/components/shared/history-timeline/history-note-input.tsx

@@ -7,7 +7,7 @@ interface HistoryNoteInputProps {
     onAddNote: (note: string, isPrivate: boolean) => void;
 }
 
-export function HistoryNoteInput({ onAddNote }: HistoryNoteInputProps) {
+export function HistoryNoteInput({ onAddNote }: Readonly<HistoryNoteInputProps>) {
     const [note, setNote] = useState('');
     const [noteIsPrivate, setNoteIsPrivate] = useState(true);
 

+ 1 - 1
packages/dashboard/src/lib/components/shared/history-timeline/history-timeline.tsx

@@ -24,7 +24,7 @@ export function useHistoryTimeline() {
     return useContext(HistoryTimelineContext);
 }
 
-export function HistoryTimeline({ children, onEditNote, onDeleteNote }: HistoryTimelineProps) {
+export function HistoryTimeline({ children, onEditNote, onDeleteNote }: Readonly<HistoryTimelineProps>) {
     const [noteEditorOpen, setNoteEditorOpen] = useState(false);
     const [noteEditorNote, setNoteEditorNote] = useState<NoteEditorNote>({
         noteId: '',

+ 1 - 1
packages/dashboard/src/lib/components/shared/option-value-input.tsx

@@ -31,7 +31,7 @@ interface OptionValueInputProps {
     disabled?: boolean;
 }
 
-export function OptionValueInput({ groupIndex, disabled = false }: OptionValueInputProps) {
+export function OptionValueInput({ groupIndex, disabled = false }: Readonly<OptionValueInputProps>) {
     const { control, watch } = useFormContext<FormValues>();
     const { fields, append, remove } = useFieldArray({
         control,

+ 1 - 1
packages/dashboard/src/lib/components/shared/paginated-list-data-table.tsx

@@ -28,7 +28,7 @@ import {
     DropdownMenuTrigger,
 } from '@/vdb/components/ui/dropdown-menu.js';
 import { DisplayComponent } from '@/vdb/framework/component-registry/dynamic-component.js';
-import { BulkAction } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
 import { ResultOf } from '@/vdb/graphql/graphql.js';
 import { useExtendedListQuery } from '@/vdb/hooks/use-extended-list-query.js';
 import { Trans, useLingui } from '@/vdb/lib/trans.js';

+ 1 - 1
packages/dashboard/src/lib/components/shared/permission-guard.tsx

@@ -11,7 +11,7 @@ export interface PermissionGuardProps {
  * This component is used to protect a route from unauthorized access.
  * It will render the children if the user has the required permissions.
  */
-export function PermissionGuard({ requires, children }: PermissionGuardProps) {
+export function PermissionGuard({ requires, children }: Readonly<PermissionGuardProps>) {
     const { hasPermissions } = usePermissions();
     const permissions = Array.isArray(requires) ? requires : [requires];
     if (!hasPermissions(permissions)) {

+ 1 - 1
packages/dashboard/src/lib/components/shared/product-variant-selector.tsx

@@ -40,7 +40,7 @@ export interface ProductVariantSelectorProps {
     onProductVariantIdChange: (productVariantId: string) => void;
 }
 
-export function ProductVariantSelector({ onProductVariantIdChange }: ProductVariantSelectorProps) {
+export function ProductVariantSelector({ onProductVariantIdChange }: Readonly<ProductVariantSelectorProps>) {
     const [search, setSearch] = useState('');
     const [open, setOpen] = useState(false);
     const debouncedSearch = useDebounce(search, 500);

+ 1 - 1
packages/dashboard/src/lib/components/shared/role-code-label.tsx

@@ -1,7 +1,7 @@
 import { CUSTOMER_ROLE_CODE, SUPER_ADMIN_ROLE_CODE } from '@/vdb/constants.js';
 import { Trans } from '@/vdb/lib/trans.js';
 
-export function RoleCodeLabel({ code }: { code: string } | { code: undefined }) {
+export function RoleCodeLabel({ code }: Readonly<{ code: string }> | Readonly<{ code: undefined }>) {
     return code === SUPER_ADMIN_ROLE_CODE ? (
         <Trans>Super Admin</Trans>
     ) : code === CUSTOMER_ROLE_CODE ? (

+ 5 - 5
packages/dashboard/src/lib/components/shared/stock-level-label.tsx

@@ -5,20 +5,20 @@ export type StockLevel = {
     stockAllocated: number;
 };
 
-export function StockLevelLabel({ stockLevels }: { stockLevels: StockLevel[] }) {
+export function StockLevelLabel({ stockLevels }: Readonly<{ stockLevels: StockLevel[] }>) {
     const { i18n } = useLingui();
-    
+
     if (!Array.isArray(stockLevels)) {
         return null;
     }
     const totalOnHand = stockLevels.reduce((acc, curr) => acc + curr.stockOnHand, 0);
     const totalAllocated = stockLevels.reduce((acc, curr) => acc + curr.stockAllocated, 0);
-    
+
     return (
-        <span 
+        <span
             title={`${i18n.t('Stock on hand')}: ${totalOnHand}, ${i18n.t('Stock allocated')}: ${totalAllocated}`}
         >
             {totalOnHand} <span className="text-muted-foreground">/ {totalAllocated}</span>
         </span>
     );
-}
+}

+ 1 - 1
packages/dashboard/src/lib/components/shared/tax-category-selector.tsx

@@ -29,7 +29,7 @@ export interface TaxCategorySelectorProps {
     onChange: (value: string) => void;
 }
 
-export function TaxCategorySelector({ value, onChange }: TaxCategorySelectorProps) {
+export function TaxCategorySelector({ value, onChange }: Readonly<TaxCategorySelectorProps>) {
     const { data, isLoading, isPending, status } = useQuery({
         queryKey: ['taxCategories'],
         staleTime: 1000 * 60 * 5,

+ 1 - 1
packages/dashboard/src/lib/components/shared/zone-selector.tsx

@@ -28,7 +28,7 @@ export interface ZoneSelectorProps {
     onChange: (value: string) => void;
 }
 
-export function ZoneSelector({ value, onChange }: ZoneSelectorProps) {
+export function ZoneSelector({ value, onChange }: Readonly<ZoneSelectorProps>) {
     const { data, isLoading, isPending } = useQuery({
         queryKey: ['zones'],
         staleTime: 1000 * 60 * 5,

+ 2 - 3
packages/dashboard/src/lib/framework/alert/alert-extensions.tsx

@@ -1,7 +1,6 @@
-import { useEffect } from 'react';
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
+import { DashboardAlertDefinition } from '../extension-api/types/alerts.js';
 import { globalRegistry } from '../registry/global-registry.js';
-import { DashboardAlertDefinition } from './types.js';
 
 globalRegistry.register('dashboardAlertRegistry', new Map<string, DashboardAlertDefinition>());
 

+ 2 - 1
packages/dashboard/src/lib/framework/alert/alert-item.tsx

@@ -2,7 +2,8 @@ import { Button } from '@/vdb/components/ui/button.js';
 import { cn } from '@/vdb/lib/utils.js';
 import { useQuery } from '@tanstack/react-query';
 import { ComponentProps } from 'react';
-import { DashboardAlertDefinition } from './types.js';
+
+import { DashboardAlertDefinition } from '../extension-api/types/alerts.js';
 
 interface AlertItemProps extends ComponentProps<'div'> {
     alert: DashboardAlertDefinition;

+ 0 - 13
packages/dashboard/src/lib/framework/alert/types.ts

@@ -1,13 +0,0 @@
-export interface DashboardAlertDefinition<TResponse = any> {
-    id: string;
-    title: string | ((data: TResponse) => string);
-    description?: string | ((data: TResponse) => string);
-    severity: 'info' | 'warning' | 'error';
-    check: () => Promise<TResponse> | TResponse;
-    recheckInterval?: number;
-    shouldShow?: (data: TResponse) => boolean;
-    actions?: Array<{
-        label: string;
-        onClick: (data: TResponse) => void;
-    }>;
-}

+ 2 - 10
packages/dashboard/src/lib/framework/dashboard-widget/base-widget.tsx

@@ -1,8 +1,8 @@
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/vdb/components/ui/card.js';
+import { DashboardBaseWidgetProps } from '@/vdb/framework/extension-api/types/index.js';
 import { Trans } from '@/vdb/lib/trans.js';
 import { cn } from '@/vdb/lib/utils.js';
-import type React from 'react';
-import { createContext, PropsWithChildren, useContext, useEffect, useRef, useState } from 'react';
+import { createContext, useContext, useEffect, useRef, useState } from 'react';
 
 type WidgetDimensions = {
     width: number;
@@ -19,14 +19,6 @@ export const useWidgetDimensions = () => {
     return context;
 };
 
-export type DashboardBaseWidgetProps = PropsWithChildren<{
-    id: string;
-    title?: string;
-    description?: string;
-    config?: Record<string, unknown>;
-    actions?: React.ReactNode;
-}>;
-
 export function DashboardBaseWidget({
     id,
     config,

+ 0 - 22
packages/dashboard/src/lib/framework/dashboard-widget/types.ts

@@ -1,22 +0,0 @@
-import { DashboardBaseWidgetProps } from './base-widget.js';
-
-export type DashboardWidgetInstance = {
-    id: string;
-    widgetId: string;
-    layout: {
-        x: number;
-        y: number;
-        w: number;
-        h: number;
-    };
-    config?: Record<string, unknown>;
-};
-
-export type DashboardWidgetDefinition = {
-    id: string;
-    name: string;
-    component: React.ComponentType<DashboardBaseWidgetProps>;
-    defaultSize: { w: number; h: number; x?: number; y?: number };
-    minSize?: { w: number; h: number };
-    maxSize?: { w: number; h: number };
-};

+ 1 - 1
packages/dashboard/src/lib/framework/dashboard-widget/widget-extensions.tsx

@@ -1,4 +1,4 @@
-import { DashboardWidgetDefinition } from './types.js';
+import { DashboardWidgetDefinition } from '@/vdb/framework/extension-api/types/index.js';
 import { globalRegistry } from '../registry/global-registry.js';
 
 globalRegistry.register('dashboardWidgetRegistry', new Map<string, DashboardWidgetDefinition>());

+ 1 - 1
packages/dashboard/src/lib/framework/data-table/data-table-extensions.ts

@@ -1,4 +1,4 @@
-import { BulkAction } from '@/vdb/framework/data-table/data-table-types.js';
+import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
 import { DocumentNode } from 'graphql';
 
 import { globalRegistry } from '../registry/global-registry.js';

Some files were not shown because too many files changed in this diff