realtimex-crm 0.1.2
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/LICENSE.md +21 -0
- package/README.md +104 -0
- package/dist/assets/DealList-DqDrFeDV.js +59 -0
- package/dist/assets/DealList-DqDrFeDV.js.map +1 -0
- package/dist/assets/index-BiQoGq1P.css +1 -0
- package/dist/assets/index-CDIy4x-0.js +152 -0
- package/dist/assets/index-CDIy4x-0.js.map +1 -0
- package/dist/auth-callback.html +140 -0
- package/dist/favicon.ico +0 -0
- package/dist/img/adding-users.png +0 -0
- package/dist/img/empty.svg +42 -0
- package/dist/index.html +1 -0
- package/dist/logo192.png +0 -0
- package/dist/logo512.png +0 -0
- package/dist/logos/0.png +0 -0
- package/dist/logos/1.png +0 -0
- package/dist/logos/10.png +0 -0
- package/dist/logos/11.png +0 -0
- package/dist/logos/12.png +0 -0
- package/dist/logos/13.png +0 -0
- package/dist/logos/14.png +0 -0
- package/dist/logos/15.png +0 -0
- package/dist/logos/16.png +0 -0
- package/dist/logos/17.png +0 -0
- package/dist/logos/18.png +0 -0
- package/dist/logos/19.png +0 -0
- package/dist/logos/2.png +0 -0
- package/dist/logos/20.png +0 -0
- package/dist/logos/21.png +0 -0
- package/dist/logos/22.png +0 -0
- package/dist/logos/23.png +0 -0
- package/dist/logos/24.png +0 -0
- package/dist/logos/25.png +0 -0
- package/dist/logos/26.png +0 -0
- package/dist/logos/27.png +0 -0
- package/dist/logos/28.png +0 -0
- package/dist/logos/29.png +0 -0
- package/dist/logos/3.png +0 -0
- package/dist/logos/30.png +0 -0
- package/dist/logos/31.png +0 -0
- package/dist/logos/32.png +0 -0
- package/dist/logos/33.png +0 -0
- package/dist/logos/34.png +0 -0
- package/dist/logos/35.png +0 -0
- package/dist/logos/36.png +0 -0
- package/dist/logos/37.png +0 -0
- package/dist/logos/38.png +0 -0
- package/dist/logos/39.png +0 -0
- package/dist/logos/4.png +0 -0
- package/dist/logos/40.png +0 -0
- package/dist/logos/41.png +0 -0
- package/dist/logos/42.png +0 -0
- package/dist/logos/43.png +0 -0
- package/dist/logos/44.png +0 -0
- package/dist/logos/45.png +0 -0
- package/dist/logos/46.png +0 -0
- package/dist/logos/47.png +0 -0
- package/dist/logos/48.png +0 -0
- package/dist/logos/49.png +0 -0
- package/dist/logos/5.png +0 -0
- package/dist/logos/50.png +0 -0
- package/dist/logos/51.png +0 -0
- package/dist/logos/52.png +0 -0
- package/dist/logos/53.png +0 -0
- package/dist/logos/54.png +0 -0
- package/dist/logos/55.png +0 -0
- package/dist/logos/6.png +0 -0
- package/dist/logos/7.png +0 -0
- package/dist/logos/8.png +0 -0
- package/dist/logos/9.png +0 -0
- package/dist/logos/Readme.md +1 -0
- package/dist/logos/logo_atomic_crm.svg +14 -0
- package/dist/logos/logo_atomic_crm_dark.svg +14 -0
- package/dist/logos/logo_atomic_crm_light.svg +14 -0
- package/dist/manifest.json +25 -0
- package/dist/robots.txt +3 -0
- package/dist/stats.html +4949 -0
- package/package.json +152 -0
- package/public/auth-callback.html +140 -0
- package/public/favicon.ico +0 -0
- package/public/img/adding-users.png +0 -0
- package/public/img/empty.svg +42 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/logos/0.png +0 -0
- package/public/logos/1.png +0 -0
- package/public/logos/10.png +0 -0
- package/public/logos/11.png +0 -0
- package/public/logos/12.png +0 -0
- package/public/logos/13.png +0 -0
- package/public/logos/14.png +0 -0
- package/public/logos/15.png +0 -0
- package/public/logos/16.png +0 -0
- package/public/logos/17.png +0 -0
- package/public/logos/18.png +0 -0
- package/public/logos/19.png +0 -0
- package/public/logos/2.png +0 -0
- package/public/logos/20.png +0 -0
- package/public/logos/21.png +0 -0
- package/public/logos/22.png +0 -0
- package/public/logos/23.png +0 -0
- package/public/logos/24.png +0 -0
- package/public/logos/25.png +0 -0
- package/public/logos/26.png +0 -0
- package/public/logos/27.png +0 -0
- package/public/logos/28.png +0 -0
- package/public/logos/29.png +0 -0
- package/public/logos/3.png +0 -0
- package/public/logos/30.png +0 -0
- package/public/logos/31.png +0 -0
- package/public/logos/32.png +0 -0
- package/public/logos/33.png +0 -0
- package/public/logos/34.png +0 -0
- package/public/logos/35.png +0 -0
- package/public/logos/36.png +0 -0
- package/public/logos/37.png +0 -0
- package/public/logos/38.png +0 -0
- package/public/logos/39.png +0 -0
- package/public/logos/4.png +0 -0
- package/public/logos/40.png +0 -0
- package/public/logos/41.png +0 -0
- package/public/logos/42.png +0 -0
- package/public/logos/43.png +0 -0
- package/public/logos/44.png +0 -0
- package/public/logos/45.png +0 -0
- package/public/logos/46.png +0 -0
- package/public/logos/47.png +0 -0
- package/public/logos/48.png +0 -0
- package/public/logos/49.png +0 -0
- package/public/logos/5.png +0 -0
- package/public/logos/50.png +0 -0
- package/public/logos/51.png +0 -0
- package/public/logos/52.png +0 -0
- package/public/logos/53.png +0 -0
- package/public/logos/54.png +0 -0
- package/public/logos/55.png +0 -0
- package/public/logos/6.png +0 -0
- package/public/logos/7.png +0 -0
- package/public/logos/8.png +0 -0
- package/public/logos/9.png +0 -0
- package/public/logos/Readme.md +1 -0
- package/public/logos/logo_atomic_crm.svg +14 -0
- package/public/logos/logo_atomic_crm_dark.svg +14 -0
- package/public/logos/logo_atomic_crm_light.svg +14 -0
- package/public/manifest.json +25 -0
- package/public/robots.txt +3 -0
- package/src/App.css +42 -0
- package/src/App.tsx +58 -0
- package/src/assets/react.svg +1 -0
- package/src/components/admin/Readme.md +40 -0
- package/src/components/admin/admin.tsx +132 -0
- package/src/components/admin/app-sidebar.tsx +166 -0
- package/src/components/admin/array-field.tsx +59 -0
- package/src/components/admin/array-input.tsx +201 -0
- package/src/components/admin/authentication.tsx +86 -0
- package/src/components/admin/autocomplete-array-input.tsx +254 -0
- package/src/components/admin/autocomplete-input.tsx +296 -0
- package/src/components/admin/badge-field.tsx +65 -0
- package/src/components/admin/boolean-input.tsx +116 -0
- package/src/components/admin/breadcrumb.tsx +135 -0
- package/src/components/admin/bulk-actions-toolbar.tsx +83 -0
- package/src/components/admin/bulk-delete-button.tsx +70 -0
- package/src/components/admin/bulk-export-button.tsx +76 -0
- package/src/components/admin/cancel-button.tsx +46 -0
- package/src/components/admin/columns-button.tsx +345 -0
- package/src/components/admin/confirm.tsx +166 -0
- package/src/components/admin/count.tsx +94 -0
- package/src/components/admin/create-button.tsx +58 -0
- package/src/components/admin/create.tsx +132 -0
- package/src/components/admin/data-table.tsx +520 -0
- package/src/components/admin/date-field.tsx +136 -0
- package/src/components/admin/date-input.tsx +317 -0
- package/src/components/admin/date-time-input.tsx +331 -0
- package/src/components/admin/delete-button.tsx +113 -0
- package/src/components/admin/edit-button.tsx +64 -0
- package/src/components/admin/edit-guesser.tsx +157 -0
- package/src/components/admin/edit.tsx +152 -0
- package/src/components/admin/email-field.tsx +74 -0
- package/src/components/admin/error.tsx +111 -0
- package/src/components/admin/export-button.tsx +126 -0
- package/src/components/admin/field-toggle.tsx +164 -0
- package/src/components/admin/file-field.tsx +123 -0
- package/src/components/admin/file-input.tsx +361 -0
- package/src/components/admin/filter-form.tsx +510 -0
- package/src/components/admin/form.tsx +312 -0
- package/src/components/admin/icon-button-with-tooltip.tsx +85 -0
- package/src/components/admin/index.ts +73 -0
- package/src/components/admin/input-helper-text.tsx +29 -0
- package/src/components/admin/layout.tsx +69 -0
- package/src/components/admin/list-guesser.tsx +239 -0
- package/src/components/admin/list-pagination.tsx +247 -0
- package/src/components/admin/list.tsx +178 -0
- package/src/components/admin/loading.tsx +40 -0
- package/src/components/admin/locales-menu-button.tsx +60 -0
- package/src/components/admin/login-page.tsx +104 -0
- package/src/components/admin/notification.tsx +114 -0
- package/src/components/admin/number-field.tsx +84 -0
- package/src/components/admin/number-input.tsx +124 -0
- package/src/components/admin/radio-button-group-input.tsx +184 -0
- package/src/components/admin/ready.tsx +55 -0
- package/src/components/admin/record-field.tsx +132 -0
- package/src/components/admin/reference-array-field.tsx +152 -0
- package/src/components/admin/reference-array-input.tsx +68 -0
- package/src/components/admin/reference-field.tsx +153 -0
- package/src/components/admin/reference-input.tsx +46 -0
- package/src/components/admin/reference-many-count.tsx +92 -0
- package/src/components/admin/reference-many-field.tsx +132 -0
- package/src/components/admin/refresh-button.tsx +31 -0
- package/src/components/admin/saved-queries.tsx +174 -0
- package/src/components/admin/search-input.tsx +57 -0
- package/src/components/admin/select-field.tsx +111 -0
- package/src/components/admin/select-input.tsx +323 -0
- package/src/components/admin/show-button.tsx +57 -0
- package/src/components/admin/show-guesser.tsx +215 -0
- package/src/components/admin/show.tsx +184 -0
- package/src/components/admin/simple-form-iterator.tsx +582 -0
- package/src/components/admin/simple-form.tsx +95 -0
- package/src/components/admin/simple-show-layout.tsx +8 -0
- package/src/components/admin/single-field-list.tsx +67 -0
- package/src/components/admin/sort-button.tsx +152 -0
- package/src/components/admin/spinner.tsx +46 -0
- package/src/components/admin/text-field.tsx +60 -0
- package/src/components/admin/text-input.tsx +77 -0
- package/src/components/admin/theme-mode-toggle.tsx +48 -0
- package/src/components/admin/theme-provider.tsx +74 -0
- package/src/components/admin/toggle-filter-button.tsx +77 -0
- package/src/components/admin/url-field.tsx +83 -0
- package/src/components/admin/user-menu.tsx +84 -0
- package/src/components/atomic-crm/activity/ActivityLog.tsx +54 -0
- package/src/components/atomic-crm/activity/ActivityLogCompanyCreated.tsx +50 -0
- package/src/components/atomic-crm/activity/ActivityLogContactCreated.tsx +42 -0
- package/src/components/atomic-crm/activity/ActivityLogContactNoteCreated.tsx +71 -0
- package/src/components/atomic-crm/activity/ActivityLogContext.tsx +11 -0
- package/src/components/atomic-crm/activity/ActivityLogDealCreated.tsx +41 -0
- package/src/components/atomic-crm/activity/ActivityLogDealNoteCreated.tsx +84 -0
- package/src/components/atomic-crm/activity/ActivityLogIterator.tsx +80 -0
- package/src/components/atomic-crm/activity/ActivityLogNote.tsx +36 -0
- package/src/components/atomic-crm/companies/AutocompleteCompanyInput.tsx +43 -0
- package/src/components/atomic-crm/companies/CompanyAside.tsx +207 -0
- package/src/components/atomic-crm/companies/CompanyAvatar.tsx +29 -0
- package/src/components/atomic-crm/companies/CompanyCard.tsx +88 -0
- package/src/components/atomic-crm/companies/CompanyCreate.tsx +41 -0
- package/src/components/atomic-crm/companies/CompanyEdit.tsx +33 -0
- package/src/components/atomic-crm/companies/CompanyEmpty.tsx +26 -0
- package/src/components/atomic-crm/companies/CompanyInputs.tsx +160 -0
- package/src/components/atomic-crm/companies/CompanyList.tsx +54 -0
- package/src/components/atomic-crm/companies/CompanyListFilter.tsx +55 -0
- package/src/components/atomic-crm/companies/CompanyShow.tsx +241 -0
- package/src/components/atomic-crm/companies/GridList.tsx +46 -0
- package/src/components/atomic-crm/companies/index.ts +11 -0
- package/src/components/atomic-crm/companies/sizes.ts +7 -0
- package/src/components/atomic-crm/consts.ts +5 -0
- package/src/components/atomic-crm/contacts/Avatar.tsx +40 -0
- package/src/components/atomic-crm/contacts/ContactAside.tsx +187 -0
- package/src/components/atomic-crm/contacts/ContactCreate.tsx +34 -0
- package/src/components/atomic-crm/contacts/ContactEdit.tsx +32 -0
- package/src/components/atomic-crm/contacts/ContactEmpty.tsx +28 -0
- package/src/components/atomic-crm/contacts/ContactImportButton.tsx +213 -0
- package/src/components/atomic-crm/contacts/ContactInputs.tsx +209 -0
- package/src/components/atomic-crm/contacts/ContactList.tsx +116 -0
- package/src/components/atomic-crm/contacts/ContactListContent.tsx +107 -0
- package/src/components/atomic-crm/contacts/ContactListFilter.tsx +126 -0
- package/src/components/atomic-crm/contacts/ContactMergeButton.tsx +263 -0
- package/src/components/atomic-crm/contacts/ContactShow.tsx +76 -0
- package/src/components/atomic-crm/contacts/ExportVCardButton.tsx +79 -0
- package/src/components/atomic-crm/contacts/TagsList.tsx +33 -0
- package/src/components/atomic-crm/contacts/TagsListEdit.tsx +155 -0
- package/src/components/atomic-crm/contacts/contacts_export.csv +3 -0
- package/src/components/atomic-crm/contacts/exportToVCard.ts +104 -0
- package/src/components/atomic-crm/contacts/index.tsx +14 -0
- package/src/components/atomic-crm/contacts/useContactImport.tsx +206 -0
- package/src/components/atomic-crm/dashboard/Dashboard.tsx +66 -0
- package/src/components/atomic-crm/dashboard/DashboardActivityLog.tsx +22 -0
- package/src/components/atomic-crm/dashboard/DashboardStepper.tsx +72 -0
- package/src/components/atomic-crm/dashboard/DealsChart.tsx +202 -0
- package/src/components/atomic-crm/dashboard/DealsPipeline.tsx +90 -0
- package/src/components/atomic-crm/dashboard/HotContacts.tsx +92 -0
- package/src/components/atomic-crm/dashboard/LatestNotes.tsx +116 -0
- package/src/components/atomic-crm/dashboard/TasksList.tsx +69 -0
- package/src/components/atomic-crm/dashboard/TasksListEmpty.tsx +22 -0
- package/src/components/atomic-crm/dashboard/TasksListFilter.tsx +72 -0
- package/src/components/atomic-crm/dashboard/Welcome.tsx +41 -0
- package/src/components/atomic-crm/deals/ContactList.tsx +31 -0
- package/src/components/atomic-crm/deals/DealArchivedList.tsx +105 -0
- package/src/components/atomic-crm/deals/DealCard.tsx +78 -0
- package/src/components/atomic-crm/deals/DealColumn.tsx +52 -0
- package/src/components/atomic-crm/deals/DealCreate.tsx +95 -0
- package/src/components/atomic-crm/deals/DealEdit.tsx +81 -0
- package/src/components/atomic-crm/deals/DealEmpty.tsx +63 -0
- package/src/components/atomic-crm/deals/DealInputs.tsx +103 -0
- package/src/components/atomic-crm/deals/DealList.tsx +95 -0
- package/src/components/atomic-crm/deals/DealListContent.tsx +245 -0
- package/src/components/atomic-crm/deals/DealShow.tsx +260 -0
- package/src/components/atomic-crm/deals/OnlyMineInput.tsx +30 -0
- package/src/components/atomic-crm/deals/deal.ts +5 -0
- package/src/components/atomic-crm/deals/dealUtils.ts +26 -0
- package/src/components/atomic-crm/deals/index.ts +6 -0
- package/src/components/atomic-crm/deals/stages.ts +28 -0
- package/src/components/atomic-crm/filters/FilterCategory.tsx +20 -0
- package/src/components/atomic-crm/layout/FormToolbar.tsx +12 -0
- package/src/components/atomic-crm/layout/Header.tsx +134 -0
- package/src/components/atomic-crm/layout/Layout.tsx +21 -0
- package/src/components/atomic-crm/layout/TopToolbar.tsx +24 -0
- package/src/components/atomic-crm/login/LoginSkeleton.tsx +18 -0
- package/src/components/atomic-crm/login/SignupPage.tsx +150 -0
- package/src/components/atomic-crm/login/StartPage.tsx +27 -0
- package/src/components/atomic-crm/misc/AsideSection.tsx +21 -0
- package/src/components/atomic-crm/misc/ContactOption.tsx +26 -0
- package/src/components/atomic-crm/misc/ImageEditorField.tsx +206 -0
- package/src/components/atomic-crm/misc/RelativeDate.tsx +5 -0
- package/src/components/atomic-crm/misc/Status.tsx +28 -0
- package/src/components/atomic-crm/misc/fetchWithTimeout.ts +19 -0
- package/src/components/atomic-crm/misc/isLinkedInUrl.ts +15 -0
- package/src/components/atomic-crm/misc/unsupportedDomains.const.ts +105 -0
- package/src/components/atomic-crm/misc/useAppBarHeight.ts +9 -0
- package/src/components/atomic-crm/misc/usePapaParse.tsx +144 -0
- package/src/components/atomic-crm/notes/Note.tsx +187 -0
- package/src/components/atomic-crm/notes/NoteAttachments.tsx +56 -0
- package/src/components/atomic-crm/notes/NoteCreate.tsx +112 -0
- package/src/components/atomic-crm/notes/NoteInputs.tsx +92 -0
- package/src/components/atomic-crm/notes/NotesIterator.tsx +37 -0
- package/src/components/atomic-crm/notes/StatusSelector.tsx +39 -0
- package/src/components/atomic-crm/notes/index.ts +3 -0
- package/src/components/atomic-crm/notes/utils.ts +13 -0
- package/src/components/atomic-crm/providers/commons/activity.ts +174 -0
- package/src/components/atomic-crm/providers/commons/canAccess.ts +26 -0
- package/src/components/atomic-crm/providers/commons/getCompanyAvatar.spec.ts +20 -0
- package/src/components/atomic-crm/providers/commons/getCompanyAvatar.ts +21 -0
- package/src/components/atomic-crm/providers/commons/getContactAvatar.spec.ts +80 -0
- package/src/components/atomic-crm/providers/commons/getContactAvatar.ts +70 -0
- package/src/components/atomic-crm/providers/commons/mergeContacts.ts +185 -0
- package/src/components/atomic-crm/providers/fakerest/authProvider.ts +74 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/companies.ts +53 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/contactNotes.ts +25 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/contacts.ts +103 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/dealNotes.ts +19 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/deals.ts +53 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/finalize.ts +10 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/index.ts +25 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/sales.ts +37 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/tags.ts +14 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/tasks.ts +55 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/types.ts +21 -0
- package/src/components/atomic-crm/providers/fakerest/dataGenerator/utils.ts +28 -0
- package/src/components/atomic-crm/providers/fakerest/dataProvider.ts +518 -0
- package/src/components/atomic-crm/providers/fakerest/index.ts +2 -0
- package/src/components/atomic-crm/providers/fakerest/internal/listParser.ts +48 -0
- package/src/components/atomic-crm/providers/fakerest/internal/supabaseAdapter.spec.ts +721 -0
- package/src/components/atomic-crm/providers/fakerest/internal/supabaseAdapter.ts +49 -0
- package/src/components/atomic-crm/providers/fakerest/internal/transformContainsFilter.spec.ts +35 -0
- package/src/components/atomic-crm/providers/fakerest/internal/transformContainsFilter.ts +17 -0
- package/src/components/atomic-crm/providers/fakerest/internal/transformFilter.ts +57 -0
- package/src/components/atomic-crm/providers/fakerest/internal/transformInFilter.spec.ts +32 -0
- package/src/components/atomic-crm/providers/fakerest/internal/transformInFilter.ts +17 -0
- package/src/components/atomic-crm/providers/fakerest/internal/transformOrFilter.spec.ts +23 -0
- package/src/components/atomic-crm/providers/fakerest/internal/transformOrFilter.ts +17 -0
- package/src/components/atomic-crm/providers/supabase/authProvider.ts +121 -0
- package/src/components/atomic-crm/providers/supabase/dataProvider.ts +407 -0
- package/src/components/atomic-crm/providers/supabase/index.ts +2 -0
- package/src/components/atomic-crm/providers/supabase/supabase.ts +34 -0
- package/src/components/atomic-crm/providers/types.ts +1 -0
- package/src/components/atomic-crm/root/CRM.tsx +167 -0
- package/src/components/atomic-crm/root/ConfigurationContext.tsx +80 -0
- package/src/components/atomic-crm/root/defaultConfiguration.ts +64 -0
- package/src/components/atomic-crm/root/i18nProvider.tsx +25 -0
- package/src/components/atomic-crm/sales/SaleName.tsx +13 -0
- package/src/components/atomic-crm/sales/SalesCreate.tsx +51 -0
- package/src/components/atomic-crm/sales/SalesEdit.tsx +82 -0
- package/src/components/atomic-crm/sales/SalesInputs.tsx +31 -0
- package/src/components/atomic-crm/sales/SalesList.tsx +62 -0
- package/src/components/atomic-crm/sales/index.ts +12 -0
- package/src/components/atomic-crm/settings/DatabaseSettings.tsx +169 -0
- package/src/components/atomic-crm/settings/SettingsPage.tsx +259 -0
- package/src/components/atomic-crm/setup/SupabaseSetupWizard.tsx +215 -0
- package/src/components/atomic-crm/simple-list/ListNoResults.tsx +53 -0
- package/src/components/atomic-crm/simple-list/ListPlaceholder.tsx +9 -0
- package/src/components/atomic-crm/simple-list/SimpleList.tsx +245 -0
- package/src/components/atomic-crm/simple-list/SimpleListItem.tsx +138 -0
- package/src/components/atomic-crm/simple-list/SimpleListLoading.tsx +60 -0
- package/src/components/atomic-crm/tags/RoundButton.tsx +10 -0
- package/src/components/atomic-crm/tags/TagChip.tsx +45 -0
- package/src/components/atomic-crm/tags/TagCreateModal.tsx +39 -0
- package/src/components/atomic-crm/tags/TagDialog.tsx +118 -0
- package/src/components/atomic-crm/tags/TagEditModal.tsx +42 -0
- package/src/components/atomic-crm/tags/colors.ts +12 -0
- package/src/components/atomic-crm/tasks/AddTask.tsx +191 -0
- package/src/components/atomic-crm/tasks/Task.tsx +184 -0
- package/src/components/atomic-crm/tasks/TaskEdit.tsx +96 -0
- package/src/components/atomic-crm/tasks/TasksIterator.tsx +30 -0
- package/src/components/atomic-crm/types.ts +226 -0
- package/src/components/supabase/forgot-password-page.tsx +86 -0
- package/src/components/supabase/layout.tsx +27 -0
- package/src/components/supabase/set-password-page.tsx +119 -0
- package/src/components/ui/README.md +34 -0
- package/src/components/ui/accordion.tsx +64 -0
- package/src/components/ui/alert.tsx +66 -0
- package/src/components/ui/avatar.tsx +99 -0
- package/src/components/ui/badge.tsx +46 -0
- package/src/components/ui/breadcrumb.tsx +109 -0
- package/src/components/ui/button.tsx +59 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/command.tsx +175 -0
- package/src/components/ui/dialog.tsx +133 -0
- package/src/components/ui/drawer.tsx +133 -0
- package/src/components/ui/dropdown-menu.tsx +255 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/navigation-menu.tsx +168 -0
- package/src/components/ui/pagination.tsx +127 -0
- package/src/components/ui/popover.tsx +46 -0
- package/src/components/ui/progress.tsx +29 -0
- package/src/components/ui/radio-group.tsx +43 -0
- package/src/components/ui/select.tsx +183 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/sheet.tsx +137 -0
- package/src/components/ui/sidebar.tsx +724 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/sonner.tsx +38 -0
- package/src/components/ui/spinner.tsx +51 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/table.tsx +114 -0
- package/src/components/ui/tabs.tsx +64 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +61 -0
- package/src/hooks/saved-queries.tsx +67 -0
- package/src/hooks/simple-form-iterator-context.tsx +70 -0
- package/src/hooks/use-mobile.ts +21 -0
- package/src/hooks/useBulkExport.tsx +61 -0
- package/src/hooks/useSupportCreateSuggestion.tsx +188 -0
- package/src/hooks/user-menu-context.tsx +24 -0
- package/src/index.css +170 -0
- package/src/lib/field.type.ts +22 -0
- package/src/lib/genericMemo.ts +18 -0
- package/src/lib/i18nProvider.ts +9 -0
- package/src/lib/sanitizeInputRestProps.ts +46 -0
- package/src/lib/supabase-config.ts +123 -0
- package/src/lib/utils.ts +6 -0
- package/src/main.tsx +10 -0
- package/src/setupTests.js +5 -0
- package/src/vite-env.d.ts +1 -0
- package/supabase/config.toml +157 -0
- package/supabase/functions/.env.development +7 -0
- package/supabase/functions/_shared/db.ts +187 -0
- package/supabase/functions/_shared/supabaseAdmin.ts +13 -0
- package/supabase/functions/_shared/utils.ts +13 -0
- package/supabase/functions/mergeContacts/index.ts +215 -0
- package/supabase/functions/postmark/addNoteToContact.ts +129 -0
- package/supabase/functions/postmark/extractMailContactData.ts +41 -0
- package/supabase/functions/postmark/getExpectedAuthorization.ts +4 -0
- package/supabase/functions/postmark/getNoteContent.ts +6 -0
- package/supabase/functions/postmark/index.ts +210 -0
- package/supabase/functions/updatePassword/index.ts +50 -0
- package/supabase/functions/users/index.ts +206 -0
- package/supabase/migrations/20240730075029_init_db.sql +600 -0
- package/supabase/migrations/20240730075425_init_triggers.sql +57 -0
- package/supabase/migrations/20240806124555_task_sales_id.sql +1 -0
- package/supabase/migrations/20240807082449_remove-aquisition.sql +20 -0
- package/supabase/migrations/20240808141826_init_state_configure.sql +9 -0
- package/supabase/migrations/20240813084010_tags_policy.sql +18 -0
- package/supabase/migrations/20241104153231_sales_policies.sql +7 -0
- package/supabase/migrations/20250109152531_email_jsonb.sql +43 -0
- package/supabase/migrations/20250113132531_phone_jsonb.sql +67 -0
- package/supabase/migrations/20251204172855_merge_contacts_function.sql +153 -0
- package/supabase/migrations/20251204201317_drop_merge_contacts_function.sql +2 -0
- package/supabase/seed.sql +0 -0
- package/supabase/templates/invite.html +70 -0
- package/supabase/templates/recovery.html +75 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ScanFace,
|
|
3
|
+
BookOpenText,
|
|
4
|
+
ChevronsLeftRight,
|
|
5
|
+
Github,
|
|
6
|
+
} from "lucide-react";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Splash screen displayed when no resources are configured yet.
|
|
10
|
+
*
|
|
11
|
+
* Provides helpful links to documentation, demo, and GitHub repository.
|
|
12
|
+
* Automatically shown when the admin app has no Resource children defined.
|
|
13
|
+
*
|
|
14
|
+
* @see {@link https://marmelab.com/shadcn-admin-kit/docs/ready/ Ready documentation}
|
|
15
|
+
*/
|
|
16
|
+
export const Ready = () => (
|
|
17
|
+
<div className="flex flex-col h-screen">
|
|
18
|
+
<div
|
|
19
|
+
className="flex-1 flex flex-col text-white text-center justify-center items-center"
|
|
20
|
+
style={{
|
|
21
|
+
background:
|
|
22
|
+
"linear-gradient(135deg, #00023b 0%, #00023b 50%, #313264 100%)",
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<ScanFace className="w-32 h-32 mb-4" />
|
|
26
|
+
<h1 className="text-3xl mb-4">Welcome to shadcn-admin-kit</h1>
|
|
27
|
+
<div className="text-lg opacity-75">
|
|
28
|
+
Your application is properly configured.
|
|
29
|
+
<br />
|
|
30
|
+
Now you can add a <Resource> as child of
|
|
31
|
+
<Admin></Admin>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<div className="flex h-[20vh] bg-zinc-100 text-black items-center justify-evenly">
|
|
35
|
+
<div className="text-xl">
|
|
36
|
+
<a href="https://marmelab.com/shadcn-admin-kit/docs">
|
|
37
|
+
<BookOpenText className="inline mr-4 w-10 h-10" />
|
|
38
|
+
Documentation
|
|
39
|
+
</a>
|
|
40
|
+
</div>
|
|
41
|
+
<div className="text-xl">
|
|
42
|
+
<a href="http://marmelab.com/shadcn-admin-kit/demo">
|
|
43
|
+
<ChevronsLeftRight className="inline mr-4 w-10 h-10" />
|
|
44
|
+
Demo
|
|
45
|
+
</a>
|
|
46
|
+
</div>
|
|
47
|
+
<div className="text-xl">
|
|
48
|
+
<a href="https://github.com/marmelab/shadcn-admin-kit">
|
|
49
|
+
<Github className="inline mr-4 w-10 h-10" />
|
|
50
|
+
GitHub
|
|
51
|
+
</a>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ReactNode, ElementType, HTMLAttributes } from "react";
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import type { ExtractRecordPaths, HintedString } from "ra-core";
|
|
4
|
+
import {
|
|
5
|
+
FieldTitle,
|
|
6
|
+
useRecordContext,
|
|
7
|
+
useResourceContext,
|
|
8
|
+
useTranslate,
|
|
9
|
+
} from "ra-core";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
|
|
12
|
+
import { TextField } from "@/components/admin/text-field";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Displays a labeled field-value pair with flexible rendering options.
|
|
16
|
+
*
|
|
17
|
+
* Supports either vertical or inline layout.
|
|
18
|
+
* It can render children, use a custom field component, or display a TextField by default.
|
|
19
|
+
* To be used with RecordContext, e.g. inside Show, or inside ArrayField to display array items.
|
|
20
|
+
*
|
|
21
|
+
* @see {@link https://marmelab.com/shadcn-admin-kit/docs/recordfield/ RecordField documentation}
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* import { NumberField, RecordField, Show } from '@/components/admin';
|
|
25
|
+
*
|
|
26
|
+
* const PostShow = () => (
|
|
27
|
+
* <Show>
|
|
28
|
+
* <div className="flex flex-col gap-4">
|
|
29
|
+
* <RecordField source="reference" label="Ref." />
|
|
30
|
+
* <RecordField
|
|
31
|
+
* label="dimensions"
|
|
32
|
+
* render={record => `${record.width}x${record.height}`}
|
|
33
|
+
* />
|
|
34
|
+
* <RecordField source="price">
|
|
35
|
+
* <NumberField source="price" options={
|
|
36
|
+
* style: 'currency',
|
|
37
|
+
* currency: 'USD',
|
|
38
|
+
* }/>
|
|
39
|
+
* <RecordField source="status" variant="inline" />
|
|
40
|
+
* </div>
|
|
41
|
+
* </Show>
|
|
42
|
+
* );
|
|
43
|
+
*/
|
|
44
|
+
export const RecordField = <
|
|
45
|
+
RecordType extends Record<string, any> = Record<string, any>,
|
|
46
|
+
>(
|
|
47
|
+
props: RecordFieldProps<RecordType>,
|
|
48
|
+
) => {
|
|
49
|
+
const {
|
|
50
|
+
children,
|
|
51
|
+
className,
|
|
52
|
+
empty,
|
|
53
|
+
field,
|
|
54
|
+
label,
|
|
55
|
+
render,
|
|
56
|
+
resource: _,
|
|
57
|
+
source,
|
|
58
|
+
record: recordProp,
|
|
59
|
+
variant,
|
|
60
|
+
...rest
|
|
61
|
+
} = props;
|
|
62
|
+
const resource = useResourceContext(props);
|
|
63
|
+
const record = useRecordContext<RecordType>({ recordProp });
|
|
64
|
+
const translate = useTranslate();
|
|
65
|
+
|
|
66
|
+
if (!source && !label && !render) return null;
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
className={cn(
|
|
71
|
+
className,
|
|
72
|
+
"flex",
|
|
73
|
+
variant === "inline" ? "flex-row" : "flex-col",
|
|
74
|
+
)}
|
|
75
|
+
{...rest}
|
|
76
|
+
>
|
|
77
|
+
{label !== "" && label !== false ? (
|
|
78
|
+
<div
|
|
79
|
+
className={cn(
|
|
80
|
+
variant === "inline" ? "block min-w-50" : "text-xs",
|
|
81
|
+
"text-muted-foreground",
|
|
82
|
+
)}
|
|
83
|
+
>
|
|
84
|
+
<FieldTitle
|
|
85
|
+
label={label}
|
|
86
|
+
source={source}
|
|
87
|
+
resource={resource}
|
|
88
|
+
isRequired={false}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
) : null}
|
|
92
|
+
{children ? (
|
|
93
|
+
<span className="flex-1">{children}</span>
|
|
94
|
+
) : render ? (
|
|
95
|
+
record && (
|
|
96
|
+
<span className="flex-1">
|
|
97
|
+
{render(record) ||
|
|
98
|
+
(typeof empty === "string"
|
|
99
|
+
? translate(empty, { _: empty })
|
|
100
|
+
: empty)}
|
|
101
|
+
</span>
|
|
102
|
+
)
|
|
103
|
+
) : field ? (
|
|
104
|
+
createElement(field, {
|
|
105
|
+
source,
|
|
106
|
+
empty,
|
|
107
|
+
className: "flex-1",
|
|
108
|
+
})
|
|
109
|
+
) : source ? (
|
|
110
|
+
<TextField source={source} empty={empty} className="flex-1" />
|
|
111
|
+
) : null}
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// FIXME remove custom type when using TypeScript >= 5.4 as it is now native
|
|
117
|
+
type NoInfer<T> = T extends infer U ? U : never;
|
|
118
|
+
|
|
119
|
+
export interface RecordFieldProps<
|
|
120
|
+
RecordType extends Record<string, any> = Record<string, any>,
|
|
121
|
+
> extends HTMLAttributes<HTMLDivElement> {
|
|
122
|
+
children?: ReactNode;
|
|
123
|
+
className?: string;
|
|
124
|
+
empty?: ReactNode;
|
|
125
|
+
field?: ElementType;
|
|
126
|
+
label?: ReactNode;
|
|
127
|
+
render?: (record: RecordType) => React.ReactNode;
|
|
128
|
+
resource?: string;
|
|
129
|
+
source?: NoInfer<HintedString<ExtractRecordPaths<RecordType>>>;
|
|
130
|
+
record?: RecordType;
|
|
131
|
+
variant?: "default" | "inline";
|
|
132
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
import { memo } from "react";
|
|
3
|
+
import type {
|
|
4
|
+
FilterPayload,
|
|
5
|
+
ListControllerResult,
|
|
6
|
+
RaRecord,
|
|
7
|
+
SortPayload,
|
|
8
|
+
ExtractRecordPaths,
|
|
9
|
+
HintedString,
|
|
10
|
+
} from "ra-core";
|
|
11
|
+
import { ReferenceArrayFieldBase, useListContext } from "ra-core";
|
|
12
|
+
import type { UseQueryOptions } from "@tanstack/react-query";
|
|
13
|
+
import { SingleFieldList } from "@/components/admin/single-field-list";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Displays multiple related records by following an array of foreign keys.
|
|
17
|
+
*
|
|
18
|
+
* This field fetches related records using an array of IDs and renders them using a child component (SingleFieldList by default).
|
|
19
|
+
* It supports custom sorting, filtering, and rendering with DataTable or other list components.
|
|
20
|
+
* To be used with RecordField or DataTable.Col components, or anywhere a RecordContext is available.
|
|
21
|
+
*
|
|
22
|
+
* @see {@link https://marmelab.com/shadcn-admin-kit/docs/referencearrayfield/ ReferenceArrayField documentation}
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* import { List, DataTable, ReferenceArrayField } from '@/components/admin';
|
|
26
|
+
*
|
|
27
|
+
* export const PostList = () => (
|
|
28
|
+
* <List>
|
|
29
|
+
* <DataTable>
|
|
30
|
+
* <DataTable.Col source="id" />
|
|
31
|
+
* <DataTable.Col source="title" />
|
|
32
|
+
* <DataTable.Col source="tag_ids" label="Tags">
|
|
33
|
+
* <ReferenceArrayField reference="tags" source="tag_ids" />
|
|
34
|
+
* </DataTable.Col>
|
|
35
|
+
* <DataTable.Col>
|
|
36
|
+
* <EditButton />
|
|
37
|
+
* </DataTable.Col>
|
|
38
|
+
* </DataTable>
|
|
39
|
+
* </List>
|
|
40
|
+
* );
|
|
41
|
+
*/
|
|
42
|
+
export const ReferenceArrayField = <
|
|
43
|
+
RecordType extends RaRecord = RaRecord,
|
|
44
|
+
ReferenceRecordType extends RaRecord = RaRecord,
|
|
45
|
+
>(
|
|
46
|
+
props: ReferenceArrayFieldProps<RecordType, ReferenceRecordType>,
|
|
47
|
+
) => {
|
|
48
|
+
const {
|
|
49
|
+
filter,
|
|
50
|
+
page = 1,
|
|
51
|
+
perPage,
|
|
52
|
+
reference,
|
|
53
|
+
resource,
|
|
54
|
+
sort,
|
|
55
|
+
source,
|
|
56
|
+
queryOptions,
|
|
57
|
+
render,
|
|
58
|
+
...rest
|
|
59
|
+
} = props;
|
|
60
|
+
return (
|
|
61
|
+
<ReferenceArrayFieldBase
|
|
62
|
+
filter={filter}
|
|
63
|
+
page={page}
|
|
64
|
+
perPage={perPage}
|
|
65
|
+
reference={reference}
|
|
66
|
+
resource={resource}
|
|
67
|
+
sort={sort}
|
|
68
|
+
source={source}
|
|
69
|
+
queryOptions={queryOptions}
|
|
70
|
+
render={render}
|
|
71
|
+
>
|
|
72
|
+
<PureReferenceArrayFieldView {...rest} />
|
|
73
|
+
</ReferenceArrayFieldBase>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
export interface ReferenceArrayFieldProps<
|
|
77
|
+
RecordType extends RaRecord = RaRecord,
|
|
78
|
+
ReferenceRecordType extends RaRecord = RaRecord,
|
|
79
|
+
> extends ReferenceArrayFieldViewProps {
|
|
80
|
+
filter?: FilterPayload;
|
|
81
|
+
page?: number;
|
|
82
|
+
pagination?: ReactElement;
|
|
83
|
+
perPage?: number;
|
|
84
|
+
reference: string;
|
|
85
|
+
resource?: string;
|
|
86
|
+
source: NoInfer<HintedString<ExtractRecordPaths<RecordType>>>;
|
|
87
|
+
sort?: SortPayload;
|
|
88
|
+
queryOptions?: Omit<
|
|
89
|
+
UseQueryOptions<ReferenceRecordType[], Error>,
|
|
90
|
+
"queryFn" | "queryKey"
|
|
91
|
+
>;
|
|
92
|
+
render?: (props: ListControllerResult<ReferenceRecordType>) => ReactElement;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ReferenceArrayFieldViewProps {
|
|
96
|
+
children?: ReactNode;
|
|
97
|
+
className?: string;
|
|
98
|
+
empty?: ReactNode;
|
|
99
|
+
error?: ReactNode;
|
|
100
|
+
loading?: ReactNode;
|
|
101
|
+
pagination?: ReactNode;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const ReferenceArrayFieldView = (
|
|
105
|
+
props: ReferenceArrayFieldViewProps,
|
|
106
|
+
) => {
|
|
107
|
+
const {
|
|
108
|
+
children = defaultChildren,
|
|
109
|
+
className,
|
|
110
|
+
empty,
|
|
111
|
+
error: errorElement,
|
|
112
|
+
loading,
|
|
113
|
+
pagination,
|
|
114
|
+
} = props;
|
|
115
|
+
const {
|
|
116
|
+
isPending,
|
|
117
|
+
error,
|
|
118
|
+
total,
|
|
119
|
+
hasPreviousPage,
|
|
120
|
+
hasNextPage,
|
|
121
|
+
data,
|
|
122
|
+
filterValues,
|
|
123
|
+
} = useListContext();
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<div className={className}>
|
|
127
|
+
{isPending && loading !== false ? (
|
|
128
|
+
loading
|
|
129
|
+
) : error && errorElement !== false ? (
|
|
130
|
+
errorElement
|
|
131
|
+
) : (total === 0 ||
|
|
132
|
+
(total == null &&
|
|
133
|
+
hasPreviousPage === false &&
|
|
134
|
+
hasNextPage === false &&
|
|
135
|
+
// @ts-expect-error FIXME total may be undefined when using partial pagination but the ListControllerResult type is wrong about it
|
|
136
|
+
data.length === 0 &&
|
|
137
|
+
// the user didn't set any filters
|
|
138
|
+
!Object.keys(filterValues).length)) &&
|
|
139
|
+
empty !== false ? (
|
|
140
|
+
empty
|
|
141
|
+
) : (
|
|
142
|
+
<span>
|
|
143
|
+
{children}
|
|
144
|
+
{pagination && total !== undefined ? pagination : null}
|
|
145
|
+
</span>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const defaultChildren = <SingleFieldList />;
|
|
152
|
+
const PureReferenceArrayFieldView = memo(ReferenceArrayFieldView);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ReactElement } from "react";
|
|
3
|
+
import type { InputProps, UseReferenceArrayInputParams } from "ra-core";
|
|
4
|
+
import {
|
|
5
|
+
useReferenceArrayInputController,
|
|
6
|
+
ResourceContextProvider,
|
|
7
|
+
ChoicesContextProvider,
|
|
8
|
+
} from "ra-core";
|
|
9
|
+
import { AutocompleteArrayInput } from "@/components/admin/autocomplete-array-input";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Form input for editing arrays of foreign key relationships with autocompletion.
|
|
13
|
+
*
|
|
14
|
+
* This component fetches related records from a reference resource and displays them
|
|
15
|
+
* in a searchable multi-select interface using AutocompleteArrayInput.
|
|
16
|
+
* Use it to edit one-to-many or many-to-many relationships, where the current record
|
|
17
|
+
* has an array of foreign keys to another resource.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://marmelab.com/shadcn-admin-kit/docs/referencearrayinput/ ReferenceArrayInput documentation}
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* import { Edit, SimpleForm, TextInput, ReferenceArrayInput } from '@/components/admin';
|
|
23
|
+
*
|
|
24
|
+
* const PostEdit = () => (
|
|
25
|
+
* <Edit>
|
|
26
|
+
* <SimpleForm>
|
|
27
|
+
* <TextInput source="title" />
|
|
28
|
+
* <ReferenceArrayInput source="tag_ids" reference="tags" />
|
|
29
|
+
* </SimpleForm>
|
|
30
|
+
* </Edit>
|
|
31
|
+
* );
|
|
32
|
+
*/
|
|
33
|
+
export const ReferenceArrayInput = (props: ReferenceArrayInputProps) => {
|
|
34
|
+
const {
|
|
35
|
+
children = defaultChildren,
|
|
36
|
+
reference,
|
|
37
|
+
sort,
|
|
38
|
+
filter = defaultFilter,
|
|
39
|
+
} = props;
|
|
40
|
+
if (React.Children.count(children) !== 1) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"<ReferenceArrayInput> only accepts a single child (like <AutocompleteArrayInput>)",
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const controllerProps = useReferenceArrayInputController({
|
|
47
|
+
...props,
|
|
48
|
+
sort,
|
|
49
|
+
filter,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<ResourceContextProvider value={reference}>
|
|
54
|
+
<ChoicesContextProvider value={controllerProps}>
|
|
55
|
+
{children}
|
|
56
|
+
</ChoicesContextProvider>
|
|
57
|
+
</ResourceContextProvider>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const defaultChildren = <AutocompleteArrayInput />;
|
|
62
|
+
const defaultFilter = {};
|
|
63
|
+
|
|
64
|
+
export interface ReferenceArrayInputProps
|
|
65
|
+
extends InputProps,
|
|
66
|
+
UseReferenceArrayInputParams {
|
|
67
|
+
children?: ReactElement;
|
|
68
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtractRecordPaths,
|
|
3
|
+
LinkToType,
|
|
4
|
+
RaRecord,
|
|
5
|
+
UseReferenceFieldControllerResult,
|
|
6
|
+
} from "ra-core";
|
|
7
|
+
import {
|
|
8
|
+
ReferenceFieldBase,
|
|
9
|
+
useFieldValue,
|
|
10
|
+
useGetRecordRepresentation,
|
|
11
|
+
useReferenceFieldContext,
|
|
12
|
+
useTranslate,
|
|
13
|
+
} from "ra-core";
|
|
14
|
+
import type { MouseEvent, ReactNode } from "react";
|
|
15
|
+
import { Link } from "react-router";
|
|
16
|
+
import type { UseQueryOptions } from "@tanstack/react-query";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Displays a field from a related record by following a foreign key relationship.
|
|
20
|
+
*
|
|
21
|
+
* This field fetches the related record using the foreign key value and displays it using the record representation.
|
|
22
|
+
* It supports linking to the related record's show or edit page.
|
|
23
|
+
* To be used with RecordField or DataTable.Col components, or anywhere a RecordContext is available.
|
|
24
|
+
*
|
|
25
|
+
* @see {@link https://marmelab.com/shadcn-admin-kit/docs/referencefield/ ReferenceField documentation}
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* import { List, DataTable, ReferenceField } from '@/components/admin';
|
|
29
|
+
*
|
|
30
|
+
* const PostList = () => (
|
|
31
|
+
* <List>
|
|
32
|
+
* <DataTable>
|
|
33
|
+
* <DataTable.Col source="title" />
|
|
34
|
+
* <DataTable.Col label="Author">
|
|
35
|
+
* <ReferenceField source="author_id" reference="authors" link="show" />
|
|
36
|
+
* </DataTable.Col>
|
|
37
|
+
* </DataTable>
|
|
38
|
+
* </List>
|
|
39
|
+
* );
|
|
40
|
+
*/
|
|
41
|
+
export const ReferenceField = <
|
|
42
|
+
RecordType extends RaRecord = RaRecord,
|
|
43
|
+
ReferenceRecordType extends RaRecord = RaRecord,
|
|
44
|
+
>(
|
|
45
|
+
props: ReferenceFieldProps<RecordType, ReferenceRecordType>,
|
|
46
|
+
) => {
|
|
47
|
+
const { loading, error, empty, render, ...rest } = props;
|
|
48
|
+
const id = useFieldValue<RecordType>(props);
|
|
49
|
+
const translate = useTranslate();
|
|
50
|
+
|
|
51
|
+
return id == null ? (
|
|
52
|
+
typeof empty === "string" ? (
|
|
53
|
+
<>{empty && translate(empty, { _: empty })}</>
|
|
54
|
+
) : (
|
|
55
|
+
empty
|
|
56
|
+
)
|
|
57
|
+
) : (
|
|
58
|
+
<ReferenceFieldBase {...rest}>
|
|
59
|
+
<ReferenceFieldView<ReferenceRecordType>
|
|
60
|
+
render={render}
|
|
61
|
+
loading={loading}
|
|
62
|
+
error={error}
|
|
63
|
+
{...rest}
|
|
64
|
+
/>
|
|
65
|
+
</ReferenceFieldBase>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export interface ReferenceFieldProps<
|
|
70
|
+
RecordType extends RaRecord = RaRecord,
|
|
71
|
+
ReferenceRecordType extends RaRecord = RaRecord,
|
|
72
|
+
> extends Partial<ReferenceFieldViewProps<ReferenceRecordType>> {
|
|
73
|
+
children?: ReactNode;
|
|
74
|
+
queryOptions?: UseQueryOptions<RaRecord[], Error> & {
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
+
meta?: any;
|
|
77
|
+
};
|
|
78
|
+
record?: RecordType;
|
|
79
|
+
reference: string;
|
|
80
|
+
translateChoice?: ((record: ReferenceRecordType) => string) | boolean;
|
|
81
|
+
link?: LinkToType;
|
|
82
|
+
source: ExtractRecordPaths<RecordType>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// useful to prevent click bubbling in a datagrid with rowClick
|
|
86
|
+
const stopPropagation = (e: MouseEvent<HTMLAnchorElement>) =>
|
|
87
|
+
e.stopPropagation();
|
|
88
|
+
|
|
89
|
+
export const ReferenceFieldView = <
|
|
90
|
+
ReferenceRecordType extends RaRecord = RaRecord,
|
|
91
|
+
>(
|
|
92
|
+
props: ReferenceFieldViewProps<ReferenceRecordType>,
|
|
93
|
+
) => {
|
|
94
|
+
const {
|
|
95
|
+
children,
|
|
96
|
+
className,
|
|
97
|
+
empty,
|
|
98
|
+
error: errorElement,
|
|
99
|
+
render,
|
|
100
|
+
reference,
|
|
101
|
+
loading,
|
|
102
|
+
} = props;
|
|
103
|
+
const referenceFieldContext = useReferenceFieldContext();
|
|
104
|
+
const { error, link, isPending, referenceRecord } = referenceFieldContext;
|
|
105
|
+
const getRecordRepresentation = useGetRecordRepresentation(reference);
|
|
106
|
+
const translate = useTranslate();
|
|
107
|
+
|
|
108
|
+
if (error && errorElement !== false) {
|
|
109
|
+
return errorElement;
|
|
110
|
+
}
|
|
111
|
+
if (isPending && loading !== false) {
|
|
112
|
+
return loading;
|
|
113
|
+
}
|
|
114
|
+
if (!referenceRecord && empty !== false) {
|
|
115
|
+
return typeof empty === "string" ? (
|
|
116
|
+
<>{empty && translate(empty, { _: empty })}</>
|
|
117
|
+
) : (
|
|
118
|
+
empty
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const child = render
|
|
123
|
+
? render(referenceFieldContext)
|
|
124
|
+
: children || <span>{getRecordRepresentation(referenceRecord)}</span>;
|
|
125
|
+
|
|
126
|
+
if (link) {
|
|
127
|
+
return (
|
|
128
|
+
<div className={className}>
|
|
129
|
+
<Link to={link} onClick={stopPropagation}>
|
|
130
|
+
{child}
|
|
131
|
+
</Link>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return <>{child}</>;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export interface ReferenceFieldViewProps<
|
|
140
|
+
ReferenceRecordType extends RaRecord = RaRecord,
|
|
141
|
+
> {
|
|
142
|
+
children?: ReactNode;
|
|
143
|
+
className?: string;
|
|
144
|
+
empty?: ReactNode;
|
|
145
|
+
loading?: ReactNode;
|
|
146
|
+
render?: (props: UseReferenceFieldControllerResult) => ReactNode;
|
|
147
|
+
reference: string;
|
|
148
|
+
source: string;
|
|
149
|
+
resource?: string;
|
|
150
|
+
translateChoice?: ((record: ReferenceRecordType) => string) | boolean;
|
|
151
|
+
resourceLinkPath?: LinkToType;
|
|
152
|
+
error?: ReactNode;
|
|
153
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ReferenceInputBaseProps } from "ra-core";
|
|
2
|
+
import { ReferenceInputBase } from "ra-core";
|
|
3
|
+
import { AutocompleteInput } from "./autocomplete-input";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Form input for editing foreign key relationships with autocompletion.
|
|
7
|
+
*
|
|
8
|
+
* This component fetches related records from a reference resource and displays them in a searchable dropdown using AutocompleteInput.
|
|
9
|
+
* Use it to edit many-to-one relationships, where the current record has a foreign key to another resource.
|
|
10
|
+
*
|
|
11
|
+
* @see {@link https://marmelab.com/shadcn-admin-kit/docs/referenceinput/ ReferenceInput documentation}
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* import { Edit, SimpleForm, TextInput, ReferenceInput } from '@/components/admin';
|
|
15
|
+
*
|
|
16
|
+
* const ContactEdit = () => (
|
|
17
|
+
* <Edit>
|
|
18
|
+
* <SimpleForm>
|
|
19
|
+
* <TextInput source="first_name" />
|
|
20
|
+
* <TextInput source="last_name" />
|
|
21
|
+
* <TextInput source="title" />
|
|
22
|
+
* <ReferenceInput source="company_id" reference="companies" />
|
|
23
|
+
* </SimpleForm>
|
|
24
|
+
* </Edit>
|
|
25
|
+
* );
|
|
26
|
+
*/
|
|
27
|
+
export const ReferenceInput = (props: ReferenceInputProps) => {
|
|
28
|
+
const { children = defaultChildren, ...rest } = props;
|
|
29
|
+
|
|
30
|
+
if (props.validate && process.env.NODE_ENV !== "production") {
|
|
31
|
+
throw new Error(
|
|
32
|
+
"<ReferenceInput> does not accept a validate prop. Set the validate prop on the child instead.",
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return <ReferenceInputBase {...rest}>{children}</ReferenceInputBase>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const defaultChildren = <AutocompleteInput />;
|
|
40
|
+
|
|
41
|
+
export interface ReferenceInputProps extends ReferenceInputBaseProps {
|
|
42
|
+
/**
|
|
43
|
+
* Call validate on the child component instead
|
|
44
|
+
*/
|
|
45
|
+
validate?: never;
|
|
46
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { RaRecord, SortPayload } from "ra-core";
|
|
2
|
+
import {
|
|
3
|
+
useCreatePath,
|
|
4
|
+
useRecordContext,
|
|
5
|
+
useReferenceManyFieldController,
|
|
6
|
+
} from "ra-core";
|
|
7
|
+
import { Link } from "react-router";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Displays the count of related records that reference the current record.
|
|
11
|
+
*
|
|
12
|
+
* Calls dataProvider.getList() to compute the the number of records in a related resource that have a foreign key pointing to the current record.
|
|
13
|
+
* It can optionally link to a filtered list of those records.
|
|
14
|
+
*
|
|
15
|
+
* @see {@link https://marmelab.com/shadcn-admin-kit/docs/referencemanycount/ ReferenceManyCount documentation}
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* import { List, DataTable, ReferenceManyCount } from '@/components/admin';
|
|
19
|
+
*
|
|
20
|
+
* const AuthorList = () => (
|
|
21
|
+
* <List>
|
|
22
|
+
* <DataTable>
|
|
23
|
+
* <DataTable.Col source="name" />
|
|
24
|
+
* <DataTable.Col label="Number of Books">
|
|
25
|
+
* <ReferenceManyCount reference="books" target="author_id" link />
|
|
26
|
+
* </DataTable.Col>
|
|
27
|
+
* </DataTable>
|
|
28
|
+
* </List>
|
|
29
|
+
* );
|
|
30
|
+
*/
|
|
31
|
+
export const ReferenceManyCount = <RecordType extends RaRecord = RaRecord>(
|
|
32
|
+
props: ReferenceManyCountProps<RecordType>,
|
|
33
|
+
) => {
|
|
34
|
+
const {
|
|
35
|
+
reference,
|
|
36
|
+
target,
|
|
37
|
+
filter,
|
|
38
|
+
sort,
|
|
39
|
+
link,
|
|
40
|
+
resource,
|
|
41
|
+
source = "id",
|
|
42
|
+
} = props;
|
|
43
|
+
const record = useRecordContext<RecordType>(props);
|
|
44
|
+
const createPath = useCreatePath();
|
|
45
|
+
|
|
46
|
+
const { isLoading, error, total } =
|
|
47
|
+
useReferenceManyFieldController<RecordType>({
|
|
48
|
+
filter,
|
|
49
|
+
sort,
|
|
50
|
+
page: 1,
|
|
51
|
+
perPage: 1,
|
|
52
|
+
record,
|
|
53
|
+
reference,
|
|
54
|
+
resource,
|
|
55
|
+
source,
|
|
56
|
+
target,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const body = isLoading ? "" : error ? "error" : total;
|
|
60
|
+
|
|
61
|
+
return link && record ? (
|
|
62
|
+
<Link
|
|
63
|
+
to={{
|
|
64
|
+
pathname: createPath({ resource: reference, type: "list" }),
|
|
65
|
+
search: `filter=${JSON.stringify({
|
|
66
|
+
...(filter || {}),
|
|
67
|
+
[target]: record[source],
|
|
68
|
+
})}`,
|
|
69
|
+
}}
|
|
70
|
+
onClick={(e) => e.stopPropagation()}
|
|
71
|
+
>
|
|
72
|
+
{body}
|
|
73
|
+
</Link>
|
|
74
|
+
) : (
|
|
75
|
+
<span>{body}</span>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export interface ReferenceManyCountProps<
|
|
80
|
+
RecordType extends RaRecord = RaRecord,
|
|
81
|
+
> {
|
|
82
|
+
record?: RecordType;
|
|
83
|
+
reference: string;
|
|
84
|
+
resource?: string;
|
|
85
|
+
target: string;
|
|
86
|
+
source?: string;
|
|
87
|
+
sort?: SortPayload;
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
filter?: any;
|
|
90
|
+
link?: boolean;
|
|
91
|
+
timeout?: number;
|
|
92
|
+
}
|