@nixxie-cms/core 1.0.0 → 1.0.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.
Files changed (187) hide show
  1. package/README.md +2 -2
  2. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.js +4 -4
  3. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.esm.js +4 -4
  4. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.js +2 -2
  5. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.esm.js +2 -2
  6. package/context/dist/nixxie-cms-core-context.cjs.js +2 -2
  7. package/context/dist/nixxie-cms-core-context.esm.js +2 -2
  8. package/dist/{CreateItemDialog-33335548.esm.js → CreateItemDialog-7008b050.esm.js} +1 -1
  9. package/dist/{CreateItemDialog-56cf59b7.cjs.js → CreateItemDialog-a0cab315.cjs.js} +1 -1
  10. package/dist/{PageContainer-7db73317.esm.js → PageContainer-5ae731cc.esm.js} +25 -18
  11. package/dist/{PageContainer-27c27f10.cjs.js → PageContainer-abd7159f.cjs.js} +25 -18
  12. package/dist/{admin-meta-graphql-6f7f5331.esm.js → admin-meta-graphql-0e6e606e.esm.js} +1 -1
  13. package/dist/{admin-meta-graphql-c8f926e9.cjs.js → admin-meta-graphql-306c224a.cjs.js} +1 -1
  14. package/dist/{context-3132c3ed.esm.js → context-af9957ed.esm.js} +2 -2
  15. package/dist/{context-e7a45152.cjs.js → context-b5204629.cjs.js} +2 -2
  16. package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
  17. package/dist/declarations/src/admin-ui/components/PageContainer.d.ts.map +1 -1
  18. package/dist/declarations/src/helpers.d.ts.map +1 -1
  19. package/dist/declarations/src/index.d.ts +1 -0
  20. package/dist/declarations/src/index.d.ts.map +1 -1
  21. package/dist/declarations/src/internal-unstable/admin-ui/id-field-view.d.ts.map +1 -0
  22. package/dist/declarations/src/internal-unstable/admin-ui/pages/App/index.d.ts.map +1 -0
  23. package/dist/declarations/src/internal-unstable/admin-ui/pages/CreateItemPage/index.d.ts.map +1 -0
  24. package/dist/declarations/src/internal-unstable/admin-ui/pages/HomePage/index.d.ts.map +1 -0
  25. package/dist/declarations/src/internal-unstable/admin-ui/pages/ItemPage/index.d.ts.map +1 -0
  26. package/dist/declarations/src/internal-unstable/admin-ui/pages/ListPage/index.d.ts.map +1 -0
  27. package/dist/declarations/src/internal-unstable/admin-ui/pages/NoAccessPage/index.d.ts.map +1 -0
  28. package/dist/declarations/src/internal-unstable/artifacts.d.ts.map +1 -0
  29. package/dist/declarations/src/lib/core/initialise-lists.d.ts +1 -1
  30. package/dist/declarations/src/schema.d.ts.map +1 -1
  31. package/dist/declarations/src/types/config/index.d.ts +60 -1
  32. package/dist/declarations/src/types/config/index.d.ts.map +1 -1
  33. package/dist/declarations/src/types/config/lists.d.ts +4 -4
  34. package/dist/declarations/src/types/context.d.ts +150 -0
  35. package/dist/declarations/src/types/context.d.ts.map +1 -1
  36. package/dist/declarations/src/types/next-fields.d.ts +1 -1
  37. package/dist/{express-e9ed9a7d.cjs.js → express-455ae20c.cjs.js} +1 -1
  38. package/dist/{express-6743b918.esm.js → express-7559ca2d.esm.js} +1 -1
  39. package/dist/{index-ac01583b.cjs.js → index-89635494.cjs.js} +4 -4
  40. package/dist/{index-24b78415.esm.js → index-baa799e0.esm.js} +4 -4
  41. package/dist/nixxie-cms-core.cjs.js +104 -77
  42. package/dist/nixxie-cms-core.esm.js +104 -77
  43. package/dist/{non-null-graphql-5315718c.esm.js → non-null-graphql-a84ed64d.esm.js} +1 -1
  44. package/dist/{non-null-graphql-17b83ddc.cjs.js → non-null-graphql-add6bb3d.cjs.js} +1 -1
  45. package/dist/{resolve-hooks-66fe8a8e.cjs.js → resolve-hooks-165a9ce2.cjs.js} +1 -1
  46. package/dist/{resolve-hooks-17aafd37.esm.js → resolve-hooks-6813a045.esm.js} +2 -2
  47. package/dist/{system-dfec2f0a.esm.js → system-03e49e4f.esm.js} +8 -4
  48. package/dist/{system-48c5f6df.cjs.js → system-a321642d.cjs.js} +8 -4
  49. package/dist/{useFilter-0b5a1ee6.esm.js → useFilter-9b6db1f9.esm.js} +1 -1
  50. package/dist/{useFilter-1a4e6900.cjs.js → useFilter-acc9d413.cjs.js} +1 -1
  51. package/fields/dist/nixxie-cms-core-fields.cjs.js +16 -16
  52. package/fields/dist/nixxie-cms-core-fields.esm.js +17 -17
  53. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +3 -3
  54. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +3 -3
  55. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.js +1 -1
  56. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.esm.js +1 -1
  57. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +3 -3
  58. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +3 -3
  59. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.js +4 -4
  60. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.esm.js +4 -4
  61. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.js +1 -1
  62. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.esm.js +1 -1
  63. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.js +1 -1
  64. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.esm.js +1 -1
  65. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.d.ts +2 -0
  66. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.js +244 -0
  67. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.esm.js +235 -0
  68. package/internal-unstable/admin-ui/id-field-view/package.json +4 -0
  69. package/internal-unstable/admin-ui/next-config/package.json +4 -0
  70. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.d.ts +2 -0
  71. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.js +59 -0
  72. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.esm.js +55 -0
  73. package/internal-unstable/admin-ui/pages/App/package.json +4 -0
  74. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.d.ts +2 -0
  75. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.js +116 -0
  76. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.esm.js +112 -0
  77. package/internal-unstable/admin-ui/pages/CreateItemPage/package.json +4 -0
  78. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.d.ts +2 -0
  79. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.js +336 -0
  80. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.esm.js +332 -0
  81. package/internal-unstable/admin-ui/pages/HomePage/package.json +4 -0
  82. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.d.ts +2 -0
  83. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.js +463 -0
  84. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.esm.js +455 -0
  85. package/internal-unstable/admin-ui/pages/ItemPage/package.json +4 -0
  86. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.d.ts +2 -0
  87. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.js +1195 -0
  88. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.esm.js +1187 -0
  89. package/internal-unstable/admin-ui/pages/ListPage/package.json +4 -0
  90. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.d.ts +2 -0
  91. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.js +40 -0
  92. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.esm.js +35 -0
  93. package/internal-unstable/admin-ui/pages/NoAccessPage/package.json +4 -0
  94. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.d.ts +2 -0
  95. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.js +51 -0
  96. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.esm.js +38 -0
  97. package/internal-unstable/artifacts/package.json +4 -0
  98. package/package.json +44 -44
  99. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +44 -15
  100. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +44 -15
  101. package/scripts/dist/nixxie-cms-core-scripts.cjs.js +3 -3
  102. package/scripts/dist/nixxie-cms-core-scripts.esm.js +3 -3
  103. package/src/admin-ui/admin-meta-graphql.ts +168 -168
  104. package/src/admin-ui/components/CommandPalette.tsx +433 -431
  105. package/src/admin-ui/components/Navigation.tsx +389 -385
  106. package/src/admin-ui/components/PageContainer.tsx +311 -310
  107. package/src/admin-ui/components/WelcomeDialog.tsx +1 -1
  108. package/src/admin-ui/context.tsx +338 -338
  109. package/src/admin-ui/templates/app.ts +60 -60
  110. package/src/admin-ui/templates/create-item.ts +5 -5
  111. package/src/admin-ui/templates/home.ts +2 -2
  112. package/src/admin-ui/templates/item.tsx +5 -5
  113. package/src/admin-ui/templates/list.tsx +5 -5
  114. package/src/admin-ui/templates/next-config.ts +29 -0
  115. package/src/admin-ui/templates/no-access.ts +7 -7
  116. package/src/fields/types/bigInt/index.ts +181 -181
  117. package/src/fields/types/bytes/index.ts +275 -275
  118. package/src/fields/types/calendarDay/index.ts +194 -194
  119. package/src/fields/types/checkbox/index.ts +76 -76
  120. package/src/fields/types/decimal/index.ts +182 -182
  121. package/src/fields/types/file/index.ts +168 -168
  122. package/src/fields/types/float/index.ts +133 -133
  123. package/src/fields/types/image/index.ts +244 -244
  124. package/src/fields/types/integer/index.ts +156 -156
  125. package/src/fields/types/json/index.ts +77 -77
  126. package/src/fields/types/multiselect/index.ts +212 -212
  127. package/src/fields/types/password/index.ts +241 -241
  128. package/src/fields/types/relationship/index.ts +381 -381
  129. package/src/fields/types/relationship/views/RelationshipTable.tsx +190 -190
  130. package/src/fields/types/select/index.ts +226 -226
  131. package/src/fields/types/text/index.ts +207 -207
  132. package/src/fields/types/timestamp/index.ts +116 -116
  133. package/src/fields/types/virtual/index.ts +108 -108
  134. package/src/helpers.ts +342 -316
  135. package/src/index.ts +4 -0
  136. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.tsx +167 -167
  137. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.tsx +22 -22
  138. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.tsx +71 -71
  139. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.tsx +333 -333
  140. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/common.tsx +358 -358
  141. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.tsx +483 -483
  142. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/FilterAdd.tsx +221 -221
  143. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/PaginationControls.tsx +170 -170
  144. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/Tag.tsx +72 -72
  145. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.tsx +1006 -1006
  146. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.tsx +24 -24
  147. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.ts +5 -5
  148. package/src/lib/context/createContext.ts +165 -161
  149. package/src/lib/core/initialise-lists.ts +1097 -1097
  150. package/src/lib/id-field.ts +214 -214
  151. package/src/lib/telemetry.ts +342 -342
  152. package/src/schema.ts +237 -233
  153. package/src/scripts/telemetry.ts +1 -1
  154. package/src/types/config/index.ts +400 -333
  155. package/src/types/config/lists.ts +4 -4
  156. package/src/types/context.ts +700 -530
  157. package/src/types/next-fields.ts +499 -499
  158. package/src/types/telemetry.ts +51 -51
  159. package/tests/telemetry.test.ts +361 -361
  160. package/CHANGELOG.md +0 -3158
  161. package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/package.json +0 -4
  162. package/___internal-do-not-use-will-break-in-patch/admin-ui/next-config/package.json +0 -4
  163. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/package.json +0 -4
  164. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/package.json +0 -4
  165. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/package.json +0 -4
  166. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/package.json +0 -4
  167. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/package.json +0 -4
  168. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/package.json +0 -4
  169. package/___internal-do-not-use-will-break-in-patch/artifacts/package.json +0 -4
  170. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.d.ts.map +0 -1
  171. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.d.ts.map +0 -1
  172. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.d.ts.map +0 -1
  173. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.d.ts.map +0 -1
  174. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.d.ts.map +0 -1
  175. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.d.ts.map +0 -1
  176. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.d.ts.map +0 -1
  177. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/artifacts.d.ts.map +0 -1
  178. /package/dist/{common-1a350e11.cjs.js → common-5933f758.cjs.js} +0 -0
  179. /package/dist/{common-29fc82e6.esm.js → common-ea5c441a.esm.js} +0 -0
  180. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.d.ts +0 -0
  181. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.d.ts +0 -0
  182. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.d.ts +0 -0
  183. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.d.ts +0 -0
  184. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.d.ts +0 -0
  185. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.d.ts +0 -0
  186. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.d.ts +0 -0
  187. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.d.ts +0 -0
@@ -1,381 +1,381 @@
1
- import { g } from '../../..'
2
- import { type ListMetaSource, getAdminMetaForRelationshipField } from '../../../lib/admin-meta'
3
- import {
4
- type BaseListTypeInfo,
5
- type CommonFieldConfig,
6
- type FieldTypeFunc,
7
- type JSONValue,
8
- type ListSortDescriptor,
9
- fieldType,
10
- } from '../../../types'
11
- import type { controller } from './views'
12
-
13
- type ListKeyFromRef<Ref extends string> = Ref extends `${infer ListKey}.${string}` ? ListKey : Ref
14
-
15
- // This is the default display mode for Relationships
16
- type SelectDisplayConfig<ListTypeInfo extends BaseListTypeInfo, Ref extends string> = {
17
- ui?: {
18
- // Sets the relationship to display as a Select field
19
- displayMode?: 'select'
20
- /**
21
- * The path of the field to use from the related list for item labels in the select.
22
- * Defaults to the labelField (if set) on the related list.
23
- */
24
- labelField?: string
25
- /**
26
- * The paths of the fields to use from the related list when searching in the select.
27
- * Defaults to the initialSearchFields (if set) on the related list.
28
- */
29
- searchFields?: string[]
30
- /**
31
- * The filter to apply when shown in the select.
32
- * Defaults to the initialSort (if set) on the related list.
33
- */
34
- filter?: ListTypeInfo['all']['lists'][ListKeyFromRef<Ref>]['inputs']['where']
35
- /**
36
- * The sort to apply when shown in the select.
37
- * Defaults to the initialSort (if set) on the related list.
38
- */
39
- sort?: ListSortDescriptor<string>
40
- }
41
- }
42
-
43
- type CountDisplayConfig = {
44
- many: true
45
- ui?: {
46
- // Sets the relationship to display as a count
47
- displayMode: 'count'
48
- itemView: {
49
- fieldMode: 'read'
50
- }
51
- }
52
- }
53
-
54
- type TableDisplayConfig = {
55
- ref: `${string}.${string}`
56
- many: true
57
- ui?: {
58
- displayMode: 'table'
59
- initialSort?: ListSortDescriptor<string>
60
- columns?: string[]
61
-
62
- itemView: {
63
- fieldMode: 'read'
64
- }
65
- }
66
- }
67
-
68
- type OneDbConfig = {
69
- many?: false
70
- db?: {
71
- extendPrismaSchema?: (field: string) => string
72
- foreignKey?:
73
- | true
74
- | {
75
- map: string
76
- }
77
- }
78
- }
79
-
80
- type ManyDbConfig = {
81
- many: true
82
- db?: {
83
- relationName?: string
84
- extendPrismaSchema?: (field: string) => string
85
- }
86
- }
87
-
88
- function throwIfMissingFields(
89
- localListMeta: ListMetaSource,
90
- foreignListMeta: ListMetaSource,
91
- refLabelField: string,
92
- refSearchFields: string[],
93
- fieldKey: string
94
- ) {
95
- if (!(refLabelField in foreignListMeta.fieldsByKey)) {
96
- throw new Error(
97
- `"${refLabelField}" is not a field of list "${foreignListMeta.key}", configured as labelField for "${localListMeta.key}.${fieldKey}"`
98
- )
99
- }
100
-
101
- for (const searchFieldKey of refSearchFields) {
102
- const field = foreignListMeta.fieldsByKey[searchFieldKey]
103
- if (!field)
104
- throw new Error(
105
- `"${searchFieldKey}" is not a field of list "${foreignListMeta.key}", configured as searchField for "${localListMeta.key}.${fieldKey}"`
106
- )
107
-
108
- if (field.search === null)
109
- throw new Error(
110
- `"${searchFieldKey}" is not a searchable field of list "${foreignListMeta.key}", configured as searchField for "${localListMeta.key}.${fieldKey}"`
111
- )
112
- }
113
- }
114
-
115
- type ArrayOr<T> = T | T[]
116
-
117
- // TODO: add types based on list types
118
- type FieldTypeInfo = {
119
- item: undefined
120
- inputs: {
121
- where: any
122
- create: JSONValue | undefined
123
- update: JSONValue | undefined
124
- uniqueWhere: undefined
125
- orderBy: undefined
126
- }
127
- prisma: {
128
- create:
129
- | {
130
- connect?: ArrayOr<{ id?: string; [key: string]: unknown }>
131
- create?: any
132
- set?: ArrayOr<{ id?: string; [key: string]: unknown }>
133
- }
134
- | undefined
135
- | null
136
- update:
137
- | {
138
- connect?: ArrayOr<{ id?: string; [key: string]: unknown }>
139
- create?: any
140
- set?: ArrayOr<{ id?: string; [key: string]: unknown }>
141
- disconnect?: boolean | ArrayOr<{ id?: string; [key: string]: unknown }> | undefined
142
- }
143
- | undefined
144
- | null
145
- }
146
- }
147
-
148
- export type RelationshipFieldConfig<
149
- ListTypeInfo extends BaseListTypeInfo,
150
- Ref extends `${keyof ListTypeInfo['all']['lists'] & string}${'' | `.${string}`}`,
151
- > = CommonFieldConfig<ListTypeInfo, FieldTypeInfo> & {
152
- many?: boolean
153
- ref: Ref
154
- ui?: {
155
- hideCreate?: boolean
156
- }
157
- } & (OneDbConfig | ManyDbConfig) &
158
- (SelectDisplayConfig<ListTypeInfo, Ref> | CountDisplayConfig | TableDisplayConfig)
159
-
160
- export function relationship<
161
- ListTypeInfo extends BaseListTypeInfo,
162
- Ref extends `${keyof ListTypeInfo['all']['lists'] & string}${'' | `.${string}`}`,
163
- >({ ref, ...config }: RelationshipFieldConfig<ListTypeInfo, Ref>): FieldTypeFunc<ListTypeInfo> {
164
- const { many = false } = config
165
- const [foreignListKey, foreignFieldKey] = ref.split('.') as [string, string | undefined]
166
-
167
- return ({ fieldKey, listKey, lists }) => {
168
- const foreignList = lists[foreignListKey]
169
- if (!foreignList)
170
- throw new Error(`${listKey}.${fieldKey} points to ${ref}, but ${ref} doesn't exist`)
171
-
172
- const foreignListTypes = foreignList.types
173
- const commonConfig = {
174
- ...config,
175
- __ksTelemetryFieldTypeName: '@nixxie-cms/relationship',
176
- views: '@nixxie-cms/core/fields/types/relationship/views',
177
- getAdminMeta: (): Parameters<typeof controller>[0]['fieldMeta'] => {
178
- const adminMetaRoot = getAdminMetaForRelationshipField()
179
- const localListMeta = adminMetaRoot.listsByKey[listKey]
180
- const foreignListMeta = adminMetaRoot.listsByKey[foreignListKey]
181
-
182
- if (!foreignListMeta) {
183
- throw new Error(`The ref [${ref}] on relationship [${listKey}.${fieldKey}] is invalid`)
184
- }
185
-
186
- const refLabelField = foreignListMeta.labelField
187
- const refSearchFields = foreignListMeta.initialSearchFields
188
-
189
- const hasOmittedCreate =
190
- !lists[foreignListKey].types.relateTo[many ? 'many' : 'one'].create.getFields().create
191
- const hideCreate = config.ui?.hideCreate ?? hasOmittedCreate
192
- if (!hideCreate && hasOmittedCreate) {
193
- throw new Error(
194
- `${listKey}.${fieldKey} has ui.hideCreate: false, but the related list ${foreignListKey} has graphql.omit.create: true`
195
- )
196
- }
197
-
198
- if (config.ui?.displayMode === 'count') {
199
- if (config.ui.itemView?.fieldMode !== 'read') {
200
- throw new Error(
201
- `displayMode: 'count' on relationship fields requires itemView.fieldMode to be 'read' but ${listKey}.${fieldKey} does not have this set`
202
- )
203
- }
204
- return {
205
- displayMode: 'count',
206
- refListKey: foreignListKey,
207
- refFieldKey: foreignFieldKey,
208
- many,
209
- hideCreate,
210
- refLabelField,
211
- refSearchFields,
212
- }
213
- }
214
-
215
- if (config.ui?.displayMode === 'table') {
216
- if (!foreignFieldKey) {
217
- throw new Error(
218
- `Using a two-sided relationship (\`ref\` must specify "List.fieldKey", not just "List") is required when using displayMode: 'table' for relationship fields but ${listKey}.${fieldKey} has \`ref: ${JSON.stringify(ref)}\``
219
- )
220
- }
221
- if (config.ui.itemView?.fieldMode !== 'read') {
222
- throw new Error(
223
- `displayMode: 'table' on relationship fields currently requires itemView.fieldMode to be 'read' but ${listKey}.${fieldKey} does not have this set`
224
- )
225
- }
226
- for (const key of config.ui.columns ?? []) {
227
- if (!(key in foreignListMeta.fieldsByKey)) {
228
- throw new Error(
229
- `The field "${foreignListMeta.key}.${key}" does not exist, configured as a column for "${localListMeta.key}.${fieldKey}"`
230
- )
231
- }
232
- }
233
- if (config.ui.initialSort) {
234
- const field = foreignListMeta.fieldsByKey[config.ui.initialSort.field]
235
- if (!field) {
236
- throw new Error(
237
- `The field "${foreignListMeta.key}.${config.ui.initialSort.field}" does not exist, configured as the initialSort field for "${localListMeta.key}.${fieldKey}"`
238
- )
239
- }
240
- if (!field.isOrderable) {
241
- throw new Error(
242
- `The field "${foreignListMeta.key}.${config.ui.initialSort.field}" is not orderable, configured as the initialSort field for "${localListMeta.key}.${fieldKey}"`
243
- )
244
- }
245
- }
246
- return {
247
- displayMode: 'table',
248
- refListKey: foreignListKey,
249
- refFieldKey: foreignFieldKey,
250
- initialSort: config.ui.initialSort ?? foreignListMeta.initialSort ?? null,
251
- columns: config.ui.columns ?? null,
252
- many,
253
- hideCreate,
254
- refLabelField,
255
- refSearchFields,
256
- }
257
- }
258
-
259
- // prefer the local definition to the foreign list, if provided
260
- const specificRefLabelField = config.ui?.labelField ?? refLabelField
261
- const specificRefSearchFields = config.ui?.searchFields ?? refSearchFields
262
- throwIfMissingFields(
263
- localListMeta,
264
- foreignListMeta,
265
- specificRefLabelField,
266
- specificRefSearchFields,
267
- fieldKey
268
- )
269
- return {
270
- displayMode: 'select',
271
- refListKey: foreignListKey,
272
- refFieldKey: foreignFieldKey,
273
- many,
274
- hideCreate,
275
- refLabelField: specificRefLabelField,
276
- refSearchFields: specificRefSearchFields,
277
- filter: config.ui?.filter ?? null,
278
- sort: config.ui?.sort ?? foreignListMeta.initialSort ?? null,
279
- }
280
- },
281
- }
282
-
283
- if (config.many) {
284
- return fieldType({
285
- kind: 'relation',
286
- mode: 'many',
287
- list: foreignListKey,
288
- field: foreignFieldKey,
289
- relationName: config.db?.relationName,
290
- extendPrismaSchema: config.db?.extendPrismaSchema,
291
- })({
292
- ...commonConfig,
293
- input: {
294
- where: {
295
- arg: g.arg({ type: foreignListTypes.relateTo.many.where }),
296
- resolve(value, _context, resolve) {
297
- return resolve(value)
298
- },
299
- },
300
- create: {
301
- arg: g.arg({ type: foreignListTypes.relateTo.many.create }),
302
- async resolve(value, _context, resolve) {
303
- return resolve(value)
304
- },
305
- },
306
- update: {
307
- arg: g.arg({ type: foreignListTypes.relateTo.many.update }),
308
- async resolve(value, _context, resolve) {
309
- return resolve(value)
310
- },
311
- },
312
- },
313
- output: g.field({
314
- args: foreignListTypes.findManyArgs,
315
- type: g.list(g.nonNull(foreignListTypes.output)),
316
- resolve({ value }, args) {
317
- return value.findMany(args)
318
- },
319
- }),
320
- extraOutputFields: {
321
- [`${fieldKey}Count`]: g.field({
322
- type: g.Int,
323
- args: {
324
- where: g.arg({
325
- type: g.nonNull(foreignListTypes.where),
326
- defaultValue: {},
327
- }),
328
- },
329
- resolve({ value }, args) {
330
- return value.count({
331
- where: args.where,
332
- })
333
- },
334
- }),
335
- },
336
- })
337
- }
338
-
339
- return fieldType({
340
- kind: 'relation',
341
- mode: 'one',
342
- list: foreignListKey,
343
- field: foreignFieldKey,
344
- foreignKey: config.db?.foreignKey,
345
- extendPrismaSchema: config.db?.extendPrismaSchema,
346
- })({
347
- ...commonConfig,
348
- input: {
349
- where: {
350
- arg: g.arg({ type: foreignListTypes.where }),
351
- resolve(value, _context, resolve) {
352
- return resolve(value)
353
- },
354
- },
355
- uniqueWhere: {
356
- arg: g.arg({ type: foreignListTypes.uniqueWhere }),
357
- },
358
-
359
- create: foreignListTypes.relateTo.one.create && {
360
- arg: g.arg({ type: foreignListTypes.relateTo.one.create }),
361
- async resolve(value, _context, resolve) {
362
- return resolve(value)
363
- },
364
- },
365
-
366
- update: foreignListTypes.relateTo.one.update && {
367
- arg: g.arg({ type: foreignListTypes.relateTo.one.update }),
368
- async resolve(value, _context, resolve) {
369
- return resolve(value)
370
- },
371
- },
372
- },
373
- output: g.field({
374
- type: foreignListTypes.output,
375
- resolve({ value }) {
376
- return value()
377
- },
378
- }),
379
- })
380
- }
381
- }
1
+ import { g } from '../../..'
2
+ import { type ListMetaSource, getAdminMetaForRelationshipField } from '../../../lib/admin-meta'
3
+ import {
4
+ type BaseListTypeInfo,
5
+ type CommonFieldConfig,
6
+ type FieldTypeFunc,
7
+ type JSONValue,
8
+ type ListSortDescriptor,
9
+ fieldType,
10
+ } from '../../../types'
11
+ import type { controller } from './views'
12
+
13
+ type ListKeyFromRef<Ref extends string> = Ref extends `${infer ListKey}.${string}` ? ListKey : Ref
14
+
15
+ // This is the default display mode for Relationships
16
+ type SelectDisplayConfig<ListTypeInfo extends BaseListTypeInfo, Ref extends string> = {
17
+ ui?: {
18
+ // Sets the relationship to display as a Select field
19
+ displayMode?: 'select'
20
+ /**
21
+ * The path of the field to use from the related list for item labels in the select.
22
+ * Defaults to the labelField (if set) on the related list.
23
+ */
24
+ labelField?: string
25
+ /**
26
+ * The paths of the fields to use from the related list when searching in the select.
27
+ * Defaults to the initialSearchFields (if set) on the related list.
28
+ */
29
+ searchFields?: string[]
30
+ /**
31
+ * The filter to apply when shown in the select.
32
+ * Defaults to the initialSort (if set) on the related list.
33
+ */
34
+ filter?: ListTypeInfo['all']['lists'][ListKeyFromRef<Ref>]['inputs']['where']
35
+ /**
36
+ * The sort to apply when shown in the select.
37
+ * Defaults to the initialSort (if set) on the related list.
38
+ */
39
+ sort?: ListSortDescriptor<string>
40
+ }
41
+ }
42
+
43
+ type CountDisplayConfig = {
44
+ many: true
45
+ ui?: {
46
+ // Sets the relationship to display as a count
47
+ displayMode: 'count'
48
+ itemView: {
49
+ fieldMode: 'read'
50
+ }
51
+ }
52
+ }
53
+
54
+ type TableDisplayConfig = {
55
+ ref: `${string}.${string}`
56
+ many: true
57
+ ui?: {
58
+ displayMode: 'table'
59
+ initialSort?: ListSortDescriptor<string>
60
+ columns?: string[]
61
+
62
+ itemView: {
63
+ fieldMode: 'read'
64
+ }
65
+ }
66
+ }
67
+
68
+ type OneDbConfig = {
69
+ many?: false
70
+ db?: {
71
+ extendPrismaSchema?: (field: string) => string
72
+ foreignKey?:
73
+ | true
74
+ | {
75
+ map: string
76
+ }
77
+ }
78
+ }
79
+
80
+ type ManyDbConfig = {
81
+ many: true
82
+ db?: {
83
+ relationName?: string
84
+ extendPrismaSchema?: (field: string) => string
85
+ }
86
+ }
87
+
88
+ function throwIfMissingFields(
89
+ localListMeta: ListMetaSource,
90
+ foreignListMeta: ListMetaSource,
91
+ refLabelField: string,
92
+ refSearchFields: string[],
93
+ fieldKey: string
94
+ ) {
95
+ if (!(refLabelField in foreignListMeta.fieldsByKey)) {
96
+ throw new Error(
97
+ `"${refLabelField}" is not a field of list "${foreignListMeta.key}", configured as labelField for "${localListMeta.key}.${fieldKey}"`
98
+ )
99
+ }
100
+
101
+ for (const searchFieldKey of refSearchFields) {
102
+ const field = foreignListMeta.fieldsByKey[searchFieldKey]
103
+ if (!field)
104
+ throw new Error(
105
+ `"${searchFieldKey}" is not a field of list "${foreignListMeta.key}", configured as searchField for "${localListMeta.key}.${fieldKey}"`
106
+ )
107
+
108
+ if (field.search === null)
109
+ throw new Error(
110
+ `"${searchFieldKey}" is not a searchable field of list "${foreignListMeta.key}", configured as searchField for "${localListMeta.key}.${fieldKey}"`
111
+ )
112
+ }
113
+ }
114
+
115
+ type ArrayOr<T> = T | T[]
116
+
117
+ // TODO: add types based on list types
118
+ type FieldTypeInfo = {
119
+ item: undefined
120
+ inputs: {
121
+ where: any
122
+ create: JSONValue | undefined
123
+ update: JSONValue | undefined
124
+ uniqueWhere: undefined
125
+ orderBy: undefined
126
+ }
127
+ prisma: {
128
+ create:
129
+ | {
130
+ connect?: ArrayOr<{ id?: string; [key: string]: unknown }>
131
+ create?: any
132
+ set?: ArrayOr<{ id?: string; [key: string]: unknown }>
133
+ }
134
+ | undefined
135
+ | null
136
+ update:
137
+ | {
138
+ connect?: ArrayOr<{ id?: string; [key: string]: unknown }>
139
+ create?: any
140
+ set?: ArrayOr<{ id?: string; [key: string]: unknown }>
141
+ disconnect?: boolean | ArrayOr<{ id?: string; [key: string]: unknown }> | undefined
142
+ }
143
+ | undefined
144
+ | null
145
+ }
146
+ }
147
+
148
+ export type RelationshipFieldConfig<
149
+ ListTypeInfo extends BaseListTypeInfo,
150
+ Ref extends `${keyof ListTypeInfo['all']['lists'] & string}${'' | `.${string}`}`,
151
+ > = CommonFieldConfig<ListTypeInfo, FieldTypeInfo> & {
152
+ many?: boolean
153
+ ref: Ref
154
+ ui?: {
155
+ hideCreate?: boolean
156
+ }
157
+ } & (OneDbConfig | ManyDbConfig) &
158
+ (SelectDisplayConfig<ListTypeInfo, Ref> | CountDisplayConfig | TableDisplayConfig)
159
+
160
+ export function relationship<
161
+ ListTypeInfo extends BaseListTypeInfo,
162
+ Ref extends `${keyof ListTypeInfo['all']['lists'] & string}${'' | `.${string}`}`,
163
+ >({ ref, ...config }: RelationshipFieldConfig<ListTypeInfo, Ref>): FieldTypeFunc<ListTypeInfo> {
164
+ const { many = false } = config
165
+ const [foreignListKey, foreignFieldKey] = ref.split('.') as [string, string | undefined]
166
+
167
+ return ({ fieldKey, listKey, lists }) => {
168
+ const foreignList = lists[foreignListKey]
169
+ if (!foreignList)
170
+ throw new Error(`${listKey}.${fieldKey} points to ${ref}, but ${ref} doesn't exist`)
171
+
172
+ const foreignListTypes = foreignList.types
173
+ const commonConfig = {
174
+ ...config,
175
+ __nxTelemetryFieldTypeName: '@nixxie-cms/relationship',
176
+ views: '@nixxie-cms/core/fields/types/relationship/views',
177
+ getAdminMeta: (): Parameters<typeof controller>[0]['fieldMeta'] => {
178
+ const adminMetaRoot = getAdminMetaForRelationshipField()
179
+ const localListMeta = adminMetaRoot.listsByKey[listKey]
180
+ const foreignListMeta = adminMetaRoot.listsByKey[foreignListKey]
181
+
182
+ if (!foreignListMeta) {
183
+ throw new Error(`The ref [${ref}] on relationship [${listKey}.${fieldKey}] is invalid`)
184
+ }
185
+
186
+ const refLabelField = foreignListMeta.labelField
187
+ const refSearchFields = foreignListMeta.initialSearchFields
188
+
189
+ const hasOmittedCreate =
190
+ !lists[foreignListKey].types.relateTo[many ? 'many' : 'one'].create.getFields().create
191
+ const hideCreate = config.ui?.hideCreate ?? hasOmittedCreate
192
+ if (!hideCreate && hasOmittedCreate) {
193
+ throw new Error(
194
+ `${listKey}.${fieldKey} has ui.hideCreate: false, but the related list ${foreignListKey} has graphql.omit.create: true`
195
+ )
196
+ }
197
+
198
+ if (config.ui?.displayMode === 'count') {
199
+ if (config.ui.itemView?.fieldMode !== 'read') {
200
+ throw new Error(
201
+ `displayMode: 'count' on relationship fields requires itemView.fieldMode to be 'read' but ${listKey}.${fieldKey} does not have this set`
202
+ )
203
+ }
204
+ return {
205
+ displayMode: 'count',
206
+ refListKey: foreignListKey,
207
+ refFieldKey: foreignFieldKey,
208
+ many,
209
+ hideCreate,
210
+ refLabelField,
211
+ refSearchFields,
212
+ }
213
+ }
214
+
215
+ if (config.ui?.displayMode === 'table') {
216
+ if (!foreignFieldKey) {
217
+ throw new Error(
218
+ `Using a two-sided relationship (\`ref\` must specify "List.fieldKey", not just "List") is required when using displayMode: 'table' for relationship fields but ${listKey}.${fieldKey} has \`ref: ${JSON.stringify(ref)}\``
219
+ )
220
+ }
221
+ if (config.ui.itemView?.fieldMode !== 'read') {
222
+ throw new Error(
223
+ `displayMode: 'table' on relationship fields currently requires itemView.fieldMode to be 'read' but ${listKey}.${fieldKey} does not have this set`
224
+ )
225
+ }
226
+ for (const key of config.ui.columns ?? []) {
227
+ if (!(key in foreignListMeta.fieldsByKey)) {
228
+ throw new Error(
229
+ `The field "${foreignListMeta.key}.${key}" does not exist, configured as a column for "${localListMeta.key}.${fieldKey}"`
230
+ )
231
+ }
232
+ }
233
+ if (config.ui.initialSort) {
234
+ const field = foreignListMeta.fieldsByKey[config.ui.initialSort.field]
235
+ if (!field) {
236
+ throw new Error(
237
+ `The field "${foreignListMeta.key}.${config.ui.initialSort.field}" does not exist, configured as the initialSort field for "${localListMeta.key}.${fieldKey}"`
238
+ )
239
+ }
240
+ if (!field.isOrderable) {
241
+ throw new Error(
242
+ `The field "${foreignListMeta.key}.${config.ui.initialSort.field}" is not orderable, configured as the initialSort field for "${localListMeta.key}.${fieldKey}"`
243
+ )
244
+ }
245
+ }
246
+ return {
247
+ displayMode: 'table',
248
+ refListKey: foreignListKey,
249
+ refFieldKey: foreignFieldKey,
250
+ initialSort: config.ui.initialSort ?? foreignListMeta.initialSort ?? null,
251
+ columns: config.ui.columns ?? null,
252
+ many,
253
+ hideCreate,
254
+ refLabelField,
255
+ refSearchFields,
256
+ }
257
+ }
258
+
259
+ // prefer the local definition to the foreign list, if provided
260
+ const specificRefLabelField = config.ui?.labelField ?? refLabelField
261
+ const specificRefSearchFields = config.ui?.searchFields ?? refSearchFields
262
+ throwIfMissingFields(
263
+ localListMeta,
264
+ foreignListMeta,
265
+ specificRefLabelField,
266
+ specificRefSearchFields,
267
+ fieldKey
268
+ )
269
+ return {
270
+ displayMode: 'select',
271
+ refListKey: foreignListKey,
272
+ refFieldKey: foreignFieldKey,
273
+ many,
274
+ hideCreate,
275
+ refLabelField: specificRefLabelField,
276
+ refSearchFields: specificRefSearchFields,
277
+ filter: config.ui?.filter ?? null,
278
+ sort: config.ui?.sort ?? foreignListMeta.initialSort ?? null,
279
+ }
280
+ },
281
+ }
282
+
283
+ if (config.many) {
284
+ return fieldType({
285
+ kind: 'relation',
286
+ mode: 'many',
287
+ list: foreignListKey,
288
+ field: foreignFieldKey,
289
+ relationName: config.db?.relationName,
290
+ extendPrismaSchema: config.db?.extendPrismaSchema,
291
+ })({
292
+ ...commonConfig,
293
+ input: {
294
+ where: {
295
+ arg: g.arg({ type: foreignListTypes.relateTo.many.where }),
296
+ resolve(value, _context, resolve) {
297
+ return resolve(value)
298
+ },
299
+ },
300
+ create: {
301
+ arg: g.arg({ type: foreignListTypes.relateTo.many.create }),
302
+ async resolve(value, _context, resolve) {
303
+ return resolve(value)
304
+ },
305
+ },
306
+ update: {
307
+ arg: g.arg({ type: foreignListTypes.relateTo.many.update }),
308
+ async resolve(value, _context, resolve) {
309
+ return resolve(value)
310
+ },
311
+ },
312
+ },
313
+ output: g.field({
314
+ args: foreignListTypes.findManyArgs,
315
+ type: g.list(g.nonNull(foreignListTypes.output)),
316
+ resolve({ value }, args) {
317
+ return value.findMany(args)
318
+ },
319
+ }),
320
+ extraOutputFields: {
321
+ [`${fieldKey}Count`]: g.field({
322
+ type: g.Int,
323
+ args: {
324
+ where: g.arg({
325
+ type: g.nonNull(foreignListTypes.where),
326
+ defaultValue: {},
327
+ }),
328
+ },
329
+ resolve({ value }, args) {
330
+ return value.count({
331
+ where: args.where,
332
+ })
333
+ },
334
+ }),
335
+ },
336
+ })
337
+ }
338
+
339
+ return fieldType({
340
+ kind: 'relation',
341
+ mode: 'one',
342
+ list: foreignListKey,
343
+ field: foreignFieldKey,
344
+ foreignKey: config.db?.foreignKey,
345
+ extendPrismaSchema: config.db?.extendPrismaSchema,
346
+ })({
347
+ ...commonConfig,
348
+ input: {
349
+ where: {
350
+ arg: g.arg({ type: foreignListTypes.where }),
351
+ resolve(value, _context, resolve) {
352
+ return resolve(value)
353
+ },
354
+ },
355
+ uniqueWhere: {
356
+ arg: g.arg({ type: foreignListTypes.uniqueWhere }),
357
+ },
358
+
359
+ create: foreignListTypes.relateTo.one.create && {
360
+ arg: g.arg({ type: foreignListTypes.relateTo.one.create }),
361
+ async resolve(value, _context, resolve) {
362
+ return resolve(value)
363
+ },
364
+ },
365
+
366
+ update: foreignListTypes.relateTo.one.update && {
367
+ arg: g.arg({ type: foreignListTypes.relateTo.one.update }),
368
+ async resolve(value, _context, resolve) {
369
+ return resolve(value)
370
+ },
371
+ },
372
+ },
373
+ output: g.field({
374
+ type: foreignListTypes.output,
375
+ resolve({ value }) {
376
+ return value()
377
+ },
378
+ }),
379
+ })
380
+ }
381
+ }