@open-mercato/documents 0.6.8-develop.7029.1.a1bb3363af → 0.6.8-develop.7031.1.005201cd70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. package/dist/modules/documents/backend/documents/DocumentsPageClient.js +1 -0
  2. package/dist/modules/documents/backend/documents/DocumentsPageClient.js.map +2 -2
  3. package/dist/modules/documents/backend/documents/DocumentsTable.js +1 -0
  4. package/dist/modules/documents/backend/documents/DocumentsTable.js.map +2 -2
  5. package/dist/modules/documents/backend/documents/templates/TemplatesPageClient.js +1 -0
  6. package/dist/modules/documents/backend/documents/templates/TemplatesPageClient.js.map +2 -2
  7. package/dist/modules/documents/backend/documents/templates/TemplatesTable.js +2 -1
  8. package/dist/modules/documents/backend/documents/templates/TemplatesTable.js.map +2 -2
  9. package/dist/modules/documents/backend/documents/templates/useTemplatesPage.js +7 -1
  10. package/dist/modules/documents/backend/documents/templates/useTemplatesPage.js.map +2 -2
  11. package/dist/modules/documents/backend/documents/useDocumentsList.js +6 -1
  12. package/dist/modules/documents/backend/documents/useDocumentsList.js.map +2 -2
  13. package/package.json +6 -6
  14. package/src/modules/documents/backend/documents/DocumentsPageClient.tsx +1 -0
  15. package/src/modules/documents/backend/documents/DocumentsTable.tsx +2 -0
  16. package/src/modules/documents/backend/documents/templates/TemplatesPageClient.tsx +1 -0
  17. package/src/modules/documents/backend/documents/templates/TemplatesTable.tsx +3 -1
  18. package/src/modules/documents/backend/documents/templates/useTemplatesPage.tsx +9 -1
  19. package/src/modules/documents/backend/documents/useDocumentsList.tsx +6 -2
@@ -83,6 +83,7 @@ function DocumentsPageClient() {
83
83
  pageSize: documents.pageSize,
84
84
  total: documents.total,
85
85
  totalPages: documents.totalPages,
86
+ totalIsCapped: documents.totalIsCapped,
86
87
  hasTemplates: documents.hasTemplates,
87
88
  canCreateDocument,
88
89
  canInstantiateTemplate,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/documents/backend/documents/DocumentsPageClient.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ShareDialog } from './components/ShareDialog'\nimport { DocumentsTable } from './DocumentsTable'\nimport { FolderDialog, type FolderDialogState } from './FolderDialog'\nimport { FolderTree } from './FolderTree'\nimport { MoveDocumentDialog } from './MoveDocumentDialog'\nimport type { DocumentRow } from './documentsListTypes'\nimport { useDocumentsList } from './useDocumentsList'\n\nfunction NewFromTemplateDialogLoading({ error, retry }: { error?: Error | null; retry?: () => void }) {\n const t = useT()\n // `next/dynamic` never forwards the caller's `onOpenChange` to a loading\n // shell, so own the dismissal here. Without it a chunk that fails for good\n // (a deploy invalidated it) traps the user in a modal Escape cannot close.\n const [open, setOpen] = React.useState(true)\n if (!open) return null\n return (\n <Dialog open onOpenChange={(next) => { if (!next) setOpen(false) }}>\n <DialogContent size=\"xl\" dismissible={Boolean(error)}>\n <DialogHeader>\n <DialogTitle>{t('documents.templates.instantiate.title')}</DialogTitle>\n <DialogDescription>{t('documents.templates.instantiate.description')}</DialogDescription>\n </DialogHeader>\n {error ? (\n <ErrorMessage\n label={t('documents.templates.instantiate.error.load')}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={retry}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <div role=\"status\" aria-live=\"polite\"><LoadingMessage label={t('documents.templates.instantiate.loading')} /></div>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n\nconst NewFromTemplateDialog = dynamic(\n () => import('./components/NewFromTemplateDialog').then((module) => module.NewFromTemplateDialog),\n { ssr: false, loading: NewFromTemplateDialogLoading },\n)\n\nexport function DocumentsPageClient() {\n const t = useT()\n const documents = useDocumentsList()\n const [shareDocument, setShareDocument] = React.useState<DocumentRow | null>(null)\n const [templateDialogOpen, setTemplateDialogOpen] = React.useState(false)\n const [folderDialog, setFolderDialog] = React.useState<FolderDialogState | null>(null)\n const [moveDocument, setMoveDocument] = React.useState<DocumentRow | null>(null)\n const selectedFolder = documents.selectedFolderId\n ? documents.folders.find((folder) => folder.id === documents.selectedFolderId) ?? null\n : null\n const destinationWritable = documents.selectedFolderId === null || selectedFolder?.canEdit === true\n const canCreateDocument = documents.collectionCapabilities.canCreateDocument && destinationWritable\n const canInstantiateTemplate = documents.collectionCapabilities.canInstantiateTemplate && destinationWritable\n\n return (\n <Page>\n <PageBody>\n {documents.loadError ? (\n <ErrorMessage\n label={documents.loadError}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={documents.refresh}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <div className=\"grid gap-4 lg:grid-cols-4\">\n <FolderTree\n folders={documents.folders}\n selectedFolderId={documents.selectedFolderId}\n onSelect={(folderId) => { documents.setSelectedFolderId(folderId); documents.setPage(1) }}\n onCreate={(parentFolderId) => setFolderDialog({ mode: 'create', parentFolderId })}\n onRename={(folder) => setFolderDialog({ mode: 'rename', folder })}\n onDelete={(folder) => void documents.deleteFolder(folder)}\n canCreateFolder={documents.collectionCapabilities.canCreateFolder}\n />\n <div className=\"min-w-0 lg:col-span-3\">\n <DocumentsTable\n title={selectedFolder?.name ?? t('documents.list.title')}\n rows={documents.rows}\n isLoading={documents.isLoading}\n isCreating={documents.isCreating}\n search={documents.search}\n page={documents.page}\n pageSize={documents.pageSize}\n total={documents.total}\n totalPages={documents.totalPages}\n hasTemplates={documents.hasTemplates}\n canCreateDocument={canCreateDocument}\n canInstantiateTemplate={canInstantiateTemplate}\n canManageTemplates={documents.collectionCapabilities.canManageTemplates}\n onSearchChange={(search) => { documents.setSearch(search); documents.setPage(1) }}\n onPageChange={documents.setPage}\n onPageSizeChange={(pageSize) => { documents.setPageSize(pageSize); documents.setPage(1) }}\n onRefresh={documents.refresh}\n onCreate={() => void documents.createDocument()}\n onNewFromTemplate={() => setTemplateDialogOpen(true)}\n onShare={setShareDocument}\n onMove={setMoveDocument}\n onDelete={(row) => void documents.deleteDocument(row)}\n archivedFilter={documents.archivedFilter}\n favoritesOnly={documents.favoritesOnly}\n onArchivedFilterChange={documents.setArchivedFilter}\n onFavoritesOnlyChange={documents.setFavoritesOnly}\n onToggleFavorite={(row) => void documents.toggleFavorite(row)}\n onDuplicate={(row) => void documents.duplicateDocument(row)}\n onArchiveToggle={(row) => void documents.archiveToggle(row)}\n />\n </div>\n </div>\n )}\n <FolderDialog\n state={folderDialog}\n onOpenChange={(open) => { if (!open) setFolderDialog(null) }}\n onSubmit={(name) => {\n if (!folderDialog) return false\n return documents.saveFolder(folderDialog.mode === 'rename'\n ? { folder: folderDialog.folder, name }\n : { parentFolderId: folderDialog.parentFolderId, name })\n }}\n />\n {shareDocument ? (\n <ShareDialog\n documentId={shareDocument.id}\n open\n onOpenChange={(open) => { if (!open) setShareDocument(null) }}\n canManage={shareDocument.capabilities.canShare}\n />\n ) : null}\n <MoveDocumentDialog\n document={moveDocument}\n folders={documents.folders}\n open={moveDocument !== null}\n onOpenChange={(open) => { if (!open) setMoveDocument(null) }}\n onMove={documents.moveDocument}\n />\n {canInstantiateTemplate && templateDialogOpen ? <NewFromTemplateDialog open folderId={documents.selectedFolderId} onOpenChange={setTemplateDialogOpen} /> : null}\n {documents.ConfirmDialogElement}\n </PageBody>\n </Page>\n )\n}\n\nexport default DocumentsPageClient\n"],
5
- "mappings": ";AA2BQ,SACE,KADF;AAzBR,YAAY,WAAW;AACvB,OAAO,aAAa;AACpB,SAAS,MAAM,gBAAgB;AAC/B,SAAS,cAAc,sBAAsB;AAC7C,SAAS,cAAc;AACvB,SAAS,QAAQ,eAAe,mBAAmB,cAAc,mBAAmB;AACpF,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,oBAA4C;AACrD,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;AAEnC,SAAS,wBAAwB;AAEjC,SAAS,6BAA6B,EAAE,OAAO,MAAM,GAAiD;AACpG,QAAM,IAAI,KAAK;AAIf,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,IAAI;AAC3C,MAAI,CAAC,KAAM,QAAO;AAClB,SACE,oBAAC,UAAO,MAAI,MAAC,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,SAAQ,KAAK;AAAA,EAAE,GAC/D,+BAAC,iBAAc,MAAK,MAAK,aAAa,QAAQ,KAAK,GACjD;AAAA,yBAAC,gBACC;AAAA,0BAAC,eAAa,YAAE,uCAAuC,GAAE;AAAA,MACzD,oBAAC,qBAAmB,YAAE,6CAA6C,GAAE;AAAA,OACvE;AAAA,IACC,QACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,4CAA4C;AAAA,QACrD,QAAQ,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,WAAU,SAAS,OAAQ,YAAE,yBAAyB,GAAE;AAAA;AAAA,IAC1G,IAEA,oBAAC,SAAI,MAAK,UAAS,aAAU,UAAS,8BAAC,kBAAe,OAAO,EAAE,yCAAyC,GAAG,GAAE;AAAA,KAEjH,GACF;AAEJ;AAEA,MAAM,wBAAwB;AAAA,EAC5B,MAAM,OAAO,oCAAoC,EAAE,KAAK,CAAC,WAAW,OAAO,qBAAqB;AAAA,EAChG,EAAE,KAAK,OAAO,SAAS,6BAA6B;AACtD;AAEO,SAAS,sBAAsB;AACpC,QAAM,IAAI,KAAK;AACf,QAAM,YAAY,iBAAiB;AACnC,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAA6B,IAAI;AACjF,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAS,KAAK;AACxE,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAmC,IAAI;AACrF,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAA6B,IAAI;AAC/E,QAAM,iBAAiB,UAAU,mBAC7B,UAAU,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,UAAU,gBAAgB,KAAK,OAChF;AACJ,QAAM,sBAAsB,UAAU,qBAAqB,QAAQ,gBAAgB,YAAY;AAC/F,QAAM,oBAAoB,UAAU,uBAAuB,qBAAqB;AAChF,QAAM,yBAAyB,UAAU,uBAAuB,0BAA0B;AAE1F,SACE,oBAAC,QACC,+BAAC,YACE;AAAA,cAAU,YACT;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,UAAU;AAAA,QACjB,QAAQ,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,WAAU,SAAS,UAAU,SAAU,YAAE,yBAAyB,GAAE;AAAA;AAAA,IACtH,IAEA,qBAAC,SAAI,WAAU,6BACf;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,UAAU;AAAA,UACnB,kBAAkB,UAAU;AAAA,UAC5B,UAAU,CAAC,aAAa;AAAE,sBAAU,oBAAoB,QAAQ;AAAG,sBAAU,QAAQ,CAAC;AAAA,UAAE;AAAA,UACxF,UAAU,CAAC,mBAAmB,gBAAgB,EAAE,MAAM,UAAU,eAAe,CAAC;AAAA,UAChF,UAAU,CAAC,WAAW,gBAAgB,EAAE,MAAM,UAAU,OAAO,CAAC;AAAA,UAChE,UAAU,CAAC,WAAW,KAAK,UAAU,aAAa,MAAM;AAAA,UACxD,iBAAiB,UAAU,uBAAuB;AAAA;AAAA,MACpD;AAAA,MACA,oBAAC,SAAI,WAAU,yBACb;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,gBAAgB,QAAQ,EAAE,sBAAsB;AAAA,UACvD,MAAM,UAAU;AAAA,UAChB,WAAW,UAAU;AAAA,UACrB,YAAY,UAAU;AAAA,UACtB,QAAQ,UAAU;AAAA,UAClB,MAAM,UAAU;AAAA,UAChB,UAAU,UAAU;AAAA,UACpB,OAAO,UAAU;AAAA,UACjB,YAAY,UAAU;AAAA,UACtB,cAAc,UAAU;AAAA,UACxB;AAAA,UACA;AAAA,UACA,oBAAoB,UAAU,uBAAuB;AAAA,UACrD,gBAAgB,CAAC,WAAW;AAAE,sBAAU,UAAU,MAAM;AAAG,sBAAU,QAAQ,CAAC;AAAA,UAAE;AAAA,UAChF,cAAc,UAAU;AAAA,UACxB,kBAAkB,CAAC,aAAa;AAAE,sBAAU,YAAY,QAAQ;AAAG,sBAAU,QAAQ,CAAC;AAAA,UAAE;AAAA,UACxF,WAAW,UAAU;AAAA,UACrB,UAAU,MAAM,KAAK,UAAU,eAAe;AAAA,UAC9C,mBAAmB,MAAM,sBAAsB,IAAI;AAAA,UACnD,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,UAAU,CAAC,QAAQ,KAAK,UAAU,eAAe,GAAG;AAAA,UACpD,gBAAgB,UAAU;AAAA,UAC1B,eAAe,UAAU;AAAA,UACzB,wBAAwB,UAAU;AAAA,UAClC,uBAAuB,UAAU;AAAA,UACjC,kBAAkB,CAAC,QAAQ,KAAK,UAAU,eAAe,GAAG;AAAA,UAC5D,aAAa,CAAC,QAAQ,KAAK,UAAU,kBAAkB,GAAG;AAAA,UAC1D,iBAAiB,CAAC,QAAQ,KAAK,UAAU,cAAc,GAAG;AAAA;AAAA,MAC5D,GACF;AAAA,OACA;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,cAAc,CAAC,SAAS;AAAE,cAAI,CAAC,KAAM,iBAAgB,IAAI;AAAA,QAAE;AAAA,QAC3D,UAAU,CAAC,SAAS;AAClB,cAAI,CAAC,aAAc,QAAO;AAC1B,iBAAO,UAAU,WAAW,aAAa,SAAS,WAC9C,EAAE,QAAQ,aAAa,QAAQ,KAAK,IACpC,EAAE,gBAAgB,aAAa,gBAAgB,KAAK,CAAC;AAAA,QAC3D;AAAA;AAAA,IACF;AAAA,IACC,gBACC;AAAA,MAAC;AAAA;AAAA,QACC,YAAY,cAAc;AAAA,QAC1B,MAAI;AAAA,QACJ,cAAc,CAAC,SAAS;AAAE,cAAI,CAAC,KAAM,kBAAiB,IAAI;AAAA,QAAE;AAAA,QAC5D,WAAW,cAAc,aAAa;AAAA;AAAA,IACxC,IACE;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,SAAS,UAAU;AAAA,QACnB,MAAM,iBAAiB;AAAA,QACvB,cAAc,CAAC,SAAS;AAAE,cAAI,CAAC,KAAM,iBAAgB,IAAI;AAAA,QAAE;AAAA,QAC3D,QAAQ,UAAU;AAAA;AAAA,IACpB;AAAA,IACC,0BAA0B,qBAAqB,oBAAC,yBAAsB,MAAI,MAAC,UAAU,UAAU,kBAAkB,cAAc,uBAAuB,IAAK;AAAA,IAC3J,UAAU;AAAA,KACb,GACF;AAEJ;AAEA,IAAO,8BAAQ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ShareDialog } from './components/ShareDialog'\nimport { DocumentsTable } from './DocumentsTable'\nimport { FolderDialog, type FolderDialogState } from './FolderDialog'\nimport { FolderTree } from './FolderTree'\nimport { MoveDocumentDialog } from './MoveDocumentDialog'\nimport type { DocumentRow } from './documentsListTypes'\nimport { useDocumentsList } from './useDocumentsList'\n\nfunction NewFromTemplateDialogLoading({ error, retry }: { error?: Error | null; retry?: () => void }) {\n const t = useT()\n // `next/dynamic` never forwards the caller's `onOpenChange` to a loading\n // shell, so own the dismissal here. Without it a chunk that fails for good\n // (a deploy invalidated it) traps the user in a modal Escape cannot close.\n const [open, setOpen] = React.useState(true)\n if (!open) return null\n return (\n <Dialog open onOpenChange={(next) => { if (!next) setOpen(false) }}>\n <DialogContent size=\"xl\" dismissible={Boolean(error)}>\n <DialogHeader>\n <DialogTitle>{t('documents.templates.instantiate.title')}</DialogTitle>\n <DialogDescription>{t('documents.templates.instantiate.description')}</DialogDescription>\n </DialogHeader>\n {error ? (\n <ErrorMessage\n label={t('documents.templates.instantiate.error.load')}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={retry}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <div role=\"status\" aria-live=\"polite\"><LoadingMessage label={t('documents.templates.instantiate.loading')} /></div>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n\nconst NewFromTemplateDialog = dynamic(\n () => import('./components/NewFromTemplateDialog').then((module) => module.NewFromTemplateDialog),\n { ssr: false, loading: NewFromTemplateDialogLoading },\n)\n\nexport function DocumentsPageClient() {\n const t = useT()\n const documents = useDocumentsList()\n const [shareDocument, setShareDocument] = React.useState<DocumentRow | null>(null)\n const [templateDialogOpen, setTemplateDialogOpen] = React.useState(false)\n const [folderDialog, setFolderDialog] = React.useState<FolderDialogState | null>(null)\n const [moveDocument, setMoveDocument] = React.useState<DocumentRow | null>(null)\n const selectedFolder = documents.selectedFolderId\n ? documents.folders.find((folder) => folder.id === documents.selectedFolderId) ?? null\n : null\n const destinationWritable = documents.selectedFolderId === null || selectedFolder?.canEdit === true\n const canCreateDocument = documents.collectionCapabilities.canCreateDocument && destinationWritable\n const canInstantiateTemplate = documents.collectionCapabilities.canInstantiateTemplate && destinationWritable\n\n return (\n <Page>\n <PageBody>\n {documents.loadError ? (\n <ErrorMessage\n label={documents.loadError}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={documents.refresh}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <div className=\"grid gap-4 lg:grid-cols-4\">\n <FolderTree\n folders={documents.folders}\n selectedFolderId={documents.selectedFolderId}\n onSelect={(folderId) => { documents.setSelectedFolderId(folderId); documents.setPage(1) }}\n onCreate={(parentFolderId) => setFolderDialog({ mode: 'create', parentFolderId })}\n onRename={(folder) => setFolderDialog({ mode: 'rename', folder })}\n onDelete={(folder) => void documents.deleteFolder(folder)}\n canCreateFolder={documents.collectionCapabilities.canCreateFolder}\n />\n <div className=\"min-w-0 lg:col-span-3\">\n <DocumentsTable\n title={selectedFolder?.name ?? t('documents.list.title')}\n rows={documents.rows}\n isLoading={documents.isLoading}\n isCreating={documents.isCreating}\n search={documents.search}\n page={documents.page}\n pageSize={documents.pageSize}\n total={documents.total}\n totalPages={documents.totalPages}\n totalIsCapped={documents.totalIsCapped}\n hasTemplates={documents.hasTemplates}\n canCreateDocument={canCreateDocument}\n canInstantiateTemplate={canInstantiateTemplate}\n canManageTemplates={documents.collectionCapabilities.canManageTemplates}\n onSearchChange={(search) => { documents.setSearch(search); documents.setPage(1) }}\n onPageChange={documents.setPage}\n onPageSizeChange={(pageSize) => { documents.setPageSize(pageSize); documents.setPage(1) }}\n onRefresh={documents.refresh}\n onCreate={() => void documents.createDocument()}\n onNewFromTemplate={() => setTemplateDialogOpen(true)}\n onShare={setShareDocument}\n onMove={setMoveDocument}\n onDelete={(row) => void documents.deleteDocument(row)}\n archivedFilter={documents.archivedFilter}\n favoritesOnly={documents.favoritesOnly}\n onArchivedFilterChange={documents.setArchivedFilter}\n onFavoritesOnlyChange={documents.setFavoritesOnly}\n onToggleFavorite={(row) => void documents.toggleFavorite(row)}\n onDuplicate={(row) => void documents.duplicateDocument(row)}\n onArchiveToggle={(row) => void documents.archiveToggle(row)}\n />\n </div>\n </div>\n )}\n <FolderDialog\n state={folderDialog}\n onOpenChange={(open) => { if (!open) setFolderDialog(null) }}\n onSubmit={(name) => {\n if (!folderDialog) return false\n return documents.saveFolder(folderDialog.mode === 'rename'\n ? { folder: folderDialog.folder, name }\n : { parentFolderId: folderDialog.parentFolderId, name })\n }}\n />\n {shareDocument ? (\n <ShareDialog\n documentId={shareDocument.id}\n open\n onOpenChange={(open) => { if (!open) setShareDocument(null) }}\n canManage={shareDocument.capabilities.canShare}\n />\n ) : null}\n <MoveDocumentDialog\n document={moveDocument}\n folders={documents.folders}\n open={moveDocument !== null}\n onOpenChange={(open) => { if (!open) setMoveDocument(null) }}\n onMove={documents.moveDocument}\n />\n {canInstantiateTemplate && templateDialogOpen ? <NewFromTemplateDialog open folderId={documents.selectedFolderId} onOpenChange={setTemplateDialogOpen} /> : null}\n {documents.ConfirmDialogElement}\n </PageBody>\n </Page>\n )\n}\n\nexport default DocumentsPageClient\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -116,6 +116,7 @@ function DocumentsTable(props) {
116
116
  pageSize: props.pageSize,
117
117
  total: props.total,
118
118
  totalPages: props.totalPages,
119
+ totalIsCapped: props.totalIsCapped,
119
120
  onPageChange: props.onPageChange,
120
121
  onPageSizeChange: props.onPageSizeChange
121
122
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/documents/backend/documents/DocumentsTable.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Star } from 'lucide-react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { RowActionItem } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { LinkButton } from '@open-mercato/ui/primitives/link-button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DOCUMENTS_ENTITY_IDS } from '../../lib/constants'\nimport { formatDateTime } from './documentUi'\nimport type { DocumentRow } from './documentsListTypes'\n\nexport type DocumentsArchivedFilter = 'exclude' | 'include' | 'only'\n\ntype DocumentsTableProps = {\n title: string\n rows: DocumentRow[]\n isLoading: boolean\n isCreating: boolean\n search: string\n page: number\n pageSize: number\n total: number\n totalPages: number\n hasTemplates: boolean\n canCreateDocument: boolean\n canInstantiateTemplate: boolean\n canManageTemplates: boolean\n onSearchChange: (search: string) => void\n onPageChange: (page: number) => void\n onPageSizeChange: (pageSize: number) => void\n onRefresh: () => void\n onCreate: () => void\n onNewFromTemplate: () => void\n onShare: (row: DocumentRow) => void\n onMove: (row: DocumentRow) => void\n onDelete: (row: DocumentRow) => void\n archivedFilter: DocumentsArchivedFilter\n favoritesOnly: boolean\n onArchivedFilterChange: (value: DocumentsArchivedFilter) => void\n onFavoritesOnlyChange: (value: boolean) => void\n onToggleFavorite: (row: DocumentRow) => void\n onDuplicate: (row: DocumentRow) => void\n onArchiveToggle: (row: DocumentRow) => void\n}\n\nexport function DocumentsTable(props: DocumentsTableProps) {\n const t = useT()\n const router = useRouter()\n const columns = React.useMemo<ColumnDef<DocumentRow>[]>(() => [\n {\n id: 'favorite', header: '', meta: { alwaysVisible: true, maxWidth: '48px' },\n cell: ({ row }) => (\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n aria-pressed={row.original.isFavorite}\n aria-label={t(row.original.isFavorite ? 'documents.actions.unfavorite' : 'documents.actions.favorite')}\n onClick={(event) => {\n event.stopPropagation()\n props.onToggleFavorite(row.original)\n }}\n >\n <Star className={row.original.isFavorite ? 'fill-current text-status-warning-icon' : 'text-muted-foreground'} />\n </IconButton>\n ),\n },\n {\n accessorKey: 'title', header: t('documents.columns.title'), meta: { alwaysVisible: true, maxWidth: '260px', truncate: true },\n cell: ({ row }) => (\n <span className=\"flex items-center gap-2\">\n <Link href={`/backend/documents/${row.original.id}`} className=\"font-medium hover:underline\">{row.original.title}</Link>\n {row.original.archivedAt ? <Badge variant=\"outline\">{t('documents.list.archivedBadge')}</Badge> : null}\n </span>\n ),\n },\n {\n accessorKey: 'folderName', header: t('documents.columns.folder'), meta: { maxWidth: '180px', truncate: true },\n cell: ({ row }) => row.original.folderName ?? <span className=\"text-sm text-muted-foreground\">{t('documents.folders.none')}</span>,\n },\n { accessorKey: 'ownerLabel', header: t('documents.columns.owner'), meta: { maxWidth: '220px', truncate: true } },\n { accessorKey: 'sharedWithCount', header: t('documents.columns.sharedWith') },\n {\n accessorKey: 'updatedAt', header: t('documents.columns.updatedAt'), meta: { maxWidth: '180px' },\n cell: ({ row }) => <span className=\"text-sm\">{formatDateTime(row.original.updatedAt, t('documents.list.noValue'))}</span>,\n },\n ], [t, props.onToggleFavorite])\n // A fragment, not a nested flex box: the DataTable header owns the wrapping\n // row, so on narrow layouts the refresh control and these buttons wrap as\n // one group instead of a lone refresh icon above a second left-aligned row.\n const actions = (\n <>\n <Button\n type=\"button\"\n variant={props.favoritesOnly ? 'secondary' : 'outline'}\n aria-pressed={props.favoritesOnly}\n onClick={() => props.onFavoritesOnlyChange(!props.favoritesOnly)}\n >\n <Star />{t('documents.list.filters.favorites')}\n </Button>\n <Select value={props.archivedFilter} onValueChange={(value) => props.onArchivedFilterChange(value as DocumentsArchivedFilter)}>\n <SelectTrigger className=\"w-36\" aria-label={t('documents.list.filters.archived.label')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"exclude\">{t('documents.list.filters.archived.active')}</SelectItem>\n <SelectItem value=\"include\">{t('documents.list.filters.archived.all')}</SelectItem>\n <SelectItem value=\"only\">{t('documents.list.filters.archived.archivedOnly')}</SelectItem>\n </SelectContent>\n </Select>\n {props.canManageTemplates ? <LinkButton asChild variant=\"gray\"><Link href=\"/backend/documents/templates\">{t('documents.templates.actions.manage')}</Link></LinkButton> : null}\n {props.hasTemplates && props.canInstantiateTemplate ? <Button type=\"button\" variant=\"outline\" onClick={props.onNewFromTemplate}>{t('documents.templates.instantiate.title')}</Button> : null}\n {props.canCreateDocument ? <Button type=\"button\" onClick={props.onCreate} disabled={props.isCreating}>{t('documents.actions.create')}</Button> : null}\n </>\n )\n return (\n <DataTable<DocumentRow>\n title={props.title}\n actions={actions}\n refreshButton={{ label: t('documents.actions.refresh'), onRefresh: props.onRefresh, isRefreshing: props.isLoading }}\n columns={columns}\n data={props.rows}\n isLoading={props.isLoading}\n searchValue={props.search}\n onSearchChange={props.onSearchChange}\n searchPlaceholder={t('documents.list.searchPlaceholder')}\n emptyState={t('documents.list.empty')}\n entityId={DOCUMENTS_ENTITY_IDS.document}\n extensionTableId=\"documents.documents.list\"\n onRowClick={(row) => router.push(`/backend/documents/${row.id}`)}\n rowClickActionIds={['open']}\n stickyActionsColumn\n pagination={{\n page: props.page, pageSize: props.pageSize, total: props.total, totalPages: props.totalPages,\n onPageChange: props.onPageChange, onPageSizeChange: props.onPageSizeChange,\n }}\n rowActions={(row) => {\n const items: RowActionItem[] = [{ id: 'open', label: t('documents.actions.open'), onSelect: () => router.push(`/backend/documents/${row.id}`) }]\n if (row.capabilities.canShare) items.push({ id: 'share', label: t('documents.actions.share'), onSelect: () => props.onShare(row) })\n if (row.capabilities.canEdit) items.push({ id: 'move', label: t('documents.folders.actions.moveDocument'), onSelect: () => props.onMove(row) })\n if (row.capabilities.canDuplicate) items.push({ id: 'duplicate', label: t('documents.actions.duplicate'), onSelect: () => props.onDuplicate(row) })\n if (row.capabilities.canArchive) {\n items.push({\n id: row.archivedAt ? 'unarchive' : 'archive',\n label: t(row.archivedAt ? 'documents.actions.unarchive' : 'documents.actions.archive'),\n onSelect: () => props.onArchiveToggle(row),\n })\n }\n if (row.capabilities.canDelete) items.push({ id: 'delete', label: t('documents.actions.delete'), destructive: true, onSelect: () => props.onDelete(row) })\n return <RowActions items={items} />\n }}\n />\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Star } from 'lucide-react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { RowActionItem } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { LinkButton } from '@open-mercato/ui/primitives/link-button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DOCUMENTS_ENTITY_IDS } from '../../lib/constants'\nimport { formatDateTime } from './documentUi'\nimport type { DocumentRow } from './documentsListTypes'\n\nexport type DocumentsArchivedFilter = 'exclude' | 'include' | 'only'\n\ntype DocumentsTableProps = {\n title: string\n rows: DocumentRow[]\n isLoading: boolean\n isCreating: boolean\n search: string\n page: number\n pageSize: number\n total: number\n totalPages: number\n totalIsCapped: boolean\n hasTemplates: boolean\n canCreateDocument: boolean\n canInstantiateTemplate: boolean\n canManageTemplates: boolean\n onSearchChange: (search: string) => void\n onPageChange: (page: number) => void\n onPageSizeChange: (pageSize: number) => void\n onRefresh: () => void\n onCreate: () => void\n onNewFromTemplate: () => void\n onShare: (row: DocumentRow) => void\n onMove: (row: DocumentRow) => void\n onDelete: (row: DocumentRow) => void\n archivedFilter: DocumentsArchivedFilter\n favoritesOnly: boolean\n onArchivedFilterChange: (value: DocumentsArchivedFilter) => void\n onFavoritesOnlyChange: (value: boolean) => void\n onToggleFavorite: (row: DocumentRow) => void\n onDuplicate: (row: DocumentRow) => void\n onArchiveToggle: (row: DocumentRow) => void\n}\n\nexport function DocumentsTable(props: DocumentsTableProps) {\n const t = useT()\n const router = useRouter()\n const columns = React.useMemo<ColumnDef<DocumentRow>[]>(() => [\n {\n id: 'favorite', header: '', meta: { alwaysVisible: true, maxWidth: '48px' },\n cell: ({ row }) => (\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n aria-pressed={row.original.isFavorite}\n aria-label={t(row.original.isFavorite ? 'documents.actions.unfavorite' : 'documents.actions.favorite')}\n onClick={(event) => {\n event.stopPropagation()\n props.onToggleFavorite(row.original)\n }}\n >\n <Star className={row.original.isFavorite ? 'fill-current text-status-warning-icon' : 'text-muted-foreground'} />\n </IconButton>\n ),\n },\n {\n accessorKey: 'title', header: t('documents.columns.title'), meta: { alwaysVisible: true, maxWidth: '260px', truncate: true },\n cell: ({ row }) => (\n <span className=\"flex items-center gap-2\">\n <Link href={`/backend/documents/${row.original.id}`} className=\"font-medium hover:underline\">{row.original.title}</Link>\n {row.original.archivedAt ? <Badge variant=\"outline\">{t('documents.list.archivedBadge')}</Badge> : null}\n </span>\n ),\n },\n {\n accessorKey: 'folderName', header: t('documents.columns.folder'), meta: { maxWidth: '180px', truncate: true },\n cell: ({ row }) => row.original.folderName ?? <span className=\"text-sm text-muted-foreground\">{t('documents.folders.none')}</span>,\n },\n { accessorKey: 'ownerLabel', header: t('documents.columns.owner'), meta: { maxWidth: '220px', truncate: true } },\n { accessorKey: 'sharedWithCount', header: t('documents.columns.sharedWith') },\n {\n accessorKey: 'updatedAt', header: t('documents.columns.updatedAt'), meta: { maxWidth: '180px' },\n cell: ({ row }) => <span className=\"text-sm\">{formatDateTime(row.original.updatedAt, t('documents.list.noValue'))}</span>,\n },\n ], [t, props.onToggleFavorite])\n // A fragment, not a nested flex box: the DataTable header owns the wrapping\n // row, so on narrow layouts the refresh control and these buttons wrap as\n // one group instead of a lone refresh icon above a second left-aligned row.\n const actions = (\n <>\n <Button\n type=\"button\"\n variant={props.favoritesOnly ? 'secondary' : 'outline'}\n aria-pressed={props.favoritesOnly}\n onClick={() => props.onFavoritesOnlyChange(!props.favoritesOnly)}\n >\n <Star />{t('documents.list.filters.favorites')}\n </Button>\n <Select value={props.archivedFilter} onValueChange={(value) => props.onArchivedFilterChange(value as DocumentsArchivedFilter)}>\n <SelectTrigger className=\"w-36\" aria-label={t('documents.list.filters.archived.label')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"exclude\">{t('documents.list.filters.archived.active')}</SelectItem>\n <SelectItem value=\"include\">{t('documents.list.filters.archived.all')}</SelectItem>\n <SelectItem value=\"only\">{t('documents.list.filters.archived.archivedOnly')}</SelectItem>\n </SelectContent>\n </Select>\n {props.canManageTemplates ? <LinkButton asChild variant=\"gray\"><Link href=\"/backend/documents/templates\">{t('documents.templates.actions.manage')}</Link></LinkButton> : null}\n {props.hasTemplates && props.canInstantiateTemplate ? <Button type=\"button\" variant=\"outline\" onClick={props.onNewFromTemplate}>{t('documents.templates.instantiate.title')}</Button> : null}\n {props.canCreateDocument ? <Button type=\"button\" onClick={props.onCreate} disabled={props.isCreating}>{t('documents.actions.create')}</Button> : null}\n </>\n )\n return (\n <DataTable<DocumentRow>\n title={props.title}\n actions={actions}\n refreshButton={{ label: t('documents.actions.refresh'), onRefresh: props.onRefresh, isRefreshing: props.isLoading }}\n columns={columns}\n data={props.rows}\n isLoading={props.isLoading}\n searchValue={props.search}\n onSearchChange={props.onSearchChange}\n searchPlaceholder={t('documents.list.searchPlaceholder')}\n emptyState={t('documents.list.empty')}\n entityId={DOCUMENTS_ENTITY_IDS.document}\n extensionTableId=\"documents.documents.list\"\n onRowClick={(row) => router.push(`/backend/documents/${row.id}`)}\n rowClickActionIds={['open']}\n stickyActionsColumn\n pagination={{\n page: props.page, pageSize: props.pageSize, total: props.total, totalPages: props.totalPages,\n totalIsCapped: props.totalIsCapped,\n onPageChange: props.onPageChange, onPageSizeChange: props.onPageSizeChange,\n }}\n rowActions={(row) => {\n const items: RowActionItem[] = [{ id: 'open', label: t('documents.actions.open'), onSelect: () => router.push(`/backend/documents/${row.id}`) }]\n if (row.capabilities.canShare) items.push({ id: 'share', label: t('documents.actions.share'), onSelect: () => props.onShare(row) })\n if (row.capabilities.canEdit) items.push({ id: 'move', label: t('documents.folders.actions.moveDocument'), onSelect: () => props.onMove(row) })\n if (row.capabilities.canDuplicate) items.push({ id: 'duplicate', label: t('documents.actions.duplicate'), onSelect: () => props.onDuplicate(row) })\n if (row.capabilities.canArchive) {\n items.push({\n id: row.archivedAt ? 'unarchive' : 'archive',\n label: t(row.archivedAt ? 'documents.actions.unarchive' : 'documents.actions.archive'),\n onSelect: () => props.onArchiveToggle(row),\n })\n }\n if (row.capabilities.canDelete) items.push({ id: 'delete', label: t('documents.actions.delete'), destructive: true, onSelect: () => props.onDelete(row) })\n return <RowActions items={items} />\n }}\n />\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -57,6 +57,7 @@ function TemplatesPageClient() {
57
57
  pageSize: templates.pageSize,
58
58
  total: templates.total,
59
59
  totalPages: templates.totalPages,
60
+ totalIsCapped: templates.totalIsCapped,
60
61
  search: templates.search,
61
62
  isLoading: templates.isLoading,
62
63
  canManageTemplates: templates.canManageTemplates,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/documents/backend/documents/templates/TemplatesPageClient.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TemplateRow } from '../components/templateUi'\nimport { TemplatesTable } from './TemplatesTable'\nimport { useTemplatesPage } from './useTemplatesPage'\n\nfunction TemplateEditorDialogLoading({ error, retry }: { error?: Error | null; retry?: () => void }) {\n const t = useT()\n // `next/dynamic` never forwards the caller's `onOpenChange` to a loading\n // shell, so own the dismissal here. Without it a chunk that fails for good\n // (a deploy invalidated it) traps the user in a modal Escape cannot close.\n const [open, setOpen] = React.useState(true)\n if (!open) return null\n return (\n <Dialog open onOpenChange={(next) => { if (!next) setOpen(false) }}>\n <DialogContent size=\"xl\" dismissible={Boolean(error)}>\n <DialogHeader>\n <DialogTitle>{t('documents.templates.actions.manage')}</DialogTitle>\n <DialogDescription>{t('documents.templates.preview.loading')}</DialogDescription>\n </DialogHeader>\n {error ? (\n <ErrorMessage\n label={t('documents.templates.error.load')}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={retry}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <div role=\"status\" aria-live=\"polite\"><LoadingMessage label={t('documents.templates.preview.loading')} /></div>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n\nconst TemplateEditorDialog = dynamic(\n () => import('../components/TemplateEditorDialog').then((module) => module.TemplateEditorDialog),\n { ssr: false, loading: TemplateEditorDialogLoading },\n)\n\nexport function TemplatesPageClient() {\n const t = useT()\n const templates = useTemplatesPage()\n const [editing, setEditing] = React.useState<TemplateRow | null>(null)\n const [editorOpen, setEditorOpen] = React.useState(false)\n const openEditor = React.useCallback((template: TemplateRow | null) => {\n setEditing(template)\n setEditorOpen(true)\n }, [])\n return (\n <Page>\n <PageBody>\n {templates.loadError ? (\n <ErrorMessage\n label={templates.loadError}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={templates.refresh}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <TemplatesTable\n rows={templates.rows}\n page={templates.page}\n pageSize={templates.pageSize}\n total={templates.total}\n totalPages={templates.totalPages}\n search={templates.search}\n isLoading={templates.isLoading}\n canManageTemplates={templates.canManageTemplates}\n onSearchChange={templates.setSearch}\n onPageChange={templates.setPage}\n onPageSizeChange={templates.setPageSize}\n onRefresh={templates.refresh}\n onEdit={openEditor}\n onDelete={(template) => void templates.deleteTemplate(template)}\n />\n )}\n {templates.canManageTemplates && editorOpen ? <TemplateEditorDialog\n open\n template={editing}\n onOpenChange={(open) => { setEditorOpen(open); if (!open) setEditing(null) }}\n onSaved={templates.refreshFromFirstPage}\n /> : null}\n {templates.ConfirmDialogElement}\n </PageBody>\n </Page>\n )\n}\n\nexport default TemplatesPageClient\n"],
5
- "mappings": ";AAuBQ,SACE,KADF;AArBR,YAAY,WAAW;AACvB,OAAO,aAAa;AACpB,SAAS,MAAM,gBAAgB;AAC/B,SAAS,cAAc,sBAAsB;AAC7C,SAAS,cAAc;AACvB,SAAS,QAAQ,eAAe,mBAAmB,cAAc,mBAAmB;AACpF,SAAS,YAAY;AAErB,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAEjC,SAAS,4BAA4B,EAAE,OAAO,MAAM,GAAiD;AACnG,QAAM,IAAI,KAAK;AAIf,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,IAAI;AAC3C,MAAI,CAAC,KAAM,QAAO;AAClB,SACE,oBAAC,UAAO,MAAI,MAAC,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,SAAQ,KAAK;AAAA,EAAE,GAC/D,+BAAC,iBAAc,MAAK,MAAK,aAAa,QAAQ,KAAK,GACjD;AAAA,yBAAC,gBACC;AAAA,0BAAC,eAAa,YAAE,oCAAoC,GAAE;AAAA,MACtD,oBAAC,qBAAmB,YAAE,qCAAqC,GAAE;AAAA,OAC/D;AAAA,IACC,QACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,gCAAgC;AAAA,QACzC,QAAQ,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,WAAU,SAAS,OAAQ,YAAE,yBAAyB,GAAE;AAAA;AAAA,IAC1G,IAEA,oBAAC,SAAI,MAAK,UAAS,aAAU,UAAS,8BAAC,kBAAe,OAAO,EAAE,qCAAqC,GAAG,GAAE;AAAA,KAE7G,GACF;AAEJ;AAEA,MAAM,uBAAuB;AAAA,EAC3B,MAAM,OAAO,oCAAoC,EAAE,KAAK,CAAC,WAAW,OAAO,oBAAoB;AAAA,EAC/F,EAAE,KAAK,OAAO,SAAS,4BAA4B;AACrD;AAEO,SAAS,sBAAsB;AACpC,QAAM,IAAI,KAAK;AACf,QAAM,YAAY,iBAAiB;AACnC,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAA6B,IAAI;AACrE,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,aAAa,MAAM,YAAY,CAAC,aAAiC;AACrE,eAAW,QAAQ;AACnB,kBAAc,IAAI;AAAA,EACpB,GAAG,CAAC,CAAC;AACL,SACE,oBAAC,QACC,+BAAC,YACE;AAAA,cAAU,YACT;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,UAAU;AAAA,QACjB,QAAQ,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,WAAU,SAAS,UAAU,SAAU,YAAE,yBAAyB,GAAE;AAAA;AAAA,IACtH,IAEA;AAAA,MAAC;AAAA;AAAA,QACD,MAAM,UAAU;AAAA,QAChB,MAAM,UAAU;AAAA,QAChB,UAAU,UAAU;AAAA,QACpB,OAAO,UAAU;AAAA,QACjB,YAAY,UAAU;AAAA,QACtB,QAAQ,UAAU;AAAA,QAClB,WAAW,UAAU;AAAA,QACrB,oBAAoB,UAAU;AAAA,QAC9B,gBAAgB,UAAU;AAAA,QAC1B,cAAc,UAAU;AAAA,QACxB,kBAAkB,UAAU;AAAA,QAC5B,WAAW,UAAU;AAAA,QACrB,QAAQ;AAAA,QACR,UAAU,CAAC,aAAa,KAAK,UAAU,eAAe,QAAQ;AAAA;AAAA,IAC9D;AAAA,IAED,UAAU,sBAAsB,aAAa;AAAA,MAAC;AAAA;AAAA,QAC7C,MAAI;AAAA,QACJ,UAAU;AAAA,QACV,cAAc,CAAC,SAAS;AAAE,wBAAc,IAAI;AAAG,cAAI,CAAC,KAAM,YAAW,IAAI;AAAA,QAAE;AAAA,QAC3E,SAAS,UAAU;AAAA;AAAA,IACrB,IAAK;AAAA,IACJ,UAAU;AAAA,KACb,GACF;AAEJ;AAEA,IAAO,8BAAQ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TemplateRow } from '../components/templateUi'\nimport { TemplatesTable } from './TemplatesTable'\nimport { useTemplatesPage } from './useTemplatesPage'\n\nfunction TemplateEditorDialogLoading({ error, retry }: { error?: Error | null; retry?: () => void }) {\n const t = useT()\n // `next/dynamic` never forwards the caller's `onOpenChange` to a loading\n // shell, so own the dismissal here. Without it a chunk that fails for good\n // (a deploy invalidated it) traps the user in a modal Escape cannot close.\n const [open, setOpen] = React.useState(true)\n if (!open) return null\n return (\n <Dialog open onOpenChange={(next) => { if (!next) setOpen(false) }}>\n <DialogContent size=\"xl\" dismissible={Boolean(error)}>\n <DialogHeader>\n <DialogTitle>{t('documents.templates.actions.manage')}</DialogTitle>\n <DialogDescription>{t('documents.templates.preview.loading')}</DialogDescription>\n </DialogHeader>\n {error ? (\n <ErrorMessage\n label={t('documents.templates.error.load')}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={retry}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <div role=\"status\" aria-live=\"polite\"><LoadingMessage label={t('documents.templates.preview.loading')} /></div>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n\nconst TemplateEditorDialog = dynamic(\n () => import('../components/TemplateEditorDialog').then((module) => module.TemplateEditorDialog),\n { ssr: false, loading: TemplateEditorDialogLoading },\n)\n\nexport function TemplatesPageClient() {\n const t = useT()\n const templates = useTemplatesPage()\n const [editing, setEditing] = React.useState<TemplateRow | null>(null)\n const [editorOpen, setEditorOpen] = React.useState(false)\n const openEditor = React.useCallback((template: TemplateRow | null) => {\n setEditing(template)\n setEditorOpen(true)\n }, [])\n return (\n <Page>\n <PageBody>\n {templates.loadError ? (\n <ErrorMessage\n label={templates.loadError}\n action={<Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={templates.refresh}>{t('documents.actions.retry')}</Button>}\n />\n ) : (\n <TemplatesTable\n rows={templates.rows}\n page={templates.page}\n pageSize={templates.pageSize}\n total={templates.total}\n totalPages={templates.totalPages}\n totalIsCapped={templates.totalIsCapped}\n search={templates.search}\n isLoading={templates.isLoading}\n canManageTemplates={templates.canManageTemplates}\n onSearchChange={templates.setSearch}\n onPageChange={templates.setPage}\n onPageSizeChange={templates.setPageSize}\n onRefresh={templates.refresh}\n onEdit={openEditor}\n onDelete={(template) => void templates.deleteTemplate(template)}\n />\n )}\n {templates.canManageTemplates && editorOpen ? <TemplateEditorDialog\n open\n template={editing}\n onOpenChange={(open) => { setEditorOpen(open); if (!open) setEditing(null) }}\n onSaved={templates.refreshFromFirstPage}\n /> : null}\n {templates.ConfirmDialogElement}\n </PageBody>\n </Page>\n )\n}\n\nexport default TemplatesPageClient\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -9,7 +9,7 @@ import { useT } from "@open-mercato/shared/lib/i18n/context";
9
9
  import { DOCUMENTS_ENTITY_IDS } from "../../../lib/constants.js";
10
10
  import { getEntityRegistryEntry } from "../../../lib/entityRegistry.js";
11
11
  import { formatDateTime } from "../documentUi.js";
12
- function TemplatesTable({ rows, page, pageSize, total, totalPages, search, isLoading, canManageTemplates, onSearchChange, onPageChange, onPageSizeChange, onRefresh, onEdit, onDelete }) {
12
+ function TemplatesTable({ rows, page, pageSize, total, totalPages, totalIsCapped, search, isLoading, canManageTemplates, onSearchChange, onPageChange, onPageSizeChange, onRefresh, onEdit, onDelete }) {
13
13
  const t = useT();
14
14
  const columns = React.useMemo(() => [
15
15
  { accessorKey: "name", header: t("documents.templates.columns.name"), meta: { alwaysVisible: true, maxWidth: "240px", truncate: true }, cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "font-medium", children: row.original.name }) },
@@ -41,6 +41,7 @@ function TemplatesTable({ rows, page, pageSize, total, totalPages, search, isLoa
41
41
  pageSize,
42
42
  total,
43
43
  totalPages,
44
+ totalIsCapped,
44
45
  onPageChange,
45
46
  onPageSizeChange,
46
47
  pageSizeOptions: [25, 50, 100]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/documents/backend/documents/templates/TemplatesTable.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { StatusBadge } from '@open-mercato/ui/primitives/status-badge'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DOCUMENTS_ENTITY_IDS } from '../../../lib/constants'\nimport { getEntityRegistryEntry } from '../../../lib/entityRegistry'\nimport { formatDateTime } from '../documentUi'\nimport type { TemplateRow } from '../components/templateUi'\n\nexport function TemplatesTable({ rows, page, pageSize, total, totalPages, search, isLoading, canManageTemplates, onSearchChange, onPageChange, onPageSizeChange, onRefresh, onEdit, onDelete }: {\n rows: TemplateRow[]\n page: number\n pageSize: number\n total: number\n totalPages: number\n search: string\n isLoading: boolean\n canManageTemplates: boolean\n onSearchChange: (search: string) => void\n onPageChange: (page: number) => void\n onPageSizeChange: (pageSize: number) => void\n onRefresh: () => void\n onEdit: (template: TemplateRow | null) => void\n onDelete: (template: TemplateRow) => void\n}) {\n const t = useT()\n const columns = React.useMemo<ColumnDef<TemplateRow>[]>(() => [\n { accessorKey: 'name', header: t('documents.templates.columns.name'), meta: { alwaysVisible: true, maxWidth: '240px', truncate: true }, cell: ({ row }) => <span className=\"font-medium\">{row.original.name}</span> },\n { accessorKey: 'description', header: t('documents.templates.columns.description'), meta: { maxWidth: '320px', truncate: true }, cell: ({ row }) => row.original.description ?? <span className=\"text-muted-foreground\">{t('documents.templates.list.noDescription')}</span> },\n { id: 'slots', header: t('documents.templates.columns.slots'), meta: { maxWidth: '260px', truncate: true }, cell: ({ row }) => row.original.contextSlots.length > 0 ? row.original.contextSlots.map((slot) => t(getEntityRegistryEntry(slot.entityType)?.labelKey ?? 'documents.relatedRecords.restricted')).join(', ') : t('documents.templates.slots.none') },\n { accessorKey: 'isActive', header: t('documents.templates.columns.active'), cell: ({ row }) => <StatusBadge variant={row.original.isActive ? 'success' : 'neutral'} dot>{t(row.original.isActive ? 'documents.templates.status.active' : 'documents.templates.status.inactive')}</StatusBadge> },\n { accessorKey: 'updatedAt', header: t('documents.columns.updatedAt'), meta: { maxWidth: '180px' }, cell: ({ row }) => formatDateTime(row.original.updatedAt, t('documents.list.noValue')) },\n ], [t])\n return (\n <DataTable<TemplateRow>\n title={t('documents.templates.list.title')}\n actions={canManageTemplates ? <Button type=\"button\" onClick={() => onEdit(null)}>{t('documents.templates.actions.new')}</Button> : undefined}\n refreshButton={{ label: t('documents.actions.refresh'), onRefresh, isRefreshing: isLoading }}\n columns={columns}\n data={rows}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={onSearchChange}\n searchPlaceholder={t('documents.templates.list.searchPlaceholder')}\n emptyState={t('documents.templates.list.empty')}\n entityId={DOCUMENTS_ENTITY_IDS.documentTemplate}\n extensionTableId=\"documents.templates.list\"\n onRowClick={canManageTemplates ? onEdit : undefined}\n rowClickActionIds={canManageTemplates ? ['edit'] : []}\n stickyActionsColumn\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n onPageChange,\n onPageSizeChange,\n pageSizeOptions: [25, 50, 100],\n }}\n rowActions={canManageTemplates ? (row) => <RowActions items={[\n { id: 'edit', label: t('documents.actions.edit'), onSelect: () => onEdit(row) },\n { id: 'delete', label: t('documents.actions.delete'), destructive: true, onSelect: () => onDelete(row) },\n ]} /> : undefined}\n />\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { StatusBadge } from '@open-mercato/ui/primitives/status-badge'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DOCUMENTS_ENTITY_IDS } from '../../../lib/constants'\nimport { getEntityRegistryEntry } from '../../../lib/entityRegistry'\nimport { formatDateTime } from '../documentUi'\nimport type { TemplateRow } from '../components/templateUi'\n\nexport function TemplatesTable({ rows, page, pageSize, total, totalPages, totalIsCapped, search, isLoading, canManageTemplates, onSearchChange, onPageChange, onPageSizeChange, onRefresh, onEdit, onDelete }: {\n rows: TemplateRow[]\n page: number\n pageSize: number\n total: number\n totalPages: number\n totalIsCapped: boolean\n search: string\n isLoading: boolean\n canManageTemplates: boolean\n onSearchChange: (search: string) => void\n onPageChange: (page: number) => void\n onPageSizeChange: (pageSize: number) => void\n onRefresh: () => void\n onEdit: (template: TemplateRow | null) => void\n onDelete: (template: TemplateRow) => void\n}) {\n const t = useT()\n const columns = React.useMemo<ColumnDef<TemplateRow>[]>(() => [\n { accessorKey: 'name', header: t('documents.templates.columns.name'), meta: { alwaysVisible: true, maxWidth: '240px', truncate: true }, cell: ({ row }) => <span className=\"font-medium\">{row.original.name}</span> },\n { accessorKey: 'description', header: t('documents.templates.columns.description'), meta: { maxWidth: '320px', truncate: true }, cell: ({ row }) => row.original.description ?? <span className=\"text-muted-foreground\">{t('documents.templates.list.noDescription')}</span> },\n { id: 'slots', header: t('documents.templates.columns.slots'), meta: { maxWidth: '260px', truncate: true }, cell: ({ row }) => row.original.contextSlots.length > 0 ? row.original.contextSlots.map((slot) => t(getEntityRegistryEntry(slot.entityType)?.labelKey ?? 'documents.relatedRecords.restricted')).join(', ') : t('documents.templates.slots.none') },\n { accessorKey: 'isActive', header: t('documents.templates.columns.active'), cell: ({ row }) => <StatusBadge variant={row.original.isActive ? 'success' : 'neutral'} dot>{t(row.original.isActive ? 'documents.templates.status.active' : 'documents.templates.status.inactive')}</StatusBadge> },\n { accessorKey: 'updatedAt', header: t('documents.columns.updatedAt'), meta: { maxWidth: '180px' }, cell: ({ row }) => formatDateTime(row.original.updatedAt, t('documents.list.noValue')) },\n ], [t])\n return (\n <DataTable<TemplateRow>\n title={t('documents.templates.list.title')}\n actions={canManageTemplates ? <Button type=\"button\" onClick={() => onEdit(null)}>{t('documents.templates.actions.new')}</Button> : undefined}\n refreshButton={{ label: t('documents.actions.refresh'), onRefresh, isRefreshing: isLoading }}\n columns={columns}\n data={rows}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={onSearchChange}\n searchPlaceholder={t('documents.templates.list.searchPlaceholder')}\n emptyState={t('documents.templates.list.empty')}\n entityId={DOCUMENTS_ENTITY_IDS.documentTemplate}\n extensionTableId=\"documents.templates.list\"\n onRowClick={canManageTemplates ? onEdit : undefined}\n rowClickActionIds={canManageTemplates ? ['edit'] : []}\n stickyActionsColumn\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n totalIsCapped,\n onPageChange,\n onPageSizeChange,\n pageSizeOptions: [25, 50, 100],\n }}\n rowActions={canManageTemplates ? (row) => <RowActions items={[\n { id: 'edit', label: t('documents.actions.edit'), onSelect: () => onEdit(row) },\n { id: 'delete', label: t('documents.actions.delete'), destructive: true, onSelect: () => onDelete(row) },\n ]} /> : undefined}\n />\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -23,6 +23,7 @@ function useTemplatesPage() {
23
23
  const [pageSize, setPageSizeState] = React.useState(TEMPLATE_MANAGEMENT_PAGE_SIZE);
24
24
  const [total, setTotal] = React.useState(0);
25
25
  const [totalPages, setTotalPages] = React.useState(1);
26
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false);
26
27
  const [search, setSearch] = React.useState("");
27
28
  const [isLoading, setIsLoading] = React.useState(true);
28
29
  const [loadError, setLoadError] = React.useState(null);
@@ -62,6 +63,7 @@ function useTemplatesPage() {
62
63
  setRows([]);
63
64
  setTotal(0);
64
65
  setTotalPages(1);
66
+ setTotalIsCapped(false);
65
67
  setCanManageTemplates(false);
66
68
  setLoadError(t("documents.templates.error.load"));
67
69
  return;
@@ -72,11 +74,13 @@ function useTemplatesPage() {
72
74
  const nextTotal = Math.max(0, Math.floor(root ? readNumber(root, "total", "totalCount", "total_count") ?? nextRows.length : nextRows.length));
73
75
  const nextTotalPages = Math.max(1, Math.floor(root ? readNumber(root, "totalPages", "total_pages") ?? Math.ceil(nextTotal / nextPageSize) : 1));
74
76
  const returnedPage = Math.max(1, Math.floor(root ? readNumber(root, "page") ?? page : page));
77
+ const nextTotalIsCapped = root ? readBoolean(root, "totalIsCapped", "total_is_capped") ?? false : false;
75
78
  setRows(nextRows);
76
79
  setTotal(nextTotal);
77
80
  setTotalPages(nextTotalPages);
81
+ setTotalIsCapped(nextTotalIsCapped);
78
82
  if (nextPageSize !== pageSize) setPageSizeState(nextPageSize);
79
- if (Math.min(returnedPage, nextTotalPages) !== page) setPage(Math.min(returnedPage, nextTotalPages));
83
+ if (!nextTotalIsCapped && Math.min(returnedPage, nextTotalPages) !== page) setPage(Math.min(returnedPage, nextTotalPages));
80
84
  const capabilities = readRecord(root?.capabilities);
81
85
  setCanManageTemplates(capabilities ? readBoolean(capabilities, "canManageTemplates", "can_manage_templates") ?? false : false);
82
86
  }).catch(() => {
@@ -84,6 +88,7 @@ function useTemplatesPage() {
84
88
  setRows([]);
85
89
  setTotal(0);
86
90
  setTotalPages(1);
91
+ setTotalIsCapped(false);
87
92
  setCanManageTemplates(false);
88
93
  setLoadError(t("documents.templates.error.load"));
89
94
  }).finally(() => {
@@ -122,6 +127,7 @@ function useTemplatesPage() {
122
127
  setPageSize: changePageSize,
123
128
  total,
124
129
  totalPages,
130
+ totalIsCapped,
125
131
  search,
126
132
  setSearch: changeSearch,
127
133
  isLoading,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/documents/backend/documents/templates/useTemplatesPage.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, apiCallOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DOCUMENTS_ENTITY_IDS } from '../../../lib/constants'\nimport { normalizeTemplates, type TemplateRow } from '../components/templateUi'\nimport { readBoolean, readNumber, readRecord } from '../documentUi'\n\nconst TEMPLATE_MANAGEMENT_PAGE_SIZE = 100\n\nfunction normalizePageSize(value: number): number {\n return Math.min(TEMPLATE_MANAGEMENT_PAGE_SIZE, Math.max(1, Math.floor(value)))\n}\n\nexport function useTemplatesPage() {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const requestId = React.useRef(0)\n const [rows, setRows] = React.useState<TemplateRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize, setPageSizeState] = React.useState(TEMPLATE_MANAGEMENT_PAGE_SIZE)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [loadError, setLoadError] = React.useState<string | null>(null)\n const [canManageTemplates, setCanManageTemplates] = React.useState(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const mutationContextId = 'documents-templates-list:mutation'\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({ contextId: mutationContextId, blockedMessage: t('ui.forms.flash.saveBlocked') })\n const refresh = React.useCallback(() => setReloadToken((value) => value + 1), [])\n const refreshFromFirstPage = React.useCallback(() => {\n setPage(1)\n setReloadToken((value) => value + 1)\n }, [])\n const changeSearch = React.useCallback((value: string) => {\n setIsLoading(true)\n setLoadError(null)\n setSearch(value)\n setPage(1)\n }, [])\n const changePageSize = React.useCallback((value: number) => {\n setPageSizeState(normalizePageSize(value))\n setPage(1)\n }, [])\n\n React.useEffect(() => {\n const currentRequestId = ++requestId.current\n setIsLoading(true)\n setLoadError(null)\n setCanManageTemplates(false)\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n includeBody: 'false',\n })\n if (search.trim()) params.set('search', search.trim())\n void apiCall<unknown>(`/api/documents/templates?${params.toString()}`, undefined, { fallback: { items: [] } })\n .then((call) => {\n if (requestId.current !== currentRequestId) return\n if (!call.ok) {\n setRows([])\n setTotal(0)\n setTotalPages(1)\n setCanManageTemplates(false)\n setLoadError(t('documents.templates.error.load'))\n return\n }\n const nextRows = normalizeTemplates(call.result)\n const root = readRecord(call.result)\n const nextPageSize = normalizePageSize(root ? readNumber(root, 'pageSize', 'page_size') ?? pageSize : pageSize)\n const nextTotal = Math.max(0, Math.floor(root ? readNumber(root, 'total', 'totalCount', 'total_count') ?? nextRows.length : nextRows.length))\n const nextTotalPages = Math.max(1, Math.floor(root ? readNumber(root, 'totalPages', 'total_pages') ?? Math.ceil(nextTotal / nextPageSize) : 1))\n const returnedPage = Math.max(1, Math.floor(root ? readNumber(root, 'page') ?? page : page))\n setRows(nextRows)\n setTotal(nextTotal)\n setTotalPages(nextTotalPages)\n if (nextPageSize !== pageSize) setPageSizeState(nextPageSize)\n if (Math.min(returnedPage, nextTotalPages) !== page) setPage(Math.min(returnedPage, nextTotalPages))\n const capabilities = readRecord(root?.capabilities)\n setCanManageTemplates(capabilities ? readBoolean(capabilities, 'canManageTemplates', 'can_manage_templates') ?? false : false)\n })\n .catch(() => {\n if (requestId.current !== currentRequestId) return\n setRows([])\n setTotal(0)\n setTotalPages(1)\n setCanManageTemplates(false)\n setLoadError(t('documents.templates.error.load'))\n })\n .finally(() => { if (requestId.current === currentRequestId) setIsLoading(false) })\n }, [page, pageSize, reloadToken, search, t])\n\n const deleteTemplate = React.useCallback(async (template: TemplateRow) => {\n if (!canManageTemplates) return\n if (!await confirm({ title: t('documents.templates.confirmDelete', { name: template.name }), variant: 'destructive' })) return\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(template.updatedAt),\n () => apiCallOrThrow(\n '/api/documents/templates',\n { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id: template.id }) },\n { errorMessage: t('documents.templates.error.delete') },\n ),\n ),\n context: { formId: mutationContextId, resourceKind: DOCUMENTS_ENTITY_IDS.documentTemplate, resourceId: template.id, retryLastMutation },\n mutationPayload: { id: template.id },\n })\n flash(t('documents.templates.success.delete'), 'success')\n refreshFromFirstPage()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refreshFromFirstPage })) {\n flash(error instanceof Error ? error.message : t('documents.templates.error.delete'), 'error')\n }\n }\n }, [canManageTemplates, confirm, mutationContextId, refreshFromFirstPage, retryLastMutation, runMutation, t])\n\n return {\n rows,\n page,\n setPage,\n pageSize,\n setPageSize: changePageSize,\n total,\n totalPages,\n search,\n setSearch: changeSearch,\n isLoading,\n loadError,\n canManageTemplates,\n refresh,\n refreshFromFirstPage,\n deleteTemplate,\n ConfirmDialogElement,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, apiCallOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DOCUMENTS_ENTITY_IDS } from '../../../lib/constants'\nimport { normalizeTemplates, type TemplateRow } from '../components/templateUi'\nimport { readBoolean, readNumber, readRecord } from '../documentUi'\n\nconst TEMPLATE_MANAGEMENT_PAGE_SIZE = 100\n\nfunction normalizePageSize(value: number): number {\n return Math.min(TEMPLATE_MANAGEMENT_PAGE_SIZE, Math.max(1, Math.floor(value)))\n}\n\nexport function useTemplatesPage() {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const requestId = React.useRef(0)\n const [rows, setRows] = React.useState<TemplateRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize, setPageSizeState] = React.useState(TEMPLATE_MANAGEMENT_PAGE_SIZE)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [loadError, setLoadError] = React.useState<string | null>(null)\n const [canManageTemplates, setCanManageTemplates] = React.useState(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const mutationContextId = 'documents-templates-list:mutation'\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({ contextId: mutationContextId, blockedMessage: t('ui.forms.flash.saveBlocked') })\n const refresh = React.useCallback(() => setReloadToken((value) => value + 1), [])\n const refreshFromFirstPage = React.useCallback(() => {\n setPage(1)\n setReloadToken((value) => value + 1)\n }, [])\n const changeSearch = React.useCallback((value: string) => {\n setIsLoading(true)\n setLoadError(null)\n setSearch(value)\n setPage(1)\n }, [])\n const changePageSize = React.useCallback((value: number) => {\n setPageSizeState(normalizePageSize(value))\n setPage(1)\n }, [])\n\n React.useEffect(() => {\n const currentRequestId = ++requestId.current\n setIsLoading(true)\n setLoadError(null)\n setCanManageTemplates(false)\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n includeBody: 'false',\n })\n if (search.trim()) params.set('search', search.trim())\n void apiCall<unknown>(`/api/documents/templates?${params.toString()}`, undefined, { fallback: { items: [] } })\n .then((call) => {\n if (requestId.current !== currentRequestId) return\n if (!call.ok) {\n setRows([])\n setTotal(0)\n setTotalPages(1)\n setTotalIsCapped(false)\n setCanManageTemplates(false)\n setLoadError(t('documents.templates.error.load'))\n return\n }\n const nextRows = normalizeTemplates(call.result)\n const root = readRecord(call.result)\n const nextPageSize = normalizePageSize(root ? readNumber(root, 'pageSize', 'page_size') ?? pageSize : pageSize)\n const nextTotal = Math.max(0, Math.floor(root ? readNumber(root, 'total', 'totalCount', 'total_count') ?? nextRows.length : nextRows.length))\n const nextTotalPages = Math.max(1, Math.floor(root ? readNumber(root, 'totalPages', 'total_pages') ?? Math.ceil(nextTotal / nextPageSize) : 1))\n const returnedPage = Math.max(1, Math.floor(root ? readNumber(root, 'page') ?? page : page))\n const nextTotalIsCapped = root ? readBoolean(root, 'totalIsCapped', 'total_is_capped') ?? false : false\n setRows(nextRows)\n setTotal(nextTotal)\n setTotalPages(nextTotalPages)\n setTotalIsCapped(nextTotalIsCapped)\n if (nextPageSize !== pageSize) setPageSizeState(nextPageSize)\n // A capped totalPages is a floor, so clamping to it would bounce the\n // user off pages that exist past the cap.\n if (!nextTotalIsCapped && Math.min(returnedPage, nextTotalPages) !== page) setPage(Math.min(returnedPage, nextTotalPages))\n const capabilities = readRecord(root?.capabilities)\n setCanManageTemplates(capabilities ? readBoolean(capabilities, 'canManageTemplates', 'can_manage_templates') ?? false : false)\n })\n .catch(() => {\n if (requestId.current !== currentRequestId) return\n setRows([])\n setTotal(0)\n setTotalPages(1)\n setTotalIsCapped(false)\n setCanManageTemplates(false)\n setLoadError(t('documents.templates.error.load'))\n })\n .finally(() => { if (requestId.current === currentRequestId) setIsLoading(false) })\n }, [page, pageSize, reloadToken, search, t])\n\n const deleteTemplate = React.useCallback(async (template: TemplateRow) => {\n if (!canManageTemplates) return\n if (!await confirm({ title: t('documents.templates.confirmDelete', { name: template.name }), variant: 'destructive' })) return\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(template.updatedAt),\n () => apiCallOrThrow(\n '/api/documents/templates',\n { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id: template.id }) },\n { errorMessage: t('documents.templates.error.delete') },\n ),\n ),\n context: { formId: mutationContextId, resourceKind: DOCUMENTS_ENTITY_IDS.documentTemplate, resourceId: template.id, retryLastMutation },\n mutationPayload: { id: template.id },\n })\n flash(t('documents.templates.success.delete'), 'success')\n refreshFromFirstPage()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refreshFromFirstPage })) {\n flash(error instanceof Error ? error.message : t('documents.templates.error.delete'), 'error')\n }\n }\n }, [canManageTemplates, confirm, mutationContextId, refreshFromFirstPage, retryLastMutation, runMutation, t])\n\n return {\n rows,\n page,\n setPage,\n pageSize,\n setPageSize: changePageSize,\n total,\n totalPages,\n totalIsCapped,\n search,\n setSearch: changeSearch,\n isLoading,\n loadError,\n canManageTemplates,\n refresh,\n refreshFromFirstPage,\n deleteTemplate,\n ConfirmDialogElement,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -17,7 +17,7 @@ import {
17
17
  normalizeFolders,
18
18
  readCreatedId
19
19
  } from "./documentsListTypes.js";
20
- import { readNumber, readRecord } from "./documentUi.js";
20
+ import { readBoolean, readNumber, readRecord } from "./documentUi.js";
21
21
  function useDocumentsList() {
22
22
  const t = useT();
23
23
  const router = useRouter();
@@ -31,6 +31,7 @@ function useDocumentsList() {
31
31
  const [pageSize, setPageSize] = React.useState(25);
32
32
  const [total, setTotal] = React.useState(0);
33
33
  const [totalPages, setTotalPages] = React.useState(1);
34
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false);
34
35
  const [search, setSearch] = React.useState("");
35
36
  const [archivedFilter, setArchivedFilter] = React.useState("exclude");
36
37
  const [favoritesOnly, setFavoritesOnly] = React.useState(false);
@@ -62,6 +63,7 @@ function useDocumentsList() {
62
63
  setFolders([]);
63
64
  setTotal(0);
64
65
  setTotalPages(1);
66
+ setTotalIsCapped(false);
65
67
  setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES);
66
68
  setLoadError(t("documents.list.error.load"));
67
69
  return;
@@ -75,12 +77,14 @@ function useDocumentsList() {
75
77
  setCollectionCapabilities(normalizeCollectionCapabilities(documentsCall.result));
76
78
  setTotal(nextTotal);
77
79
  setTotalPages(root ? readNumber(root, "totalPages", "total_pages") ?? Math.max(1, Math.ceil(nextTotal / pageSize)) : 1);
80
+ setTotalIsCapped(root ? readBoolean(root, "totalIsCapped", "total_is_capped") ?? false : false);
78
81
  }).catch(() => {
79
82
  if (requestId.current !== currentRequestId) return;
80
83
  setRows([]);
81
84
  setFolders([]);
82
85
  setTotal(0);
83
86
  setTotalPages(1);
87
+ setTotalIsCapped(false);
84
88
  setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES);
85
89
  setLoadError(t("documents.list.error.load"));
86
90
  }).finally(() => {
@@ -285,6 +289,7 @@ function useDocumentsList() {
285
289
  setPageSize,
286
290
  total,
287
291
  totalPages,
292
+ totalIsCapped,
288
293
  search,
289
294
  setSearch,
290
295
  isLoading,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/documents/backend/documents/useDocumentsList.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { apiCall, apiCallOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n hasActiveTemplate,\n canWriteToFolder,\n EMPTY_COLLECTION_CAPABILITIES,\n normalizeCollectionCapabilities,\n normalizeDocuments,\n normalizeFolders,\n readCreatedId,\n type DocumentRow,\n type FolderRow,\n type CollectionCapabilities,\n} from './documentsListTypes'\nimport { readNumber, readRecord } from './documentUi'\n\nexport function useDocumentsList() {\n const t = useT()\n const router = useRouter()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const requestId = React.useRef(0)\n const createInFlight = React.useRef(false)\n const [rows, setRows] = React.useState<DocumentRow[]>([])\n const [folders, setFolders] = React.useState<FolderRow[]>([])\n const [selectedFolderId, setSelectedFolderId] = React.useState<string | null>(null)\n const [page, setPage] = React.useState(1)\n const [pageSize, setPageSize] = React.useState(25)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [archivedFilter, setArchivedFilter] = React.useState<'exclude' | 'include' | 'only'>('exclude')\n const [favoritesOnly, setFavoritesOnly] = React.useState(false)\n const [isLoading, setIsLoading] = React.useState(true)\n const [isCreating, setIsCreating] = React.useState(false)\n const [loadError, setLoadError] = React.useState<string | null>(null)\n const [hasTemplates, setHasTemplates] = React.useState(false)\n const [collectionCapabilities, setCollectionCapabilities] = React.useState<CollectionCapabilities>(EMPTY_COLLECTION_CAPABILITIES)\n const [reloadToken, setReloadToken] = React.useState(0)\n const mutationContextId = 'documents-list:mutation'\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({ contextId: mutationContextId, blockedMessage: t('ui.forms.flash.saveBlocked') })\n\n const refresh = React.useCallback(() => setReloadToken((token) => token + 1), [])\n React.useEffect(() => {\n const currentRequestId = ++requestId.current\n setIsLoading(true)\n setLoadError(null)\n const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) })\n if (search.trim()) params.set('search', search.trim())\n if (selectedFolderId) params.set('folderId', selectedFolderId)\n if (archivedFilter !== 'exclude') params.set('archived', archivedFilter)\n if (favoritesOnly) params.set('favorite', 'true')\n void Promise.all([\n apiCall<unknown>('/api/documents/folders', undefined, { fallback: { items: [] } }),\n apiCall<unknown>(`/api/documents?${params.toString()}`, undefined, { fallback: { items: [] } }),\n ]).then(([foldersCall, documentsCall]) => {\n if (requestId.current !== currentRequestId) return\n if (!foldersCall.ok || !documentsCall.ok) {\n setRows([])\n setFolders([])\n setTotal(0)\n setTotalPages(1)\n setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES)\n setLoadError(t('documents.list.error.load'))\n return\n }\n const nextFolders = normalizeFolders(foldersCall.result)\n const nextRows = normalizeDocuments(documentsCall.result, nextFolders, t('documents.list.unknownOwner'))\n const root = readRecord(documentsCall.result)\n const nextTotal = root ? readNumber(root, 'total', 'totalCount', 'total_count') ?? nextRows.length : nextRows.length\n setFolders(nextFolders)\n setRows(nextRows)\n setCollectionCapabilities(normalizeCollectionCapabilities(documentsCall.result))\n setTotal(nextTotal)\n setTotalPages(root ? readNumber(root, 'totalPages', 'total_pages') ?? Math.max(1, Math.ceil(nextTotal / pageSize)) : 1)\n }).catch(() => {\n if (requestId.current !== currentRequestId) return\n setRows([])\n setFolders([])\n setTotal(0)\n setTotalPages(1)\n setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES)\n setLoadError(t('documents.list.error.load'))\n }).finally(() => {\n if (requestId.current === currentRequestId) setIsLoading(false)\n })\n }, [archivedFilter, favoritesOnly, page, pageSize, reloadToken, search, selectedFolderId, t])\n\n React.useEffect(() => {\n let active = true\n void apiCall<unknown>('/api/documents/templates?page=1&pageSize=1&isActive=true', undefined, { fallback: { items: [] } })\n .then((call) => { if (active) setHasTemplates(call.ok && hasActiveTemplate(call.result)) })\n return () => { active = false }\n }, [])\n\n const createDocument = React.useCallback(async () => {\n const selectedFolder = selectedFolderId ? folders.find((folder) => folder.id === selectedFolderId) ?? null : null\n if (createInFlight.current || !collectionCapabilities.canCreateDocument || !canWriteToFolder(selectedFolderId, selectedFolder)) return\n createInFlight.current = true\n setIsCreating(true)\n try {\n const call = await runMutation({\n operation: () => apiCallOrThrow<unknown>(\n '/api/documents',\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ title: t('documents.documents.untitled'), folderId: selectedFolderId }) },\n { errorMessage: t('documents.list.error.create') },\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: selectedFolderId ?? 'new', retryLastMutation },\n mutationPayload: { folderId: selectedFolderId },\n })\n const id = readCreatedId(call.result)\n if (!id) throw new Error(t('documents.list.error.missingCreatedId'))\n router.push(`/backend/documents/${id}`)\n } catch (error) {\n flash(error instanceof Error ? error.message : t('documents.list.error.create'), 'error')\n createInFlight.current = false\n setIsCreating(false)\n }\n }, [collectionCapabilities.canCreateDocument, folders, mutationContextId, retryLastMutation, router, runMutation, selectedFolderId, t])\n\n const deleteDocument = React.useCallback(async (row: DocumentRow) => {\n if (!await confirm({ title: t('documents.list.confirmDelete', { title: row.title }), variant: 'destructive' })) return\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(buildOptimisticLockHeader(row.updatedAt), () => apiCallOrThrow(`/api/documents/${encodeURIComponent(row.id)}`, { method: 'DELETE' })),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { id: row.id },\n })\n flash(t('documents.list.success.delete'), 'success')\n refresh()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.list.error.delete'), 'error')\n }\n }\n }, [confirm, mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const moveDocument = React.useCallback(async (row: DocumentRow, folderId: string | null) => {\n if (!row.capabilities.canEdit || row.folderId === folderId) return false\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () => apiCallOrThrow(\n `/api/documents/${encodeURIComponent(row.id)}`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ folderId }),\n },\n { errorMessage: t('documents.folders.error.moveDocument') },\n ),\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { id: row.id, folderId },\n })\n flash(t('documents.folders.success.moveDocument'), 'success')\n refresh()\n return true\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.folders.error.moveDocument'), 'error')\n }\n return false\n }\n }, [mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const saveFolder = React.useCallback(async (input: { folder?: FolderRow; parentFolderId?: string | null; name: string }) => {\n const isRename = Boolean(input.folder)\n const folder = input.folder\n const operation = () => apiCallOrThrow(\n '/api/documents/folders',\n {\n method: isRename ? 'PUT' : 'POST', headers: { 'content-type': 'application/json' },\n body: JSON.stringify(isRename ? { id: folder?.id, name: input.name, parentFolderId: folder?.parentFolderId } : { name: input.name, parentFolderId: input.parentFolderId ?? null }),\n },\n { errorMessage: t(isRename ? 'documents.folders.error.rename' : 'documents.folders.error.create') },\n )\n try {\n await runMutation({\n operation: () => isRename ? withScopedApiRequestHeaders(buildOptimisticLockHeader(folder?.updatedAt), operation) : operation(),\n context: { formId: mutationContextId, resourceKind: 'documents.document_folder', resourceId: folder?.id ?? input.parentFolderId ?? 'new', retryLastMutation },\n mutationPayload: input,\n })\n flash(t(isRename ? 'documents.folders.success.rename' : 'documents.folders.success.create'), 'success')\n refresh()\n return true\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t(isRename ? 'documents.folders.error.rename' : 'documents.folders.error.create'), 'error')\n }\n return false\n }\n }, [mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const deleteFolder = React.useCallback(async (folder: FolderRow) => {\n if (!await confirm({ title: t('documents.folders.confirmDelete', { name: folder.name }), variant: 'destructive' })) return\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(buildOptimisticLockHeader(folder.updatedAt), () => apiCallOrThrow('/api/documents/folders', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id: folder.id }) })),\n context: { formId: mutationContextId, resourceKind: 'documents.document_folder', resourceId: folder.id, retryLastMutation },\n mutationPayload: { id: folder.id },\n })\n if (selectedFolderId === folder.id) setSelectedFolderId(null)\n flash(t('documents.folders.success.delete'), 'success')\n refresh()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.folders.error.delete'), 'error')\n }\n }\n }, [confirm, mutationContextId, refresh, retryLastMutation, runMutation, selectedFolderId, t])\n\n const pendingFavoriteIds = React.useRef<Set<string>>(new Set())\n const toggleFavorite = React.useCallback(async (row: DocumentRow) => {\n if (pendingFavoriteIds.current.has(row.id)) return\n pendingFavoriteIds.current.add(row.id)\n const nextActive = !row.isFavorite\n setRows((current) => current.map((candidate) => candidate.id === row.id\n ? { ...candidate, isFavorite: nextActive }\n : candidate))\n try {\n await runMutation({\n operation: () => apiCallOrThrow(\n `/api/documents/${encodeURIComponent(row.id)}/favorite`,\n { method: nextActive ? 'POST' : 'DELETE' },\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document_favorite', resourceId: row.id, retryLastMutation },\n mutationPayload: { id: row.id, active: nextActive },\n })\n if (favoritesOnly && !nextActive) refresh()\n } catch (error) {\n setRows((current) => current.map((candidate) => candidate.id === row.id\n ? { ...candidate, isFavorite: !nextActive }\n : candidate))\n flash(error instanceof Error ? error.message : t('documents.list.error.load'), 'error')\n } finally {\n pendingFavoriteIds.current.delete(row.id)\n }\n }, [favoritesOnly, mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const pendingDuplicateIds = React.useRef<Set<string>>(new Set())\n const duplicateDocument = React.useCallback(async (row: DocumentRow) => {\n if (pendingDuplicateIds.current.has(row.id)) return\n pendingDuplicateIds.current.add(row.id)\n try {\n const created = await runMutation({\n operation: () => apiCallOrThrow<{ id: string }>(\n `/api/documents/${encodeURIComponent(row.id)}/duplicate`,\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({}) },\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { action: 'duplicate', sourceDocumentId: row.id },\n })\n flash(t('documents.duplicate.success'), 'success')\n const createdId = created?.result?.id\n if (createdId) router.push(`/backend/documents/${encodeURIComponent(createdId)}`)\n } catch (error) {\n flash(error instanceof Error ? error.message : t('documents.duplicate.error'), 'error')\n } finally {\n pendingDuplicateIds.current.delete(row.id)\n }\n }, [mutationContextId, retryLastMutation, router, runMutation, t])\n\n const archiveToggle = React.useCallback(async (row: DocumentRow) => {\n const action = row.archivedAt ? 'unarchive' : 'archive'\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () => apiCallOrThrow(`/api/documents/${encodeURIComponent(row.id)}/${action}`, { method: 'POST' }),\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { action, id: row.id },\n })\n flash(t(row.archivedAt ? 'documents.archive.success.unarchive' : 'documents.archive.success.archive'), 'success')\n refresh()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.archive.error'), 'error')\n }\n }\n }, [mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n return {\n rows, folders, selectedFolderId, setSelectedFolderId, page, setPage, pageSize, setPageSize,\n total, totalPages, search, setSearch, isLoading, isCreating, loadError, hasTemplates, collectionCapabilities, refresh,\n archivedFilter, setArchivedFilter, favoritesOnly, setFavoritesOnly,\n createDocument, deleteDocument, moveDocument, saveFolder, deleteFolder, ConfirmDialogElement,\n toggleFavorite, duplicateDocument, archiveToggle,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { apiCall, apiCallOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n hasActiveTemplate,\n canWriteToFolder,\n EMPTY_COLLECTION_CAPABILITIES,\n normalizeCollectionCapabilities,\n normalizeDocuments,\n normalizeFolders,\n readCreatedId,\n type DocumentRow,\n type FolderRow,\n type CollectionCapabilities,\n} from './documentsListTypes'\nimport { readBoolean, readNumber, readRecord } from './documentUi'\n\nexport function useDocumentsList() {\n const t = useT()\n const router = useRouter()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const requestId = React.useRef(0)\n const createInFlight = React.useRef(false)\n const [rows, setRows] = React.useState<DocumentRow[]>([])\n const [folders, setFolders] = React.useState<FolderRow[]>([])\n const [selectedFolderId, setSelectedFolderId] = React.useState<string | null>(null)\n const [page, setPage] = React.useState(1)\n const [pageSize, setPageSize] = React.useState(25)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [archivedFilter, setArchivedFilter] = React.useState<'exclude' | 'include' | 'only'>('exclude')\n const [favoritesOnly, setFavoritesOnly] = React.useState(false)\n const [isLoading, setIsLoading] = React.useState(true)\n const [isCreating, setIsCreating] = React.useState(false)\n const [loadError, setLoadError] = React.useState<string | null>(null)\n const [hasTemplates, setHasTemplates] = React.useState(false)\n const [collectionCapabilities, setCollectionCapabilities] = React.useState<CollectionCapabilities>(EMPTY_COLLECTION_CAPABILITIES)\n const [reloadToken, setReloadToken] = React.useState(0)\n const mutationContextId = 'documents-list:mutation'\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({ contextId: mutationContextId, blockedMessage: t('ui.forms.flash.saveBlocked') })\n\n const refresh = React.useCallback(() => setReloadToken((token) => token + 1), [])\n React.useEffect(() => {\n const currentRequestId = ++requestId.current\n setIsLoading(true)\n setLoadError(null)\n const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) })\n if (search.trim()) params.set('search', search.trim())\n if (selectedFolderId) params.set('folderId', selectedFolderId)\n if (archivedFilter !== 'exclude') params.set('archived', archivedFilter)\n if (favoritesOnly) params.set('favorite', 'true')\n void Promise.all([\n apiCall<unknown>('/api/documents/folders', undefined, { fallback: { items: [] } }),\n apiCall<unknown>(`/api/documents?${params.toString()}`, undefined, { fallback: { items: [] } }),\n ]).then(([foldersCall, documentsCall]) => {\n if (requestId.current !== currentRequestId) return\n if (!foldersCall.ok || !documentsCall.ok) {\n setRows([])\n setFolders([])\n setTotal(0)\n setTotalPages(1)\n setTotalIsCapped(false)\n setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES)\n setLoadError(t('documents.list.error.load'))\n return\n }\n const nextFolders = normalizeFolders(foldersCall.result)\n const nextRows = normalizeDocuments(documentsCall.result, nextFolders, t('documents.list.unknownOwner'))\n const root = readRecord(documentsCall.result)\n const nextTotal = root ? readNumber(root, 'total', 'totalCount', 'total_count') ?? nextRows.length : nextRows.length\n setFolders(nextFolders)\n setRows(nextRows)\n setCollectionCapabilities(normalizeCollectionCapabilities(documentsCall.result))\n setTotal(nextTotal)\n setTotalPages(root ? readNumber(root, 'totalPages', 'total_pages') ?? Math.max(1, Math.ceil(nextTotal / pageSize)) : 1)\n setTotalIsCapped(root ? readBoolean(root, 'totalIsCapped', 'total_is_capped') ?? false : false)\n }).catch(() => {\n if (requestId.current !== currentRequestId) return\n setRows([])\n setFolders([])\n setTotal(0)\n setTotalPages(1)\n setTotalIsCapped(false)\n setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES)\n setLoadError(t('documents.list.error.load'))\n }).finally(() => {\n if (requestId.current === currentRequestId) setIsLoading(false)\n })\n }, [archivedFilter, favoritesOnly, page, pageSize, reloadToken, search, selectedFolderId, t])\n\n React.useEffect(() => {\n let active = true\n void apiCall<unknown>('/api/documents/templates?page=1&pageSize=1&isActive=true', undefined, { fallback: { items: [] } })\n .then((call) => { if (active) setHasTemplates(call.ok && hasActiveTemplate(call.result)) })\n return () => { active = false }\n }, [])\n\n const createDocument = React.useCallback(async () => {\n const selectedFolder = selectedFolderId ? folders.find((folder) => folder.id === selectedFolderId) ?? null : null\n if (createInFlight.current || !collectionCapabilities.canCreateDocument || !canWriteToFolder(selectedFolderId, selectedFolder)) return\n createInFlight.current = true\n setIsCreating(true)\n try {\n const call = await runMutation({\n operation: () => apiCallOrThrow<unknown>(\n '/api/documents',\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ title: t('documents.documents.untitled'), folderId: selectedFolderId }) },\n { errorMessage: t('documents.list.error.create') },\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: selectedFolderId ?? 'new', retryLastMutation },\n mutationPayload: { folderId: selectedFolderId },\n })\n const id = readCreatedId(call.result)\n if (!id) throw new Error(t('documents.list.error.missingCreatedId'))\n router.push(`/backend/documents/${id}`)\n } catch (error) {\n flash(error instanceof Error ? error.message : t('documents.list.error.create'), 'error')\n createInFlight.current = false\n setIsCreating(false)\n }\n }, [collectionCapabilities.canCreateDocument, folders, mutationContextId, retryLastMutation, router, runMutation, selectedFolderId, t])\n\n const deleteDocument = React.useCallback(async (row: DocumentRow) => {\n if (!await confirm({ title: t('documents.list.confirmDelete', { title: row.title }), variant: 'destructive' })) return\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(buildOptimisticLockHeader(row.updatedAt), () => apiCallOrThrow(`/api/documents/${encodeURIComponent(row.id)}`, { method: 'DELETE' })),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { id: row.id },\n })\n flash(t('documents.list.success.delete'), 'success')\n refresh()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.list.error.delete'), 'error')\n }\n }\n }, [confirm, mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const moveDocument = React.useCallback(async (row: DocumentRow, folderId: string | null) => {\n if (!row.capabilities.canEdit || row.folderId === folderId) return false\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () => apiCallOrThrow(\n `/api/documents/${encodeURIComponent(row.id)}`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ folderId }),\n },\n { errorMessage: t('documents.folders.error.moveDocument') },\n ),\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { id: row.id, folderId },\n })\n flash(t('documents.folders.success.moveDocument'), 'success')\n refresh()\n return true\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.folders.error.moveDocument'), 'error')\n }\n return false\n }\n }, [mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const saveFolder = React.useCallback(async (input: { folder?: FolderRow; parentFolderId?: string | null; name: string }) => {\n const isRename = Boolean(input.folder)\n const folder = input.folder\n const operation = () => apiCallOrThrow(\n '/api/documents/folders',\n {\n method: isRename ? 'PUT' : 'POST', headers: { 'content-type': 'application/json' },\n body: JSON.stringify(isRename ? { id: folder?.id, name: input.name, parentFolderId: folder?.parentFolderId } : { name: input.name, parentFolderId: input.parentFolderId ?? null }),\n },\n { errorMessage: t(isRename ? 'documents.folders.error.rename' : 'documents.folders.error.create') },\n )\n try {\n await runMutation({\n operation: () => isRename ? withScopedApiRequestHeaders(buildOptimisticLockHeader(folder?.updatedAt), operation) : operation(),\n context: { formId: mutationContextId, resourceKind: 'documents.document_folder', resourceId: folder?.id ?? input.parentFolderId ?? 'new', retryLastMutation },\n mutationPayload: input,\n })\n flash(t(isRename ? 'documents.folders.success.rename' : 'documents.folders.success.create'), 'success')\n refresh()\n return true\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t(isRename ? 'documents.folders.error.rename' : 'documents.folders.error.create'), 'error')\n }\n return false\n }\n }, [mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const deleteFolder = React.useCallback(async (folder: FolderRow) => {\n if (!await confirm({ title: t('documents.folders.confirmDelete', { name: folder.name }), variant: 'destructive' })) return\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(buildOptimisticLockHeader(folder.updatedAt), () => apiCallOrThrow('/api/documents/folders', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id: folder.id }) })),\n context: { formId: mutationContextId, resourceKind: 'documents.document_folder', resourceId: folder.id, retryLastMutation },\n mutationPayload: { id: folder.id },\n })\n if (selectedFolderId === folder.id) setSelectedFolderId(null)\n flash(t('documents.folders.success.delete'), 'success')\n refresh()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.folders.error.delete'), 'error')\n }\n }\n }, [confirm, mutationContextId, refresh, retryLastMutation, runMutation, selectedFolderId, t])\n\n const pendingFavoriteIds = React.useRef<Set<string>>(new Set())\n const toggleFavorite = React.useCallback(async (row: DocumentRow) => {\n if (pendingFavoriteIds.current.has(row.id)) return\n pendingFavoriteIds.current.add(row.id)\n const nextActive = !row.isFavorite\n setRows((current) => current.map((candidate) => candidate.id === row.id\n ? { ...candidate, isFavorite: nextActive }\n : candidate))\n try {\n await runMutation({\n operation: () => apiCallOrThrow(\n `/api/documents/${encodeURIComponent(row.id)}/favorite`,\n { method: nextActive ? 'POST' : 'DELETE' },\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document_favorite', resourceId: row.id, retryLastMutation },\n mutationPayload: { id: row.id, active: nextActive },\n })\n if (favoritesOnly && !nextActive) refresh()\n } catch (error) {\n setRows((current) => current.map((candidate) => candidate.id === row.id\n ? { ...candidate, isFavorite: !nextActive }\n : candidate))\n flash(error instanceof Error ? error.message : t('documents.list.error.load'), 'error')\n } finally {\n pendingFavoriteIds.current.delete(row.id)\n }\n }, [favoritesOnly, mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n const pendingDuplicateIds = React.useRef<Set<string>>(new Set())\n const duplicateDocument = React.useCallback(async (row: DocumentRow) => {\n if (pendingDuplicateIds.current.has(row.id)) return\n pendingDuplicateIds.current.add(row.id)\n try {\n const created = await runMutation({\n operation: () => apiCallOrThrow<{ id: string }>(\n `/api/documents/${encodeURIComponent(row.id)}/duplicate`,\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({}) },\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { action: 'duplicate', sourceDocumentId: row.id },\n })\n flash(t('documents.duplicate.success'), 'success')\n const createdId = created?.result?.id\n if (createdId) router.push(`/backend/documents/${encodeURIComponent(createdId)}`)\n } catch (error) {\n flash(error instanceof Error ? error.message : t('documents.duplicate.error'), 'error')\n } finally {\n pendingDuplicateIds.current.delete(row.id)\n }\n }, [mutationContextId, retryLastMutation, router, runMutation, t])\n\n const archiveToggle = React.useCallback(async (row: DocumentRow) => {\n const action = row.archivedAt ? 'unarchive' : 'archive'\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () => apiCallOrThrow(`/api/documents/${encodeURIComponent(row.id)}/${action}`, { method: 'POST' }),\n ),\n context: { formId: mutationContextId, resourceKind: 'documents.document', resourceId: row.id, retryLastMutation },\n mutationPayload: { action, id: row.id },\n })\n flash(t(row.archivedAt ? 'documents.archive.success.unarchive' : 'documents.archive.success.archive'), 'success')\n refresh()\n } catch (error) {\n if (!surfaceRecordConflict(error, t, { onRefresh: refresh })) {\n flash(error instanceof Error ? error.message : t('documents.archive.error'), 'error')\n }\n }\n }, [mutationContextId, refresh, retryLastMutation, runMutation, t])\n\n return {\n rows, folders, selectedFolderId, setSelectedFolderId, page, setPage, pageSize, setPageSize,\n total, totalPages, totalIsCapped, search, setSearch, isLoading, isCreating, loadError, hasTemplates, collectionCapabilities, refresh,\n archivedFilter, setArchivedFilter, favoritesOnly, setFavoritesOnly,\n createDocument, deleteDocument, moveDocument, saveFolder, deleteFolder, ConfirmDialogElement,\n toggleFavorite, duplicateDocument, archiveToggle,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/documents",
3
- "version": "0.6.8-develop.7029.1.a1bb3363af",
3
+ "version": "0.6.8-develop.7031.1.005201cd70",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -75,8 +75,8 @@
75
75
  "@hocuspocus/server": "^4.4.0",
76
76
  "@hocuspocus/transformer": "^4.3.0",
77
77
  "@mikro-orm/core": "^7.1.8",
78
- "@open-mercato/events": "0.6.8-develop.7029.1.a1bb3363af",
79
- "@open-mercato/ui": "0.6.8-develop.7029.1.a1bb3363af",
78
+ "@open-mercato/events": "0.6.8-develop.7031.1.005201cd70",
79
+ "@open-mercato/ui": "0.6.8-develop.7031.1.005201cd70",
80
80
  "@tiptap/core": "^3",
81
81
  "@tiptap/extension-bubble-menu": "^3",
82
82
  "@tiptap/extension-collaboration": "^3.27.3",
@@ -112,13 +112,13 @@
112
112
  },
113
113
  "peerDependencies": {
114
114
  "@mikro-orm/postgresql": "^7.0.14",
115
- "@open-mercato/shared": "0.6.8-develop.7029.1.a1bb3363af",
115
+ "@open-mercato/shared": "0.6.8-develop.7031.1.005201cd70",
116
116
  "react": "^19.0.0",
117
117
  "react-dom": "^19.0.0"
118
118
  },
119
119
  "devDependencies": {
120
- "@open-mercato/core": "0.6.8-develop.7029.1.a1bb3363af",
121
- "@open-mercato/shared": "0.6.8-develop.7029.1.a1bb3363af",
120
+ "@open-mercato/core": "0.6.8-develop.7031.1.005201cd70",
121
+ "@open-mercato/shared": "0.6.8-develop.7031.1.005201cd70",
122
122
  "@types/jest": "^30.0.0",
123
123
  "@types/pg": "^8.20.0",
124
124
  "@types/react": "^19.2.16",
@@ -91,6 +91,7 @@ export function DocumentsPageClient() {
91
91
  pageSize={documents.pageSize}
92
92
  total={documents.total}
93
93
  totalPages={documents.totalPages}
94
+ totalIsCapped={documents.totalIsCapped}
94
95
  hasTemplates={documents.hasTemplates}
95
96
  canCreateDocument={canCreateDocument}
96
97
  canInstantiateTemplate={canInstantiateTemplate}
@@ -36,6 +36,7 @@ type DocumentsTableProps = {
36
36
  pageSize: number
37
37
  total: number
38
38
  totalPages: number
39
+ totalIsCapped: boolean
39
40
  hasTemplates: boolean
40
41
  canCreateDocument: boolean
41
42
  canInstantiateTemplate: boolean
@@ -146,6 +147,7 @@ export function DocumentsTable(props: DocumentsTableProps) {
146
147
  stickyActionsColumn
147
148
  pagination={{
148
149
  page: props.page, pageSize: props.pageSize, total: props.total, totalPages: props.totalPages,
150
+ totalIsCapped: props.totalIsCapped,
149
151
  onPageChange: props.onPageChange, onPageSizeChange: props.onPageSizeChange,
150
152
  }}
151
153
  rowActions={(row) => {
@@ -67,6 +67,7 @@ export function TemplatesPageClient() {
67
67
  pageSize={templates.pageSize}
68
68
  total={templates.total}
69
69
  totalPages={templates.totalPages}
70
+ totalIsCapped={templates.totalIsCapped}
70
71
  search={templates.search}
71
72
  isLoading={templates.isLoading}
72
73
  canManageTemplates={templates.canManageTemplates}
@@ -12,12 +12,13 @@ import { getEntityRegistryEntry } from '../../../lib/entityRegistry'
12
12
  import { formatDateTime } from '../documentUi'
13
13
  import type { TemplateRow } from '../components/templateUi'
14
14
 
15
- export function TemplatesTable({ rows, page, pageSize, total, totalPages, search, isLoading, canManageTemplates, onSearchChange, onPageChange, onPageSizeChange, onRefresh, onEdit, onDelete }: {
15
+ export function TemplatesTable({ rows, page, pageSize, total, totalPages, totalIsCapped, search, isLoading, canManageTemplates, onSearchChange, onPageChange, onPageSizeChange, onRefresh, onEdit, onDelete }: {
16
16
  rows: TemplateRow[]
17
17
  page: number
18
18
  pageSize: number
19
19
  total: number
20
20
  totalPages: number
21
+ totalIsCapped: boolean
21
22
  search: string
22
23
  isLoading: boolean
23
24
  canManageTemplates: boolean
@@ -58,6 +59,7 @@ export function TemplatesTable({ rows, page, pageSize, total, totalPages, search
58
59
  pageSize,
59
60
  total,
60
61
  totalPages,
62
+ totalIsCapped,
61
63
  onPageChange,
62
64
  onPageSizeChange,
63
65
  pageSizeOptions: [25, 50, 100],
@@ -27,6 +27,7 @@ export function useTemplatesPage() {
27
27
  const [pageSize, setPageSizeState] = React.useState(TEMPLATE_MANAGEMENT_PAGE_SIZE)
28
28
  const [total, setTotal] = React.useState(0)
29
29
  const [totalPages, setTotalPages] = React.useState(1)
30
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
30
31
  const [search, setSearch] = React.useState('')
31
32
  const [isLoading, setIsLoading] = React.useState(true)
32
33
  const [loadError, setLoadError] = React.useState<string | null>(null)
@@ -73,6 +74,7 @@ export function useTemplatesPage() {
73
74
  setRows([])
74
75
  setTotal(0)
75
76
  setTotalPages(1)
77
+ setTotalIsCapped(false)
76
78
  setCanManageTemplates(false)
77
79
  setLoadError(t('documents.templates.error.load'))
78
80
  return
@@ -83,11 +85,15 @@ export function useTemplatesPage() {
83
85
  const nextTotal = Math.max(0, Math.floor(root ? readNumber(root, 'total', 'totalCount', 'total_count') ?? nextRows.length : nextRows.length))
84
86
  const nextTotalPages = Math.max(1, Math.floor(root ? readNumber(root, 'totalPages', 'total_pages') ?? Math.ceil(nextTotal / nextPageSize) : 1))
85
87
  const returnedPage = Math.max(1, Math.floor(root ? readNumber(root, 'page') ?? page : page))
88
+ const nextTotalIsCapped = root ? readBoolean(root, 'totalIsCapped', 'total_is_capped') ?? false : false
86
89
  setRows(nextRows)
87
90
  setTotal(nextTotal)
88
91
  setTotalPages(nextTotalPages)
92
+ setTotalIsCapped(nextTotalIsCapped)
89
93
  if (nextPageSize !== pageSize) setPageSizeState(nextPageSize)
90
- if (Math.min(returnedPage, nextTotalPages) !== page) setPage(Math.min(returnedPage, nextTotalPages))
94
+ // A capped totalPages is a floor, so clamping to it would bounce the
95
+ // user off pages that exist past the cap.
96
+ if (!nextTotalIsCapped && Math.min(returnedPage, nextTotalPages) !== page) setPage(Math.min(returnedPage, nextTotalPages))
91
97
  const capabilities = readRecord(root?.capabilities)
92
98
  setCanManageTemplates(capabilities ? readBoolean(capabilities, 'canManageTemplates', 'can_manage_templates') ?? false : false)
93
99
  })
@@ -96,6 +102,7 @@ export function useTemplatesPage() {
96
102
  setRows([])
97
103
  setTotal(0)
98
104
  setTotalPages(1)
105
+ setTotalIsCapped(false)
99
106
  setCanManageTemplates(false)
100
107
  setLoadError(t('documents.templates.error.load'))
101
108
  })
@@ -135,6 +142,7 @@ export function useTemplatesPage() {
135
142
  setPageSize: changePageSize,
136
143
  total,
137
144
  totalPages,
145
+ totalIsCapped,
138
146
  search,
139
147
  setSearch: changeSearch,
140
148
  isLoading,
@@ -21,7 +21,7 @@ import {
21
21
  type FolderRow,
22
22
  type CollectionCapabilities,
23
23
  } from './documentsListTypes'
24
- import { readNumber, readRecord } from './documentUi'
24
+ import { readBoolean, readNumber, readRecord } from './documentUi'
25
25
 
26
26
  export function useDocumentsList() {
27
27
  const t = useT()
@@ -36,6 +36,7 @@ export function useDocumentsList() {
36
36
  const [pageSize, setPageSize] = React.useState(25)
37
37
  const [total, setTotal] = React.useState(0)
38
38
  const [totalPages, setTotalPages] = React.useState(1)
39
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
39
40
  const [search, setSearch] = React.useState('')
40
41
  const [archivedFilter, setArchivedFilter] = React.useState<'exclude' | 'include' | 'only'>('exclude')
41
42
  const [favoritesOnly, setFavoritesOnly] = React.useState(false)
@@ -73,6 +74,7 @@ export function useDocumentsList() {
73
74
  setFolders([])
74
75
  setTotal(0)
75
76
  setTotalPages(1)
77
+ setTotalIsCapped(false)
76
78
  setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES)
77
79
  setLoadError(t('documents.list.error.load'))
78
80
  return
@@ -86,12 +88,14 @@ export function useDocumentsList() {
86
88
  setCollectionCapabilities(normalizeCollectionCapabilities(documentsCall.result))
87
89
  setTotal(nextTotal)
88
90
  setTotalPages(root ? readNumber(root, 'totalPages', 'total_pages') ?? Math.max(1, Math.ceil(nextTotal / pageSize)) : 1)
91
+ setTotalIsCapped(root ? readBoolean(root, 'totalIsCapped', 'total_is_capped') ?? false : false)
89
92
  }).catch(() => {
90
93
  if (requestId.current !== currentRequestId) return
91
94
  setRows([])
92
95
  setFolders([])
93
96
  setTotal(0)
94
97
  setTotalPages(1)
98
+ setTotalIsCapped(false)
95
99
  setCollectionCapabilities(EMPTY_COLLECTION_CAPABILITIES)
96
100
  setLoadError(t('documents.list.error.load'))
97
101
  }).finally(() => {
@@ -297,7 +301,7 @@ export function useDocumentsList() {
297
301
 
298
302
  return {
299
303
  rows, folders, selectedFolderId, setSelectedFolderId, page, setPage, pageSize, setPageSize,
300
- total, totalPages, search, setSearch, isLoading, isCreating, loadError, hasTemplates, collectionCapabilities, refresh,
304
+ total, totalPages, totalIsCapped, search, setSearch, isLoading, isCreating, loadError, hasTemplates, collectionCapabilities, refresh,
301
305
  archivedFilter, setArchivedFilter, favoritesOnly, setFavoritesOnly,
302
306
  createDocument, deleteDocument, moveDocument, saveFolder, deleteFolder, ConfirmDialogElement,
303
307
  toggleFavorite, duplicateDocument, archiveToggle,