@proofkit/cli 1.0.0-beta.0
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.
- package/CHANGELOG.md +120 -0
- package/LICENSE.md +21 -0
- package/README.md +19 -0
- package/dist/acorn-AKFTBDM6.js +15 -0
- package/dist/angular-BOQ6FHSU.js +2 -0
- package/dist/babel-ZTOORN7K.js +15 -0
- package/dist/chunk-4LISTI44.js +1 -0
- package/dist/estree-KOJPX4S6.js +36 -0
- package/dist/flow-RCI44GYZ.js +19 -0
- package/dist/glimmer-GV5EF5E4.js +30 -0
- package/dist/graphql-YXQNPQWM.js +29 -0
- package/dist/html-ZAJTRROK.js +22 -0
- package/dist/index.js +300 -0
- package/dist/markdown-Q75DTQI7.js +63 -0
- package/dist/meriyah-32K7GBV5.js +4 -0
- package/dist/postcss-WWYO4PGL.js +54 -0
- package/dist/typescript-M6N7JDNQ.js +20 -0
- package/dist/yaml-LY7PNAYV.js +161 -0
- package/index.d.ts +19 -0
- package/package.json +122 -0
- package/template/extras/_cursor/conditional-rules/nextjs-framework.mdc +51 -0
- package/template/extras/_cursor/conditional-rules/npm.mdc +60 -0
- package/template/extras/_cursor/conditional-rules/pnpm.mdc +65 -0
- package/template/extras/_cursor/conditional-rules/yarn.mdc +60 -0
- package/template/extras/_cursor/rules/cursor-rules.mdc +88 -0
- package/template/extras/_cursor/rules/filemaker-api.mdc +176 -0
- package/template/extras/_cursor/rules/troubleshooting-patterns.mdc +240 -0
- package/template/extras/_cursor/rules/ui-components.mdc +57 -0
- package/template/extras/config/_eslint.js +27 -0
- package/template/extras/config/_prettier.config.js +6 -0
- package/template/extras/config/drizzle-config-mysql.ts +12 -0
- package/template/extras/config/drizzle-config-postgres.ts +12 -0
- package/template/extras/config/drizzle-config-sqlite.ts +12 -0
- package/template/extras/config/fmschema.config.mjs +9 -0
- package/template/extras/config/get-query-client.ts +6 -0
- package/template/extras/config/postcss.config.cjs +7 -0
- package/template/extras/config/query-provider-vite.tsx +19 -0
- package/template/extras/config/query-provider.tsx +21 -0
- package/template/extras/emailProviders/none/email.tsx +24 -0
- package/template/extras/emailProviders/plunk/email.tsx +26 -0
- package/template/extras/emailProviders/plunk/service.ts +4 -0
- package/template/extras/emailProviders/resend/email.tsx +23 -0
- package/template/extras/emailProviders/resend/service.ts +4 -0
- package/template/extras/fmaddon-auth/app/(main)/auth/profile/actions.ts +93 -0
- package/template/extras/fmaddon-auth/app/(main)/auth/profile/page.tsx +27 -0
- package/template/extras/fmaddon-auth/app/(main)/auth/profile/profile-form.tsx +56 -0
- package/template/extras/fmaddon-auth/app/(main)/auth/profile/reset-password-form.tsx +110 -0
- package/template/extras/fmaddon-auth/app/(main)/auth/profile/schema.ts +19 -0
- package/template/extras/fmaddon-auth/app/auth/forgot-password/actions.ts +37 -0
- package/template/extras/fmaddon-auth/app/auth/forgot-password/forgot-form.tsx +41 -0
- package/template/extras/fmaddon-auth/app/auth/forgot-password/page.tsx +21 -0
- package/template/extras/fmaddon-auth/app/auth/forgot-password/schema.ts +5 -0
- package/template/extras/fmaddon-auth/app/auth/login/actions.ts +34 -0
- package/template/extras/fmaddon-auth/app/auth/login/login-form.tsx +64 -0
- package/template/extras/fmaddon-auth/app/auth/login/page.tsx +26 -0
- package/template/extras/fmaddon-auth/app/auth/login/schema.ts +6 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/actions.ts +50 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/page.tsx +32 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/reset-password-form.tsx +59 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/schema.ts +14 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/actions.ts +45 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/page.tsx +32 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/schema.ts +5 -0
- package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/verify-email-form.tsx +48 -0
- package/template/extras/fmaddon-auth/app/auth/signup/actions.ts +49 -0
- package/template/extras/fmaddon-auth/app/auth/signup/page.tsx +26 -0
- package/template/extras/fmaddon-auth/app/auth/signup/schema.ts +12 -0
- package/template/extras/fmaddon-auth/app/auth/signup/signup-form.tsx +67 -0
- package/template/extras/fmaddon-auth/app/auth/verify-email/actions.ts +110 -0
- package/template/extras/fmaddon-auth/app/auth/verify-email/email-verification-form.tsx +45 -0
- package/template/extras/fmaddon-auth/app/auth/verify-email/page.tsx +38 -0
- package/template/extras/fmaddon-auth/app/auth/verify-email/resend-button.tsx +35 -0
- package/template/extras/fmaddon-auth/app/auth/verify-email/schema.ts +5 -0
- package/template/extras/fmaddon-auth/components/auth/actions.ts +16 -0
- package/template/extras/fmaddon-auth/components/auth/protect.tsx +17 -0
- package/template/extras/fmaddon-auth/components/auth/redirect.tsx +26 -0
- package/template/extras/fmaddon-auth/components/auth/use-user.ts +59 -0
- package/template/extras/fmaddon-auth/components/auth/user-menu.tsx +51 -0
- package/template/extras/fmaddon-auth/emails/auth-code.tsx +156 -0
- package/template/extras/fmaddon-auth/middleware.ts +45 -0
- package/template/extras/fmaddon-auth/server/auth/utils/email-verification.ts +136 -0
- package/template/extras/fmaddon-auth/server/auth/utils/encryption.ts +51 -0
- package/template/extras/fmaddon-auth/server/auth/utils/index.ts +16 -0
- package/template/extras/fmaddon-auth/server/auth/utils/password-reset.ts +152 -0
- package/template/extras/fmaddon-auth/server/auth/utils/password.ts +67 -0
- package/template/extras/fmaddon-auth/server/auth/utils/redirect.ts +8 -0
- package/template/extras/fmaddon-auth/server/auth/utils/session.ts +192 -0
- package/template/extras/fmaddon-auth/server/auth/utils/user.ts +147 -0
- package/template/extras/prisma/schema/base-planetscale.prisma +24 -0
- package/template/extras/prisma/schema/base.prisma +20 -0
- package/template/extras/prisma/schema/with-auth-planetscale.prisma +77 -0
- package/template/extras/prisma/schema/with-auth.prisma +74 -0
- package/template/extras/src/app/_components/post-tw.tsx +50 -0
- package/template/extras/src/app/_components/post.tsx +54 -0
- package/template/extras/src/app/api/auth/[...nextauth]/route.ts +4 -0
- package/template/extras/src/app/api/trpc/[trpc]/route.ts +34 -0
- package/template/extras/src/app/clerk-auth/layout.tsx +10 -0
- package/template/extras/src/app/clerk-auth/signin/[[...sign-in]]/page.tsx +5 -0
- package/template/extras/src/app/clerk-auth/signup/[[...sign-up]]/page.tsx +5 -0
- package/template/extras/src/app/layout/base.tsx +34 -0
- package/template/extras/src/app/layout/main-shell.tsx +37 -0
- package/template/extras/src/app/layout/with-trpc-tw.tsx +24 -0
- package/template/extras/src/app/layout/with-trpc.tsx +24 -0
- package/template/extras/src/app/layout/with-tw.tsx +20 -0
- package/template/extras/src/app/next-auth/layout.tsx +22 -0
- package/template/extras/src/app/next-auth/signin/page.tsx +82 -0
- package/template/extras/src/app/next-auth/signup/action.ts +24 -0
- package/template/extras/src/app/next-auth/signup/page.tsx +40 -0
- package/template/extras/src/app/next-auth/signup/validation.ts +12 -0
- package/template/extras/src/app/page/base.tsx +6 -0
- package/template/extras/src/app/page/with-auth-trpc-tw.tsx +67 -0
- package/template/extras/src/app/page/with-auth-trpc.tsx +68 -0
- package/template/extras/src/app/page/with-trpc-tw.tsx +53 -0
- package/template/extras/src/app/page/with-trpc.tsx +54 -0
- package/template/extras/src/app/page/with-tw.tsx +37 -0
- package/template/extras/src/components/clerk-auth/clerk-provider.tsx +18 -0
- package/template/extras/src/components/clerk-auth/user-menu-mobile.tsx +36 -0
- package/template/extras/src/components/clerk-auth/user-menu.tsx +24 -0
- package/template/extras/src/components/next-auth/next-auth-provider.tsx +14 -0
- package/template/extras/src/components/next-auth/user-menu-mobile.tsx +31 -0
- package/template/extras/src/components/next-auth/user-menu.tsx +38 -0
- package/template/extras/src/env/with-auth.ts +31 -0
- package/template/extras/src/env/with-clerk.ts +20 -0
- package/template/extras/src/index.module.css +177 -0
- package/template/extras/src/middleware/clerk.ts +20 -0
- package/template/extras/src/middleware/next-auth.ts +5 -0
- package/template/extras/src/pages/_app/base.tsx +14 -0
- package/template/extras/src/pages/_app/with-auth-trpc-tw.tsx +23 -0
- package/template/extras/src/pages/_app/with-auth-trpc.tsx +23 -0
- package/template/extras/src/pages/_app/with-auth-tw.tsx +21 -0
- package/template/extras/src/pages/_app/with-auth.tsx +21 -0
- package/template/extras/src/pages/_app/with-trpc-tw.tsx +16 -0
- package/template/extras/src/pages/_app/with-trpc.tsx +16 -0
- package/template/extras/src/pages/_app/with-tw.tsx +14 -0
- package/template/extras/src/pages/api/auth/[...nextauth].ts +5 -0
- package/template/extras/src/pages/api/trpc/[trpc].ts +19 -0
- package/template/extras/src/pages/index/base.tsx +47 -0
- package/template/extras/src/pages/index/with-auth-trpc-tw.tsx +80 -0
- package/template/extras/src/pages/index/with-auth-trpc.tsx +81 -0
- package/template/extras/src/pages/index/with-trpc-tw.tsx +52 -0
- package/template/extras/src/pages/index/with-trpc.tsx +53 -0
- package/template/extras/src/pages/index/with-tw.tsx +45 -0
- package/template/extras/src/server/api/root.ts +23 -0
- package/template/extras/src/server/api/routers/post/base.ts +40 -0
- package/template/extras/src/server/api/routers/post/with-auth-drizzle.ts +39 -0
- package/template/extras/src/server/api/routers/post/with-auth-prisma.ts +41 -0
- package/template/extras/src/server/api/routers/post/with-auth.ts +37 -0
- package/template/extras/src/server/api/routers/post/with-drizzle.ts +30 -0
- package/template/extras/src/server/api/routers/post/with-prisma.ts +31 -0
- package/template/extras/src/server/api/trpc-app/base.ts +103 -0
- package/template/extras/src/server/api/trpc-app/with-auth-db.ts +133 -0
- package/template/extras/src/server/api/trpc-app/with-auth.ts +130 -0
- package/template/extras/src/server/api/trpc-app/with-db.ts +106 -0
- package/template/extras/src/server/api/trpc-pages/base.ts +122 -0
- package/template/extras/src/server/api/trpc-pages/with-auth-db.ts +160 -0
- package/template/extras/src/server/api/trpc-pages/with-auth.ts +158 -0
- package/template/extras/src/server/api/trpc-pages/with-db.ts +125 -0
- package/template/extras/src/server/data/users.ts +23 -0
- package/template/extras/src/server/db/db-prisma-planetscale.ts +22 -0
- package/template/extras/src/server/db/db-prisma.ts +17 -0
- package/template/extras/src/server/db/index-drizzle/with-mysql.ts +18 -0
- package/template/extras/src/server/db/index-drizzle/with-planetscale.ts +7 -0
- package/template/extras/src/server/db/index-drizzle/with-postgres.ts +18 -0
- package/template/extras/src/server/db/index-drizzle/with-sqlite.ts +19 -0
- package/template/extras/src/server/db/schema-drizzle/base-mysql.ts +34 -0
- package/template/extras/src/server/db/schema-drizzle/base-planetscale.ts +34 -0
- package/template/extras/src/server/db/schema-drizzle/base-postgres.ts +36 -0
- package/template/extras/src/server/db/schema-drizzle/base-sqlite.ts +30 -0
- package/template/extras/src/server/db/schema-drizzle/with-auth-mysql.ts +123 -0
- package/template/extras/src/server/db/schema-drizzle/with-auth-planetscale.ts +117 -0
- package/template/extras/src/server/db/schema-drizzle/with-auth-postgres.ts +130 -0
- package/template/extras/src/server/db/schema-drizzle/with-auth-sqlite.ts +116 -0
- package/template/extras/src/server/next-auth/base.ts +111 -0
- package/template/extras/src/server/next-auth/password.ts +13 -0
- package/template/extras/src/server/next-auth/with-drizzle.ts +83 -0
- package/template/extras/src/server/next-auth/with-prisma.ts +72 -0
- package/template/extras/src/trpc/query-client.ts +25 -0
- package/template/extras/src/trpc/react.tsx +76 -0
- package/template/extras/src/trpc/server.ts +30 -0
- package/template/extras/src/utils/api.ts +68 -0
- package/template/extras/start-database/mysql.sh +54 -0
- package/template/extras/start-database/postgres.sh +55 -0
- package/template/fm-addon/ProofKitAuth/de.xml +518 -0
- package/template/fm-addon/ProofKitAuth/en.xml +518 -0
- package/template/fm-addon/ProofKitAuth/es.xml +518 -0
- package/template/fm-addon/ProofKitAuth/fr.xml +518 -0
- package/template/fm-addon/ProofKitAuth/icon.png +0 -0
- package/template/fm-addon/ProofKitAuth/icon@2x.png +0 -0
- package/template/fm-addon/ProofKitAuth/info.json +11 -0
- package/template/fm-addon/ProofKitAuth/info_de.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_en.json +8 -0
- package/template/fm-addon/ProofKitAuth/info_es.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_fr.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_it.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_ja.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_ko.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_nl.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_pt.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_sv.json +18 -0
- package/template/fm-addon/ProofKitAuth/info_zh.json +18 -0
- package/template/fm-addon/ProofKitAuth/it.xml +518 -0
- package/template/fm-addon/ProofKitAuth/ja.xml +518 -0
- package/template/fm-addon/ProofKitAuth/ko.xml +518 -0
- package/template/fm-addon/ProofKitAuth/nl.xml +518 -0
- package/template/fm-addon/ProofKitAuth/preview.png +0 -0
- package/template/fm-addon/ProofKitAuth/pt.xml +518 -0
- package/template/fm-addon/ProofKitAuth/sv.xml +518 -0
- package/template/fm-addon/ProofKitAuth/template.xml +0 -0
- package/template/fm-addon/ProofKitAuth/zh.xml +518 -0
- package/template/fm-addon/ProofKitWV/de.xml +896 -0
- package/template/fm-addon/ProofKitWV/en.xml +896 -0
- package/template/fm-addon/ProofKitWV/es.xml +896 -0
- package/template/fm-addon/ProofKitWV/fr.xml +896 -0
- package/template/fm-addon/ProofKitWV/icon.png +0 -0
- package/template/fm-addon/ProofKitWV/icon@2x.png +0 -0
- package/template/fm-addon/ProofKitWV/info.json +11 -0
- package/template/fm-addon/ProofKitWV/info_de.json +18 -0
- package/template/fm-addon/ProofKitWV/info_en.json +11 -0
- package/template/fm-addon/ProofKitWV/info_es.json +18 -0
- package/template/fm-addon/ProofKitWV/info_fr.json +18 -0
- package/template/fm-addon/ProofKitWV/info_it.json +18 -0
- package/template/fm-addon/ProofKitWV/info_ja.json +18 -0
- package/template/fm-addon/ProofKitWV/info_ko.json +18 -0
- package/template/fm-addon/ProofKitWV/info_nl.json +18 -0
- package/template/fm-addon/ProofKitWV/info_pt.json +18 -0
- package/template/fm-addon/ProofKitWV/info_sv.json +18 -0
- package/template/fm-addon/ProofKitWV/info_zh.json +18 -0
- package/template/fm-addon/ProofKitWV/it.xml +896 -0
- package/template/fm-addon/ProofKitWV/ja.xml +896 -0
- package/template/fm-addon/ProofKitWV/ko.xml +896 -0
- package/template/fm-addon/ProofKitWV/nl.xml +896 -0
- package/template/fm-addon/ProofKitWV/preview.png +0 -0
- package/template/fm-addon/ProofKitWV/pt.xml +896 -0
- package/template/fm-addon/ProofKitWV/records_de.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_en.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_es.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_fr.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_it.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_ja.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_ko.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_nl.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_pt.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_sv.xml +0 -0
- package/template/fm-addon/ProofKitWV/records_zh.xml +0 -0
- package/template/fm-addon/ProofKitWV/sv.xml +896 -0
- package/template/fm-addon/ProofKitWV/template.xml +0 -0
- package/template/fm-addon/ProofKitWV/zh.xml +896 -0
- package/template/nextjs/README.md +27 -0
- package/template/nextjs/_gitignore +37 -0
- package/template/nextjs/next.config.ts +12 -0
- package/template/nextjs/package.json +50 -0
- package/template/nextjs/postcss.config.cjs +14 -0
- package/template/nextjs/proofkit.json +1 -0
- package/template/nextjs/public/favicon.ico +0 -0
- package/template/nextjs/public/proofkit.png +0 -0
- package/template/nextjs/src/app/(main)/layout.tsx +6 -0
- package/template/nextjs/src/app/(main)/page.tsx +90 -0
- package/template/nextjs/src/app/layout.tsx +39 -0
- package/template/nextjs/src/app/navigation.tsx +12 -0
- package/template/nextjs/src/components/AppLogo.tsx +6 -0
- package/template/nextjs/src/components/AppShell/internal/AppShell.tsx +21 -0
- package/template/nextjs/src/components/AppShell/internal/Header.module.css +40 -0
- package/template/nextjs/src/components/AppShell/internal/Header.tsx +34 -0
- package/template/nextjs/src/components/AppShell/internal/HeaderMobileMenu.tsx +27 -0
- package/template/nextjs/src/components/AppShell/internal/HeaderNavLink.tsx +31 -0
- package/template/nextjs/src/components/AppShell/internal/config.ts +1 -0
- package/template/nextjs/src/components/AppShell/slot-header-center.tsx +13 -0
- package/template/nextjs/src/components/AppShell/slot-header-left.tsx +23 -0
- package/template/nextjs/src/components/AppShell/slot-header-mobile-content.tsx +43 -0
- package/template/nextjs/src/components/AppShell/slot-header-right.tsx +26 -0
- package/template/nextjs/src/config/env.ts +13 -0
- package/template/nextjs/src/config/theme/globals.css +1 -0
- package/template/nextjs/src/config/theme/mantine-theme.ts +22 -0
- package/template/nextjs/src/server/safe-action.ts +3 -0
- package/template/nextjs/src/utils/notification-helpers.ts +32 -0
- package/template/nextjs/tsconfig.json +40 -0
- package/template/pages/nextjs/blank/page.tsx +5 -0
- package/template/pages/nextjs/table/page.tsx +17 -0
- package/template/pages/nextjs/table/table.tsx +18 -0
- package/template/pages/nextjs/table-edit/actions.ts +23 -0
- package/template/pages/nextjs/table-edit/page.tsx +28 -0
- package/template/pages/nextjs/table-edit/schema.ts +4 -0
- package/template/pages/nextjs/table-edit/table.tsx +43 -0
- package/template/pages/nextjs/table-infinite/actions.ts +62 -0
- package/template/pages/nextjs/table-infinite/page.tsx +11 -0
- package/template/pages/nextjs/table-infinite/query.ts +44 -0
- package/template/pages/nextjs/table-infinite/table.tsx +107 -0
- package/template/pages/nextjs/table-infinite-edit/actions.ts +84 -0
- package/template/pages/nextjs/table-infinite-edit/page.tsx +23 -0
- package/template/pages/nextjs/table-infinite-edit/query.ts +81 -0
- package/template/pages/nextjs/table-infinite-edit/schema.ts +4 -0
- package/template/pages/nextjs/table-infinite-edit/table.tsx +130 -0
- package/template/pages/vite-wv/blank/index.tsx +0 -0
- package/template/pages/vite-wv/table/index.tsx +34 -0
- package/template/pages/vite-wv/table-edit/index.tsx +72 -0
- package/template/vite-wv/.vscode/settings.json +11 -0
- package/template/vite-wv/_gitignore +18 -0
- package/template/vite-wv/index.html +13 -0
- package/template/vite-wv/package.json +52 -0
- package/template/vite-wv/pnpm-lock.yaml +2294 -0
- package/template/vite-wv/postcss.config.cjs +14 -0
- package/template/vite-wv/proofkit.json +1 -0
- package/template/vite-wv/scripts/launch-fm.sh +3 -0
- package/template/vite-wv/scripts/upload.js +21 -0
- package/template/vite-wv/src/components/AppLogo.tsx +5 -0
- package/template/vite-wv/src/components/full-screen-loader.tsx +9 -0
- package/template/vite-wv/src/config/env.ts +16 -0
- package/template/vite-wv/src/config/theme/globals.css +1 -0
- package/template/vite-wv/src/config/theme/mantine-theme.ts +22 -0
- package/template/vite-wv/src/main.tsx +42 -0
- package/template/vite-wv/src/routeTree.gen.ts +111 -0
- package/template/vite-wv/src/routes/__root.tsx +21 -0
- package/template/vite-wv/src/routes/index.tsx +63 -0
- package/template/vite-wv/src/routes/secondary.tsx +28 -0
- package/template/vite-wv/src/utils/notification-helpers.ts +32 -0
- package/template/vite-wv/tsconfig.json +14 -0
- package/template/vite-wv/vite.config.ts +18 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": [
|
|
4
|
+
"dom",
|
|
5
|
+
"dom.iterable",
|
|
6
|
+
"esnext"
|
|
7
|
+
],
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"module": "esnext",
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"jsx": "preserve",
|
|
18
|
+
"incremental": true,
|
|
19
|
+
"plugins": [
|
|
20
|
+
{
|
|
21
|
+
"name": "next"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"paths": {
|
|
25
|
+
"@/*": [
|
|
26
|
+
"./src/*"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"target": "ES2017"
|
|
30
|
+
},
|
|
31
|
+
"include": [
|
|
32
|
+
"next-env.d.ts",
|
|
33
|
+
"**/*.ts",
|
|
34
|
+
"**/*.tsx",
|
|
35
|
+
".next/types/**/*.ts"
|
|
36
|
+
],
|
|
37
|
+
"exclude": [
|
|
38
|
+
"node_modules"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { __CLIENT_NAME__ } from "@/config/schemas/__SOURCE_NAME__/client";
|
|
2
|
+
import { Stack } from "@mantine/core";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
import TableContent from "./table";
|
|
6
|
+
|
|
7
|
+
export default async function TablePage() {
|
|
8
|
+
// this function is limited to 100 records by default. To load more, see the other table templates from the docs
|
|
9
|
+
const { data } = await __CLIENT_NAME__.list({
|
|
10
|
+
fetch: { next: { revalidate: 60 } }, // only call the database at most once every 60 seconds
|
|
11
|
+
});
|
|
12
|
+
return (
|
|
13
|
+
<Stack>
|
|
14
|
+
<TableContent data={data.map((d) => d.fieldData)} />
|
|
15
|
+
</Stack>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { __TYPE_NAME__ } from "@/config/schemas/__SOURCE_NAME__/__SCHEMA_NAME__";
|
|
4
|
+
import {
|
|
5
|
+
MantineReactTable,
|
|
6
|
+
MRT_ColumnDef,
|
|
7
|
+
useMantineReactTable,
|
|
8
|
+
} from "mantine-react-table";
|
|
9
|
+
import React from "react";
|
|
10
|
+
|
|
11
|
+
type TData = __TYPE_NAME__;
|
|
12
|
+
|
|
13
|
+
const columns: MRT_ColumnDef<TData>[] = [];
|
|
14
|
+
|
|
15
|
+
export default function MyTable({ data }: { data: TData[] }) {
|
|
16
|
+
const table = useMantineReactTable({ data, columns });
|
|
17
|
+
return <MantineReactTable table={table} />;
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import { __CLIENT_NAME__ } from "@/config/schemas/__SOURCE_NAME__/client";
|
|
4
|
+
import { __ZOD_TYPE_NAME__ } from "@/config/schemas/__SOURCE_NAME__/__SCHEMA_NAME__";
|
|
5
|
+
import { __ACTION_CLIENT__ } from "@/server/safe-action";
|
|
6
|
+
import { idFieldName } from "./schema";
|
|
7
|
+
|
|
8
|
+
export const updateRecord = __ACTION_CLIENT__
|
|
9
|
+
.schema(__ZOD_TYPE_NAME__.partial())
|
|
10
|
+
.action(async ({ parsedInput }) => {
|
|
11
|
+
const id = parsedInput[idFieldName];
|
|
12
|
+
delete parsedInput[idFieldName]; // this ensures the id field value is not included in the updated fieldData
|
|
13
|
+
const data = parsedInput;
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
data: { recordId },
|
|
17
|
+
} = await __CLIENT_NAME__.findOne({ query: { [idFieldName]: `==${id}` } });
|
|
18
|
+
|
|
19
|
+
return await __CLIENT_NAME__.update({
|
|
20
|
+
recordId,
|
|
21
|
+
fieldData: data,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { __CLIENT_NAME__ } from "@/config/schemas/__SOURCE_NAME__/client";
|
|
2
|
+
import { Stack, Text, Code } from "@mantine/core";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
import TableContent from "./table";
|
|
6
|
+
import { idFieldName } from "./schema";
|
|
7
|
+
|
|
8
|
+
export default async function TablePage() {
|
|
9
|
+
// this function is limited to 100 records by default. To load more, see the other table templates from the docs
|
|
10
|
+
const { data } = await __CLIENT_NAME__.list({
|
|
11
|
+
fetch: { next: { revalidate: 60 } }, // only call the database at most once every 60 seconds
|
|
12
|
+
});
|
|
13
|
+
return (
|
|
14
|
+
<Stack>
|
|
15
|
+
<div>
|
|
16
|
+
<Text>
|
|
17
|
+
This table allows editing. Double-click on a cell to edit the value.
|
|
18
|
+
</Text>
|
|
19
|
+
<Text size="sm" c="dimmed">
|
|
20
|
+
NOTE: This feature requires a primary key field on your API layout. If your
|
|
21
|
+
primary key field is not <Code>{idFieldName}</Code>, update the
|
|
22
|
+
<Code>idFieldName</Code> variable in the <Code>schema.ts</Code> file.
|
|
23
|
+
</Text>
|
|
24
|
+
</div>
|
|
25
|
+
<TableContent data={data.map((d) => d.fieldData)} />
|
|
26
|
+
</Stack>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type __TYPE_NAME__ } from "@/config/schemas/__SOURCE_NAME__/__SCHEMA_NAME__";
|
|
4
|
+
import {
|
|
5
|
+
MantineReactTable,
|
|
6
|
+
type MRT_Cell,
|
|
7
|
+
type MRT_ColumnDef,
|
|
8
|
+
useMantineReactTable,
|
|
9
|
+
} from "mantine-react-table";
|
|
10
|
+
import React from "react";
|
|
11
|
+
import { updateRecord } from "./actions";
|
|
12
|
+
import { showErrorNotification } from "@/utils/notification-helpers";
|
|
13
|
+
import { idFieldName } from "./schema";
|
|
14
|
+
|
|
15
|
+
type TData = __TYPE_NAME__;
|
|
16
|
+
|
|
17
|
+
const columns: MRT_ColumnDef<TData>[] = [];
|
|
18
|
+
|
|
19
|
+
async function handleSaveCell(cell: MRT_Cell<TData>, value: unknown) {
|
|
20
|
+
const resp = await updateRecord({
|
|
21
|
+
[idFieldName]: cell.row.id,
|
|
22
|
+
[cell.column.id]: value,
|
|
23
|
+
});
|
|
24
|
+
if (!resp?.data) {
|
|
25
|
+
showErrorNotification("Failed to update record");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default function MyTable({ data }: { data: TData[] }) {
|
|
30
|
+
const table = useMantineReactTable({
|
|
31
|
+
data,
|
|
32
|
+
columns,
|
|
33
|
+
enableEditing: true,
|
|
34
|
+
editDisplayMode: "cell",
|
|
35
|
+
getRowId: (row) => row[idFieldName],
|
|
36
|
+
mantineEditTextInputProps: ({ cell }) => ({
|
|
37
|
+
//onBlur is more efficient, but could use onChange instead
|
|
38
|
+
onBlur: (event) => {
|
|
39
|
+
handleSaveCell(cell, event.target.value);
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
}); return <MantineReactTable table={table} />;
|
|
43
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import { __TYPE_NAME__ } from "@/config/schemas/__SOURCE_NAME__/__SCHEMA_NAME__";
|
|
4
|
+
import { __CLIENT_NAME__ } from "@/config/schemas/__SOURCE_NAME__/client";
|
|
5
|
+
import { __ACTION_CLIENT__ } from "@/server/safe-action";
|
|
6
|
+
import { ListParams, Query } from "@proofkit/fmdapi/dist/client-types.js";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import { z } from "zod/v4";
|
|
9
|
+
|
|
10
|
+
const limit = 50; // raise or lower this number depending on how your layout performs
|
|
11
|
+
export const fetchData = __ACTION_CLIENT__
|
|
12
|
+
.schema(
|
|
13
|
+
z.object({
|
|
14
|
+
offset: z.number().catch(0),
|
|
15
|
+
sorting: z.array(
|
|
16
|
+
z.object({ id: z.string(), desc: z.boolean().default(false) })
|
|
17
|
+
),
|
|
18
|
+
columnFilters: z.array(z.object({ id: z.string(), value: z.unknown() })),
|
|
19
|
+
})
|
|
20
|
+
)
|
|
21
|
+
.action(async ({ parsedInput: { offset, sorting, columnFilters } }) => {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
const getOptions: ListParams<__TYPE_NAME__, any> & {
|
|
24
|
+
query: Query<__TYPE_NAME__>[];
|
|
25
|
+
} = {
|
|
26
|
+
limit,
|
|
27
|
+
offset,
|
|
28
|
+
query: [{ ["__FIRST_FIELD_NAME__"]: "*" }],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (sorting.length > 0) {
|
|
32
|
+
getOptions.sort = sorting.map(({ id, desc }) => ({
|
|
33
|
+
fieldName: id as keyof __TYPE_NAME__,
|
|
34
|
+
sortOrder: desc ? "descend" : "ascend",
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (columnFilters.length > 0) {
|
|
39
|
+
getOptions.query = columnFilters
|
|
40
|
+
.map(({ id, value }) => {
|
|
41
|
+
if (typeof value === "string") {
|
|
42
|
+
return {
|
|
43
|
+
[id]: value,
|
|
44
|
+
};
|
|
45
|
+
} else if (typeof value === "object" && value instanceof Date) {
|
|
46
|
+
return {
|
|
47
|
+
[id]: dayjs(value).format("YYYY+MM+DD"),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
})
|
|
52
|
+
.filter(Boolean) as Query<any>[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const data = await __CLIENT_NAME__.find(getOptions);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
data: data.data,
|
|
59
|
+
hasNextPage: data.dataInfo.foundCount > limit + offset,
|
|
60
|
+
totalCount: data.dataInfo.foundCount,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
4
|
+
import { fetchData } from "./actions";
|
|
5
|
+
import { useMemo } from "react";
|
|
6
|
+
import type {
|
|
7
|
+
MRT_SortingState,
|
|
8
|
+
MRT_ColumnFiltersState,
|
|
9
|
+
} from "mantine-react-table";
|
|
10
|
+
|
|
11
|
+
export function useAllData({
|
|
12
|
+
sorting,
|
|
13
|
+
columnFilters,
|
|
14
|
+
}: {
|
|
15
|
+
sorting: MRT_SortingState;
|
|
16
|
+
columnFilters: MRT_ColumnFiltersState;
|
|
17
|
+
}) {
|
|
18
|
+
// useInfiniteQuery is used to help with automatic pagination
|
|
19
|
+
const qr = useInfiniteQuery({
|
|
20
|
+
queryKey: ["all-__SCHEMA_NAME__", sorting, columnFilters],
|
|
21
|
+
queryFn: async ({ pageParam: offset }) => {
|
|
22
|
+
const result = await fetchData({ offset, sorting, columnFilters });
|
|
23
|
+
if (!result) throw new Error(`Failed to fetch __SCHEMA_NAME__`);
|
|
24
|
+
if (!result.data) throw new Error(`No data found for __SCHEMA_NAME__`);
|
|
25
|
+
return result?.data;
|
|
26
|
+
},
|
|
27
|
+
retry: false,
|
|
28
|
+
initialPageParam: 0,
|
|
29
|
+
getNextPageParam: (lastPage, pages) =>
|
|
30
|
+
lastPage.hasNextPage
|
|
31
|
+
? pages.flatMap((page) => page.data).length
|
|
32
|
+
: undefined,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const flatData = useMemo(
|
|
36
|
+
() =>
|
|
37
|
+
qr.data?.pages.flatMap((page) => page.data).map((o) => o.fieldData) ?? [],
|
|
38
|
+
[qr.data]
|
|
39
|
+
);
|
|
40
|
+
const totalFetched = flatData.length;
|
|
41
|
+
const totalDBRowCount = qr.data?.pages?.[0]?.totalCount ?? 0;
|
|
42
|
+
|
|
43
|
+
return { ...qr, data: flatData, totalDBRowCount, totalFetched };
|
|
44
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { __TYPE_NAME__ } from "@/config/schemas/__SOURCE_NAME__/__SCHEMA_NAME__";
|
|
4
|
+
import {
|
|
5
|
+
createMRTColumnHelper,
|
|
6
|
+
MantineReactTable,
|
|
7
|
+
MRT_ColumnDef,
|
|
8
|
+
MRT_ColumnFiltersState,
|
|
9
|
+
MRT_RowVirtualizer,
|
|
10
|
+
MRT_SortingState,
|
|
11
|
+
useMantineReactTable,
|
|
12
|
+
} from "mantine-react-table";
|
|
13
|
+
import React, {
|
|
14
|
+
type UIEvent,
|
|
15
|
+
useCallback,
|
|
16
|
+
useEffect,
|
|
17
|
+
useRef,
|
|
18
|
+
useState,
|
|
19
|
+
} from "react";
|
|
20
|
+
import { useAllData } from "./query";
|
|
21
|
+
import { Text } from "@mantine/core";
|
|
22
|
+
|
|
23
|
+
type TData = __TYPE_NAME__;
|
|
24
|
+
|
|
25
|
+
const columns: MRT_ColumnDef<TData>[] = [];
|
|
26
|
+
|
|
27
|
+
export default function MyTable() {
|
|
28
|
+
const tableContainerRef = useRef<HTMLDivElement>(null);
|
|
29
|
+
const rowVirtualizerInstanceRef =
|
|
30
|
+
useRef<MRT_RowVirtualizer<HTMLDivElement, HTMLTableRowElement>>(null);
|
|
31
|
+
|
|
32
|
+
const [sorting, setSorting] = useState<MRT_SortingState>([]);
|
|
33
|
+
const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
|
|
34
|
+
[]
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const {
|
|
38
|
+
data,
|
|
39
|
+
totalDBRowCount,
|
|
40
|
+
totalFetched,
|
|
41
|
+
isLoading,
|
|
42
|
+
isFetching,
|
|
43
|
+
fetchNextPage,
|
|
44
|
+
} = useAllData({ sorting, columnFilters });
|
|
45
|
+
|
|
46
|
+
const table = useMantineReactTable({
|
|
47
|
+
data,
|
|
48
|
+
columns,
|
|
49
|
+
rowCount: totalDBRowCount,
|
|
50
|
+
enableRowVirtualization: true, // only render the rows that are visible on screen to improve performance
|
|
51
|
+
state: { isLoading, sorting, showProgressBars: isFetching, columnFilters },
|
|
52
|
+
enableGlobalFilter: false, // doesn't work as easily with server-side filters, it's better to filter the specific columns
|
|
53
|
+
onSortingChange: setSorting,
|
|
54
|
+
onColumnFiltersChange: setColumnFilters,
|
|
55
|
+
enablePagination: false, // hide pagination buttons
|
|
56
|
+
enableStickyHeader: true,
|
|
57
|
+
mantineBottomToolbarProps: { style: { alignItems: "center" } },
|
|
58
|
+
renderBottomToolbarCustomActions: () =>
|
|
59
|
+
!isLoading ? (
|
|
60
|
+
<Text px="sm">
|
|
61
|
+
Fetched {totalFetched} of {totalDBRowCount}
|
|
62
|
+
</Text>
|
|
63
|
+
) : null,
|
|
64
|
+
mantineTableContainerProps: ({ table }) => {
|
|
65
|
+
return {
|
|
66
|
+
h: table.getState().isFullScreen
|
|
67
|
+
? "100%"
|
|
68
|
+
: `calc(100vh - var(--app-shell-header-height) - 10rem)`, // may need to adjust this height if you have more elements on your page
|
|
69
|
+
ref: tableContainerRef,
|
|
70
|
+
onScroll: (
|
|
71
|
+
event: UIEvent<HTMLDivElement> //add an event listener to the table container element
|
|
72
|
+
) => fetchMoreOnBottomReached(event.target as HTMLDivElement),
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table
|
|
78
|
+
const fetchMoreOnBottomReached = useCallback(
|
|
79
|
+
(containerRefElement?: HTMLDivElement | null) => {
|
|
80
|
+
if (containerRefElement) {
|
|
81
|
+
const { scrollHeight, scrollTop, clientHeight } = containerRefElement;
|
|
82
|
+
// once the user has scrolled within 400px of the bottom of the table, fetch more data
|
|
83
|
+
if (
|
|
84
|
+
scrollHeight - scrollTop - clientHeight < 400 &&
|
|
85
|
+
!isFetching &&
|
|
86
|
+
totalFetched < totalDBRowCount
|
|
87
|
+
) {
|
|
88
|
+
void fetchNextPage();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
[fetchNextPage, isFetching, totalFetched, totalDBRowCount]
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// scroll to top of table when sorting or filters change
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (rowVirtualizerInstanceRef.current) {
|
|
98
|
+
try {
|
|
99
|
+
rowVirtualizerInstanceRef.current.scrollToIndex(0);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
console.error(e);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}, [sorting, columnFilters]);
|
|
105
|
+
|
|
106
|
+
return <MantineReactTable table={table} />;
|
|
107
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
__TYPE_NAME__,
|
|
5
|
+
__ZOD_TYPE_NAME__,
|
|
6
|
+
} from "@/config/schemas/__SOURCE_NAME__/__SCHEMA_NAME__";
|
|
7
|
+
import { __CLIENT_NAME__ } from "@/config/schemas/__SOURCE_NAME__/client";
|
|
8
|
+
import { __ACTION_CLIENT__ } from "@/server/safe-action";
|
|
9
|
+
import { ListParams, Query } from "@proofkit/fmdapi/dist/client-types.js";
|
|
10
|
+
import dayjs from "dayjs";
|
|
11
|
+
import { z } from "zod/v4";
|
|
12
|
+
|
|
13
|
+
import { idFieldName } from "./schema";
|
|
14
|
+
|
|
15
|
+
const limit = 50; // raise or lower this number depending on how your layout performs
|
|
16
|
+
export const fetchData = __ACTION_CLIENT__
|
|
17
|
+
.schema(
|
|
18
|
+
z.object({
|
|
19
|
+
offset: z.number().catch(0),
|
|
20
|
+
sorting: z.array(
|
|
21
|
+
z.object({ id: z.string(), desc: z.boolean().default(false) })
|
|
22
|
+
),
|
|
23
|
+
columnFilters: z.array(z.object({ id: z.string(), value: z.unknown() })),
|
|
24
|
+
})
|
|
25
|
+
)
|
|
26
|
+
.action(async ({ parsedInput: { offset, sorting, columnFilters } }) => {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
const getOptions: ListParams<__TYPE_NAME__, any> & {
|
|
29
|
+
query: Query<__TYPE_NAME__>[];
|
|
30
|
+
} = {
|
|
31
|
+
limit,
|
|
32
|
+
offset,
|
|
33
|
+
query: [{ ["__FIRST_FIELD_NAME__"]: "*" }],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if (sorting.length > 0) {
|
|
37
|
+
getOptions.sort = sorting.map(({ id, desc }) => ({
|
|
38
|
+
fieldName: id as keyof __TYPE_NAME__,
|
|
39
|
+
sortOrder: desc ? "descend" : "ascend",
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (columnFilters.length > 0) {
|
|
44
|
+
getOptions.query = columnFilters
|
|
45
|
+
.map(({ id, value }) => {
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
return {
|
|
48
|
+
[id]: value,
|
|
49
|
+
};
|
|
50
|
+
} else if (typeof value === "object" && value instanceof Date) {
|
|
51
|
+
return {
|
|
52
|
+
[id]: dayjs(value).format("YYYY+MM+DD"),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
})
|
|
57
|
+
.filter(Boolean) as Query<any>[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const data = await __CLIENT_NAME__.find(getOptions);
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
data: data.data,
|
|
64
|
+
hasNextPage: data.dataInfo.foundCount > limit + offset,
|
|
65
|
+
totalCount: data.dataInfo.foundCount,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export const updateRecord = __ACTION_CLIENT__
|
|
70
|
+
.schema(__ZOD_TYPE_NAME__.partial())
|
|
71
|
+
.action(async ({ parsedInput }) => {
|
|
72
|
+
const id = parsedInput[idFieldName];
|
|
73
|
+
delete parsedInput[idFieldName]; // this ensures the id field value is not included in the updated fieldData
|
|
74
|
+
const data = parsedInput;
|
|
75
|
+
|
|
76
|
+
const {
|
|
77
|
+
data: { recordId },
|
|
78
|
+
} = await __CLIENT_NAME__.findOne({ query: { [idFieldName]: `==${id}` } });
|
|
79
|
+
|
|
80
|
+
return await __CLIENT_NAME__.update({
|
|
81
|
+
recordId,
|
|
82
|
+
fieldData: data,
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Stack, Text, Code } from "@mantine/core";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
import TableContent from "./table";
|
|
5
|
+
import { idFieldName } from "./schema";
|
|
6
|
+
|
|
7
|
+
export default async function TablePage() {
|
|
8
|
+
return (
|
|
9
|
+
<Stack>
|
|
10
|
+
<div>
|
|
11
|
+
<Text>
|
|
12
|
+
This table allows editing. Double-click on a cell to edit the value.
|
|
13
|
+
</Text>
|
|
14
|
+
<Text size="sm" c="dimmed">
|
|
15
|
+
NOTE: This feature requires a primary key field on your API layout. If your
|
|
16
|
+
primary key field is not <Code>{idFieldName}</Code>, update the
|
|
17
|
+
<Code>idFieldName</Code> variable in the <Code>schema.ts</Code> file.
|
|
18
|
+
</Text>
|
|
19
|
+
</div>
|
|
20
|
+
<TableContent />
|
|
21
|
+
</Stack>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { showErrorNotification } from "@/utils/notification-helpers";
|
|
4
|
+
import {
|
|
5
|
+
useInfiniteQuery,
|
|
6
|
+
useMutation,
|
|
7
|
+
useQueryClient,
|
|
8
|
+
} from "@tanstack/react-query";
|
|
9
|
+
import type {
|
|
10
|
+
MRT_ColumnFiltersState,
|
|
11
|
+
MRT_SortingState,
|
|
12
|
+
} from "mantine-react-table";
|
|
13
|
+
import { useMemo } from "react";
|
|
14
|
+
|
|
15
|
+
import { fetchData, updateRecord } from "./actions";
|
|
16
|
+
import { idFieldName } from "./schema";
|
|
17
|
+
|
|
18
|
+
export function useAllData({
|
|
19
|
+
sorting,
|
|
20
|
+
columnFilters,
|
|
21
|
+
}: {
|
|
22
|
+
sorting: MRT_SortingState;
|
|
23
|
+
columnFilters: MRT_ColumnFiltersState;
|
|
24
|
+
}) {
|
|
25
|
+
const queryKey = ["all-__SCHEMA_NAME__", sorting, columnFilters];
|
|
26
|
+
// useInfiniteQuery is used to help with automatic pagination
|
|
27
|
+
const qr = useInfiniteQuery({
|
|
28
|
+
queryKey,
|
|
29
|
+
queryFn: async ({ pageParam: offset }) => {
|
|
30
|
+
const result = await fetchData({ offset, sorting, columnFilters });
|
|
31
|
+
if (!result) throw new Error(`Failed to fetch __SCHEMA_NAME__`);
|
|
32
|
+
if (!result.data) throw new Error(`No data found for __SCHEMA_NAME__`);
|
|
33
|
+
return result?.data;
|
|
34
|
+
},
|
|
35
|
+
retry: false,
|
|
36
|
+
initialPageParam: 0,
|
|
37
|
+
getNextPageParam: (lastPage, pages) =>
|
|
38
|
+
lastPage.hasNextPage
|
|
39
|
+
? pages.flatMap((page) => page.data).length
|
|
40
|
+
: undefined,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const flatData = useMemo(
|
|
44
|
+
() =>
|
|
45
|
+
qr.data?.pages.flatMap((page) => page.data).map((o) => o.fieldData) ?? [],
|
|
46
|
+
[qr.data]
|
|
47
|
+
);
|
|
48
|
+
const totalFetched = flatData.length;
|
|
49
|
+
const totalDBRowCount = qr.data?.pages?.[0]?.totalCount ?? 0;
|
|
50
|
+
|
|
51
|
+
const queryClient = useQueryClient();
|
|
52
|
+
|
|
53
|
+
const updateRecordMutation = useMutation({
|
|
54
|
+
mutationFn: updateRecord,
|
|
55
|
+
onMutate: async (newRecord) => {
|
|
56
|
+
// Cancel any outgoing refetches
|
|
57
|
+
await queryClient.cancelQueries({ queryKey });
|
|
58
|
+
|
|
59
|
+
// Optimistically update to the new value
|
|
60
|
+
queryClient.setQueryData<typeof qr.data>(queryKey, (old) => {
|
|
61
|
+
if (!old) return old;
|
|
62
|
+
return {
|
|
63
|
+
...old,
|
|
64
|
+
pages: old.pages.map((page) => ({
|
|
65
|
+
...page,
|
|
66
|
+
data: page.data.map((row) =>
|
|
67
|
+
row.fieldData[idFieldName] === newRecord[idFieldName]
|
|
68
|
+
? { ...row, fieldData: { ...row.fieldData, ...newRecord } }
|
|
69
|
+
: row,
|
|
70
|
+
),
|
|
71
|
+
})),
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
onError: () => {
|
|
76
|
+
showErrorNotification("Failed to update record");
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return { ...qr, data: flatData, totalDBRowCount, totalFetched, updateRecord: updateRecordMutation.mutate };
|
|
81
|
+
}
|