@nixxie-cms/core 1.0.3 → 2.0.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.
Files changed (203) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/CHANGES-1.1.md +134 -0
  3. package/context/dist/nixxie-cms-core-context.cjs.js +4 -3
  4. package/context/dist/nixxie-cms-core-context.esm.js +3 -2
  5. package/dist/declarations/src/access.d.ts +2 -2
  6. package/dist/declarations/src/access.d.ts.map +1 -1
  7. package/dist/declarations/src/admin-ui/components/Navigation.d.ts +2 -2
  8. package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
  9. package/dist/declarations/src/admin-ui/context.d.ts +6 -6
  10. package/dist/declarations/src/admin-ui/context.d.ts.map +1 -1
  11. package/dist/declarations/src/admin-ui/utils/Fields.d.ts +3 -3
  12. package/dist/declarations/src/admin-ui/utils/Fields.d.ts.map +1 -1
  13. package/dist/declarations/src/admin-ui/utils/filters.d.ts +5 -5
  14. package/dist/declarations/src/admin-ui/utils/filters.d.ts.map +1 -1
  15. package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts +3 -3
  16. package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts.map +1 -1
  17. package/dist/declarations/src/admin-ui/utils/utils.d.ts +2 -2
  18. package/dist/declarations/src/admin-ui/utils/utils.d.ts.map +1 -1
  19. package/dist/declarations/src/context.d.ts +1 -1
  20. package/dist/declarations/src/context.d.ts.map +1 -1
  21. package/dist/declarations/src/fields/types/bigInt/index.d.ts +3 -3
  22. package/dist/declarations/src/fields/types/bigInt/index.d.ts.map +1 -1
  23. package/dist/declarations/src/fields/types/bytes/index.d.ts +3 -3
  24. package/dist/declarations/src/fields/types/bytes/index.d.ts.map +1 -1
  25. package/dist/declarations/src/fields/types/calendarDay/index.d.ts +3 -3
  26. package/dist/declarations/src/fields/types/calendarDay/index.d.ts.map +1 -1
  27. package/dist/declarations/src/fields/types/checkbox/index.d.ts +3 -3
  28. package/dist/declarations/src/fields/types/checkbox/index.d.ts.map +1 -1
  29. package/dist/declarations/src/fields/types/decimal/index.d.ts +3 -3
  30. package/dist/declarations/src/fields/types/decimal/index.d.ts.map +1 -1
  31. package/dist/declarations/src/fields/types/file/index.d.ts +4 -4
  32. package/dist/declarations/src/fields/types/file/index.d.ts.map +1 -1
  33. package/dist/declarations/src/fields/types/float/index.d.ts +3 -3
  34. package/dist/declarations/src/fields/types/float/index.d.ts.map +1 -1
  35. package/dist/declarations/src/fields/types/image/index.d.ts +4 -4
  36. package/dist/declarations/src/fields/types/image/index.d.ts.map +1 -1
  37. package/dist/declarations/src/fields/types/integer/index.d.ts +3 -3
  38. package/dist/declarations/src/fields/types/integer/index.d.ts.map +1 -1
  39. package/dist/declarations/src/fields/types/json/index.d.ts +3 -3
  40. package/dist/declarations/src/fields/types/json/index.d.ts.map +1 -1
  41. package/dist/declarations/src/fields/types/multiselect/index.d.ts +3 -3
  42. package/dist/declarations/src/fields/types/multiselect/index.d.ts.map +1 -1
  43. package/dist/declarations/src/fields/types/multiselect/views/index.d.ts.map +1 -1
  44. package/dist/declarations/src/fields/types/password/index.d.ts +3 -3
  45. package/dist/declarations/src/fields/types/password/index.d.ts.map +1 -1
  46. package/dist/declarations/src/fields/types/relationship/index.d.ts +8 -8
  47. package/dist/declarations/src/fields/types/relationship/index.d.ts.map +1 -1
  48. package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts +3 -3
  49. package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts.map +1 -1
  50. package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts +3 -3
  51. package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts.map +1 -1
  52. package/dist/declarations/src/fields/types/relationship/views/index.d.ts +3 -3
  53. package/dist/declarations/src/fields/types/relationship/views/index.d.ts.map +1 -1
  54. package/dist/declarations/src/fields/types/relationship/views/types.d.ts +3 -3
  55. package/dist/declarations/src/fields/types/relationship/views/types.d.ts.map +1 -1
  56. package/dist/declarations/src/fields/types/select/index.d.ts +3 -3
  57. package/dist/declarations/src/fields/types/select/index.d.ts.map +1 -1
  58. package/dist/declarations/src/fields/types/text/index.d.ts +3 -3
  59. package/dist/declarations/src/fields/types/text/index.d.ts.map +1 -1
  60. package/dist/declarations/src/fields/types/timestamp/index.d.ts +3 -3
  61. package/dist/declarations/src/fields/types/timestamp/index.d.ts.map +1 -1
  62. package/dist/declarations/src/fields/types/virtual/index.d.ts +7 -7
  63. package/dist/declarations/src/fields/types/virtual/index.d.ts.map +1 -1
  64. package/dist/declarations/src/helpers.d.ts +249 -13
  65. package/dist/declarations/src/helpers.d.ts.map +1 -1
  66. package/dist/declarations/src/index.d.ts +9 -4
  67. package/dist/declarations/src/index.d.ts.map +1 -1
  68. package/dist/declarations/src/internal-unstable/admin-ui/pages/ListPage/index.d.ts.map +1 -1
  69. package/dist/declarations/src/lib/admin-meta.d.ts +11 -11
  70. package/dist/declarations/src/lib/admin-meta.d.ts.map +1 -1
  71. package/dist/declarations/src/lib/core/access-control.d.ts +18 -18
  72. package/dist/declarations/src/lib/core/access-control.d.ts.map +1 -1
  73. package/dist/declarations/src/lib/core/cascade.d.ts +47 -0
  74. package/dist/declarations/src/lib/core/cascade.d.ts.map +1 -0
  75. package/dist/declarations/src/lib/core/initialise-lists.d.ts +27 -24
  76. package/dist/declarations/src/lib/core/initialise-lists.d.ts.map +1 -1
  77. package/dist/declarations/src/lib/env.d.ts +9 -0
  78. package/dist/declarations/src/lib/env.d.ts.map +1 -0
  79. package/dist/declarations/src/lib/system.d.ts +1 -1
  80. package/dist/declarations/src/lib/system.d.ts.map +1 -1
  81. package/dist/declarations/src/list-features.d.ts +162 -0
  82. package/dist/declarations/src/list-features.d.ts.map +1 -0
  83. package/dist/declarations/src/schema.d.ts +24 -23
  84. package/dist/declarations/src/schema.d.ts.map +1 -1
  85. package/dist/declarations/src/session.d.ts +75 -0
  86. package/dist/declarations/src/session.d.ts.map +1 -1
  87. package/dist/declarations/src/types/admin-meta.d.ts +11 -11
  88. package/dist/declarations/src/types/admin-meta.d.ts.map +1 -1
  89. package/dist/declarations/src/types/config/access-control.d.ts +42 -42
  90. package/dist/declarations/src/types/config/access-control.d.ts.map +1 -1
  91. package/dist/declarations/src/types/config/fields.d.ts +19 -19
  92. package/dist/declarations/src/types/config/fields.d.ts.map +1 -1
  93. package/dist/declarations/src/types/config/hooks.d.ts +131 -131
  94. package/dist/declarations/src/types/config/hooks.d.ts.map +1 -1
  95. package/dist/declarations/src/types/config/index.d.ts +190 -8
  96. package/dist/declarations/src/types/config/index.d.ts.map +1 -1
  97. package/dist/declarations/src/types/config/lists.d.ts +146 -108
  98. package/dist/declarations/src/types/config/lists.d.ts.map +1 -1
  99. package/dist/declarations/src/types/context.d.ts +507 -47
  100. package/dist/declarations/src/types/context.d.ts.map +1 -1
  101. package/dist/declarations/src/types/next-fields.d.ts +28 -28
  102. package/dist/declarations/src/types/next-fields.d.ts.map +1 -1
  103. package/dist/declarations/src/types/type-info.d.ts +3 -3
  104. package/dist/declarations/src/types/type-info.d.ts.map +1 -1
  105. package/dist/{express-455ae20c.cjs.js → express-84d534c2.cjs.js} +6 -6
  106. package/dist/{express-7559ca2d.esm.js → express-d0a4ce99.esm.js} +6 -6
  107. package/dist/{index-15c8f81e.esm.js → index-5d8b0b4e.esm.js} +363 -183
  108. package/dist/index-6055753b.cjs.js +393 -0
  109. package/dist/{index-42045902.cjs.js → index-ac29f382.cjs.js} +363 -185
  110. package/dist/index-f1703b7b.esm.js +386 -0
  111. package/dist/nixxie-cms-core.cjs.js +1388 -30
  112. package/dist/nixxie-cms-core.esm.js +1362 -24
  113. package/dist/{non-null-graphql-add6bb3d.cjs.js → non-null-graphql-4a44c122.cjs.js} +1 -1
  114. package/dist/{non-null-graphql-a84ed64d.esm.js → non-null-graphql-8c5feaae.esm.js} +1 -1
  115. package/dist/{resolve-hooks-165a9ce2.cjs.js → resolve-hooks-10a5f84c.cjs.js} +240 -6
  116. package/dist/{resolve-hooks-6813a045.esm.js → resolve-hooks-9e676794.esm.js} +238 -7
  117. package/dist/{system-a321642d.cjs.js → system-6b37a5f8.cjs.js} +33 -7
  118. package/dist/{system-03e49e4f.esm.js → system-e591d821.esm.js} +33 -7
  119. package/fields/dist/nixxie-cms-core-fields.cjs.js +29 -576
  120. package/fields/dist/nixxie-cms-core-fields.esm.js +18 -565
  121. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +4 -2
  122. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +4 -2
  123. package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.cjs.js +1 -6
  124. package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.esm.js +1 -6
  125. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +4 -2
  126. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +4 -2
  127. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.js +4 -3
  128. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.esm.js +4 -3
  129. package/package.json +4 -4
  130. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +4 -3
  131. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +4 -3
  132. package/scripts/dist/nixxie-cms-core-scripts.cjs.js +4 -3
  133. package/scripts/dist/nixxie-cms-core-scripts.esm.js +4 -3
  134. package/session/dist/nixxie-cms-core-session.cjs.js +286 -0
  135. package/session/dist/nixxie-cms-core-session.esm.js +279 -1
  136. package/src/access.ts +25 -25
  137. package/src/admin-ui/admin-meta-graphql.ts +5 -5
  138. package/src/admin-ui/components/CreateButtonLink.tsx +46 -46
  139. package/src/admin-ui/components/Navigation.tsx +3 -3
  140. package/src/admin-ui/context.tsx +6 -6
  141. package/src/admin-ui/utils/Fields.tsx +241 -241
  142. package/src/admin-ui/utils/actionData.ts +36 -36
  143. package/src/admin-ui/utils/filters.ts +148 -148
  144. package/src/admin-ui/utils/useCreateItem.ts +171 -171
  145. package/src/admin-ui/utils/utils.tsx +127 -127
  146. package/src/context.ts +1 -1
  147. package/src/fields/non-null-graphql.ts +115 -115
  148. package/src/fields/types/bigInt/index.ts +6 -6
  149. package/src/fields/types/bytes/index.ts +6 -6
  150. package/src/fields/types/calendarDay/index.ts +18 -19
  151. package/src/fields/types/checkbox/index.ts +6 -6
  152. package/src/fields/types/decimal/index.ts +6 -6
  153. package/src/fields/types/file/index.ts +8 -8
  154. package/src/fields/types/float/index.ts +6 -6
  155. package/src/fields/types/image/index.ts +8 -8
  156. package/src/fields/types/integer/index.ts +6 -6
  157. package/src/fields/types/json/index.ts +5 -5
  158. package/src/fields/types/multiselect/index.ts +7 -7
  159. package/src/fields/types/multiselect/views/index.tsx +149 -151
  160. package/src/fields/types/password/index.ts +6 -6
  161. package/src/fields/types/relationship/index.ts +13 -13
  162. package/src/fields/types/relationship/views/ComboboxMany.tsx +110 -110
  163. package/src/fields/types/relationship/views/ComboboxSingle.tsx +115 -115
  164. package/src/fields/types/relationship/views/ContextualActions.tsx +139 -139
  165. package/src/fields/types/relationship/views/index.tsx +492 -492
  166. package/src/fields/types/relationship/views/types.ts +46 -46
  167. package/src/fields/types/relationship/views/useApolloQuery.ts +185 -185
  168. package/src/fields/types/relationship/views/useFilter.tsx +109 -109
  169. package/src/fields/types/select/index.ts +6 -6
  170. package/src/fields/types/text/index.ts +6 -6
  171. package/src/fields/types/timestamp/index.ts +23 -21
  172. package/src/fields/types/virtual/index.ts +11 -11
  173. package/src/helpers.ts +773 -42
  174. package/src/index.ts +66 -24
  175. package/src/internal-unstable/admin-ui/pages/ItemPage/common.tsx +4 -4
  176. package/src/internal-unstable/admin-ui/pages/ItemPage/index.tsx +5 -5
  177. package/src/internal-unstable/admin-ui/pages/ListPage/index.tsx +8 -8
  178. package/src/lib/admin-meta.ts +369 -369
  179. package/src/lib/context/createContext.ts +6 -0
  180. package/src/lib/core/access-control.ts +434 -434
  181. package/src/lib/core/cascade.ts +236 -0
  182. package/src/lib/core/initialise-lists.ts +49 -33
  183. package/src/lib/core/mutations/index.ts +7 -0
  184. package/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts +145 -145
  185. package/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts +71 -71
  186. package/src/lib/core/queries/output-field.ts +178 -178
  187. package/src/lib/env.ts +50 -0
  188. package/src/lib/id-field.ts +2 -2
  189. package/src/lib/system.ts +221 -207
  190. package/src/lib/typescript-schema-printer.ts +227 -227
  191. package/src/list-features.ts +476 -0
  192. package/src/schema.ts +92 -22
  193. package/src/session.ts +225 -0
  194. package/src/types/admin-meta.ts +218 -218
  195. package/src/types/config/access-control.ts +186 -186
  196. package/src/types/config/fields.ts +96 -96
  197. package/src/types/config/hooks.ts +529 -529
  198. package/src/types/config/index.ts +206 -7
  199. package/src/types/config/lists.ts +606 -565
  200. package/src/types/context.ts +592 -55
  201. package/src/types/next-fields.ts +31 -31
  202. package/src/types/type-info.ts +38 -38
  203. package/src/types/type-tests.ts +21 -21
@@ -1,6 +1,6 @@
1
1
  import type { SimpleFieldTypeInfo } from '../../../types'
2
2
  import {
3
- type BaseListTypeInfo,
3
+ type BaseCollectionTypeInfo,
4
4
  type CommonFieldConfig,
5
5
  type FieldTypeFunc,
6
6
  fieldType,
@@ -12,8 +12,8 @@ import { filters } from '../../filters'
12
12
  import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
13
13
  import type { controller } from './views'
14
14
 
15
- export type DecimalFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
16
- ListTypeInfo,
15
+ export type DecimalFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
16
+ CollectionTypeInfo,
17
17
  SimpleFieldTypeInfo<'Decimal'>
18
18
  > & {
19
19
  isIndexed?: boolean | 'unique'
@@ -40,9 +40,9 @@ function safeParseDecimal(value: string | null | undefined) {
40
40
  }
41
41
 
42
42
  // TODO: https://github.com/Nixxie/keystatic/blob/main/design-system/pkg/src/number-field/NumberField.tsx
43
- export function decimal<ListTypeInfo extends BaseListTypeInfo>(
44
- config: DecimalFieldConfig<ListTypeInfo> = {}
45
- ): FieldTypeFunc<ListTypeInfo> {
43
+ export function decimal<CollectionTypeInfo extends BaseCollectionTypeInfo>(
44
+ config: DecimalFieldConfig<CollectionTypeInfo> = {}
45
+ ): FieldTypeFunc<CollectionTypeInfo> {
46
46
  const {
47
47
  defaultValue: defaultValue_,
48
48
  isIndexed,
@@ -1,6 +1,6 @@
1
1
  import type {
2
2
  BaseNixxieTypeInfo,
3
- BaseListTypeInfo,
3
+ BaseCollectionTypeInfo,
4
4
  CommonFieldConfig,
5
5
  FieldHooks,
6
6
  FieldTypeFunc,
@@ -29,11 +29,11 @@ export type FieldTypeInfo = {
29
29
  }
30
30
  }
31
31
 
32
- export type FileFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
33
- ListTypeInfo,
32
+ export type FileFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
33
+ CollectionTypeInfo,
34
34
  FieldTypeInfo
35
35
  > & {
36
- storage: StorageStrategy<ListTypeInfo['all']>
36
+ storage: StorageStrategy<CollectionTypeInfo['all']>
37
37
  transformName?: (originalFilename: string) => MaybePromise<string>
38
38
  db?: {
39
39
  extendPrismaSchema?: (field: string) => string
@@ -81,9 +81,9 @@ async function inputResolver(
81
81
  return { filename, filesize }
82
82
  }
83
83
 
84
- export function file<ListTypeInfo extends BaseListTypeInfo>(
85
- config: FileFieldConfig<ListTypeInfo>
86
- ): FieldTypeFunc<ListTypeInfo> {
84
+ export function file<CollectionTypeInfo extends BaseCollectionTypeInfo>(
85
+ config: FileFieldConfig<CollectionTypeInfo>
86
+ ): FieldTypeFunc<CollectionTypeInfo> {
87
87
  const { transformName = defaultTransformName } = config
88
88
  return meta => {
89
89
  const { fieldKey } = meta
@@ -93,7 +93,7 @@ export function file<ListTypeInfo extends BaseListTypeInfo>(
93
93
  }
94
94
 
95
95
  const afterOperationResolver: Extract<
96
- FieldHooks<BaseListTypeInfo, FieldTypeInfo>['afterOperation'],
96
+ FieldHooks<BaseCollectionTypeInfo, FieldTypeInfo>['afterOperation'],
97
97
  (args: any) => any
98
98
  > = async function afterOperationResolver(args) {
99
99
  if (args.operation === 'update' || args.operation === 'delete') {
@@ -1,6 +1,6 @@
1
1
  import type { SimpleFieldTypeInfo } from '../../../types'
2
2
  import {
3
- type BaseListTypeInfo,
3
+ type BaseCollectionTypeInfo,
4
4
  type FieldTypeFunc,
5
5
  type CommonFieldConfig,
6
6
  fieldType,
@@ -11,8 +11,8 @@ import { filters } from '../../filters'
11
11
  import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
12
12
  import type { controller } from './views'
13
13
 
14
- export type FloatFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
15
- ListTypeInfo,
14
+ export type FloatFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
15
+ CollectionTypeInfo,
16
16
  SimpleFieldTypeInfo<'Float'>
17
17
  > & {
18
18
  isIndexed?: boolean | 'unique'
@@ -29,9 +29,9 @@ export type FloatFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFiel
29
29
  }
30
30
  }
31
31
 
32
- export function float<ListTypeInfo extends BaseListTypeInfo>(
33
- config: FloatFieldConfig<ListTypeInfo> = {}
34
- ): FieldTypeFunc<ListTypeInfo> {
32
+ export function float<CollectionTypeInfo extends BaseCollectionTypeInfo>(
33
+ config: FloatFieldConfig<CollectionTypeInfo> = {}
34
+ ): FieldTypeFunc<CollectionTypeInfo> {
35
35
  const { defaultValue: defaultValue_, isIndexed, validation = {} } = config
36
36
 
37
37
  const { isRequired = false, min, max } = validation
@@ -1,5 +1,5 @@
1
1
  import type {
2
- BaseListTypeInfo,
2
+ BaseCollectionTypeInfo,
3
3
  FieldTypeFunc,
4
4
  CommonFieldConfig,
5
5
  NixxieContext,
@@ -32,11 +32,11 @@ export type FieldTypeInfo = {
32
32
  }
33
33
  }
34
34
 
35
- export type ImageFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
36
- ListTypeInfo,
35
+ export type ImageFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
36
+ CollectionTypeInfo,
37
37
  FieldTypeInfo
38
38
  > & {
39
- storage: StorageStrategy<ListTypeInfo['all']>
39
+ storage: StorageStrategy<CollectionTypeInfo['all']>
40
40
  transformName?: (originalFilename: string, extension: string) => MaybePromise<string>
41
41
  db?: {
42
42
  extendPrismaSchema?: (field: string) => string
@@ -149,9 +149,9 @@ function isValidImageExtension(extension: string): extension is ImageExtension {
149
149
  return extensionsSet.has(extension)
150
150
  }
151
151
 
152
- export function image<ListTypeInfo extends BaseListTypeInfo>(
153
- config: ImageFieldConfig<ListTypeInfo>
154
- ): FieldTypeFunc<ListTypeInfo> {
152
+ export function image<CollectionTypeInfo extends BaseCollectionTypeInfo>(
153
+ config: ImageFieldConfig<CollectionTypeInfo>
154
+ ): FieldTypeFunc<CollectionTypeInfo> {
155
155
  const { transformName = defaultTransformName } = config
156
156
  return meta => {
157
157
  const { fieldKey } = meta
@@ -161,7 +161,7 @@ export function image<ListTypeInfo extends BaseListTypeInfo>(
161
161
  }
162
162
 
163
163
  const afterOperationResolver: Extract<
164
- FieldHooks<BaseListTypeInfo, FieldTypeInfo>['afterOperation'],
164
+ FieldHooks<BaseCollectionTypeInfo, FieldTypeInfo>['afterOperation'],
165
165
  (args: any) => any
166
166
  > = async function afterOperationResolver(args) {
167
167
  if (args.operation === 'update' || args.operation === 'delete') {
@@ -1,7 +1,7 @@
1
1
  import { g } from '../../..'
2
2
  import type { SimpleFieldTypeInfo } from '../../../types'
3
3
  import {
4
- type BaseListTypeInfo,
4
+ type BaseCollectionTypeInfo,
5
5
  type CommonFieldConfig,
6
6
  type FieldTypeFunc,
7
7
  fieldType,
@@ -11,8 +11,8 @@ import { filters } from '../../filters'
11
11
  import { defaultIsRequired, makeValidateHook } from '../../non-null-graphql'
12
12
  import type { controller } from './views'
13
13
 
14
- export type IntegerFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
15
- ListTypeInfo,
14
+ export type IntegerFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
15
+ CollectionTypeInfo,
16
16
  SimpleFieldTypeInfo<'Int'>
17
17
  > & {
18
18
  isIndexed?: boolean | 'unique'
@@ -33,9 +33,9 @@ export type IntegerFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFi
33
33
  const MAX_INT = 0x7fffffff
34
34
  const MIN_INT = -0x80000000
35
35
 
36
- export function integer<ListTypeInfo extends BaseListTypeInfo>(
37
- config: IntegerFieldConfig<ListTypeInfo> = {}
38
- ): FieldTypeFunc<ListTypeInfo> {
36
+ export function integer<CollectionTypeInfo extends BaseCollectionTypeInfo>(
37
+ config: IntegerFieldConfig<CollectionTypeInfo> = {}
38
+ ): FieldTypeFunc<CollectionTypeInfo> {
39
39
  const { defaultValue: defaultValue_, isIndexed, validation = {} } = config
40
40
 
41
41
  const { isRequired = false, min, max } = validation
@@ -1,6 +1,6 @@
1
1
  import { g } from '../../..'
2
2
  import {
3
- type BaseListTypeInfo,
3
+ type BaseCollectionTypeInfo,
4
4
  type CommonFieldConfig,
5
5
  fieldType,
6
6
  type FieldTypeFunc,
@@ -22,18 +22,18 @@ type FieldTypeInfo = {
22
22
  }
23
23
  }
24
24
 
25
- export type JsonFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
26
- ListTypeInfo,
25
+ export type JsonFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
26
+ CollectionTypeInfo,
27
27
  FieldTypeInfo
28
28
  > & {
29
29
  defaultValue?: JSONValue
30
30
  db?: { map?: string; extendPrismaSchema?: (field: string) => string }
31
31
  }
32
32
 
33
- export function json<ListTypeInfo extends BaseListTypeInfo>({
33
+ export function json<CollectionTypeInfo extends BaseCollectionTypeInfo>({
34
34
  defaultValue = null,
35
35
  ...config
36
- }: JsonFieldConfig<ListTypeInfo> = {}): FieldTypeFunc<ListTypeInfo> {
36
+ }: JsonFieldConfig<CollectionTypeInfo> = {}): FieldTypeFunc<CollectionTypeInfo> {
37
37
  return meta => {
38
38
  if ((config as any).isIndexed === 'unique') {
39
39
  throw Error("isIndexed: 'unique' is not a supported option for field type json")
@@ -2,7 +2,7 @@ import { g } from '../../..'
2
2
  import { humanize } from '../../../lib/utils'
3
3
  import type { JSONValue } from '../../../types'
4
4
  import {
5
- type BaseListTypeInfo,
5
+ type BaseCollectionTypeInfo,
6
6
  type CommonFieldConfig,
7
7
  type FieldData,
8
8
  fieldType,
@@ -26,8 +26,8 @@ type FieldTypeInfo = {
26
26
  }
27
27
  }
28
28
 
29
- export type MultiselectFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
30
- ListTypeInfo,
29
+ export type MultiselectFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
30
+ CollectionTypeInfo,
31
31
  FieldTypeInfo
32
32
  > &
33
33
  (
@@ -63,9 +63,9 @@ export type MultiselectFieldConfig<ListTypeInfo extends BaseListTypeInfo> = Comm
63
63
  const MAX_INT = 2147483647
64
64
  const MIN_INT = -2147483648
65
65
 
66
- export function multiselect<ListTypeInfo extends BaseListTypeInfo>(
67
- config: MultiselectFieldConfig<ListTypeInfo>
68
- ): FieldTypeFunc<ListTypeInfo> {
66
+ export function multiselect<CollectionTypeInfo extends BaseCollectionTypeInfo>(
67
+ config: MultiselectFieldConfig<CollectionTypeInfo>
68
+ ): FieldTypeFunc<CollectionTypeInfo> {
69
69
  const { defaultValue: defaultValue_, ui: { displayMode = 'select', ...ui } = {} } = config
70
70
 
71
71
  config.db ??= {}
@@ -165,7 +165,7 @@ export function multiselect<ListTypeInfo extends BaseListTypeInfo>(
165
165
  }
166
166
 
167
167
  function configToOptionsAndGraphQLType(
168
- config: MultiselectFieldConfig<BaseListTypeInfo>,
168
+ config: MultiselectFieldConfig<BaseCollectionTypeInfo>,
169
169
  meta: FieldData
170
170
  ) {
171
171
  if (config.type === 'integer') {
@@ -1,151 +1,149 @@
1
- import { useState } from 'react'
2
- import { useFilter, useListFormatter } from '@react-aria/i18n'
3
-
4
- import { Checkbox, CheckboxGroup } from '@keystar/ui/checkbox'
5
- import { Combobox, Item } from '@keystar/ui/combobox'
6
- import { VStack } from '@keystar/ui/layout'
7
- import { TagGroup } from '@keystar/ui/tag'
8
- import { Text } from '@keystar/ui/typography'
9
-
10
- import type {
11
- CellComponent,
12
- FieldController,
13
- FieldControllerConfig,
14
- FieldProps,
15
- } from '../../../../types'
16
-
17
- export function Field(props: FieldProps<typeof controller>) {
18
- if (props.field.displayMode === 'checkboxes') return <CheckboxesModeField {...props} />
19
- return <SelectModeField {...props} />
20
- }
21
-
22
- function SelectModeField(props: FieldProps<typeof controller>) {
23
- const { field, onChange, value } = props
24
- const [filterText, setFilterText] = useState('')
25
- const { contains } = useFilter({ sensitivity: 'base' })
26
- const items = field.options.filter(option => !value.some(x => x.value === option.value))
27
- const filteredItems = filterText ? items.filter(item => contains(item.label, filterText)) : items
28
-
29
- return (
30
- <VStack gap="regular">
31
- <Combobox
32
- label={field.label}
33
- description={field.description}
34
- isReadOnly={onChange === undefined}
35
- items={filteredItems}
36
- loadingState="idle"
37
- onInputChange={setFilterText}
38
- inputValue={filterText}
39
- // selectedKey={null}
40
- onSelectionChange={key => {
41
- if (key == null) return
42
- onChange?.([...value, field.valuesToOptionsWithStringValues[key]])
43
- }}
44
- width="auto"
45
- >
46
- {item => <Item key={item.value}>{item.label}</Item>}
47
- </Combobox>
48
-
49
- <TagGroup
50
- aria-label={`${field.label} selected items`}
51
- items={value}
52
- maxRows={2}
53
- onRemove={keys => {
54
- const key = keys.values().next().value
55
- onChange?.(value.filter(x => x.value !== key))
56
- }}
57
- renderEmptyState={() => (
58
- <Text color="neutralSecondary" size="small">
59
- No items…
60
- </Text>
61
- )}
62
- >
63
- {item => <Item key={item.value}>{item.label}</Item>}
64
- </TagGroup>
65
- </VStack>
66
- )
67
- }
68
-
69
- function CheckboxesModeField(props: FieldProps<typeof controller>) {
70
- const { field, onChange, value } = props
71
- return (
72
- <CheckboxGroup
73
- label={field.label}
74
- description={field.description}
75
- isReadOnly={onChange === undefined}
76
- value={value.map(x => x.value)}
77
- onChange={keys => {
78
- onChange?.(keys.map(key => field.valuesToOptionsWithStringValues[key]))
79
- }}
80
- >
81
- {field.options.map(option => (
82
- <Checkbox key={option.value} value={option.value}>
83
- {option.label}
84
- </Checkbox>
85
- ))}
86
- </CheckboxGroup>
87
- )
88
- }
89
-
90
- export const Cell: CellComponent<typeof controller> = ({ value = [], field }) => {
91
- const listFormatter = useListFormatter({ style: 'short', type: 'conjunction' })
92
- const labels = (value as string[]).map(x => field.valuesToOptionsWithStringValues[x].label)
93
-
94
- let cellContent = null
95
- if (value.length > 3) {
96
- cellContent = listFormatter.format([labels[0], `${value.length - 1} more`])
97
- } else {
98
- cellContent = listFormatter.format(labels)
99
- }
100
-
101
- return <Text>{cellContent}</Text>
102
- }
103
-
104
- export type AdminMultiSelectFieldMeta = {
105
- options: readonly { label: string; value: string | number }[]
106
- type: 'string' | 'integer' | 'enum'
107
- displayMode: 'checkboxes' | 'select'
108
- defaultValue: string[] | number[]
109
- }
110
-
111
- type Config = FieldControllerConfig<AdminMultiSelectFieldMeta>
112
- type Option = { label: string; value: string }
113
- type Value = readonly Option[]
114
-
115
- export function controller(config: Config): FieldController<Value, Option[]> & {
116
- displayMode: 'checkboxes' | 'select'
117
- options: Option[]
118
- type: 'string' | 'integer' | 'enum'
119
- valuesToOptionsWithStringValues: Record<string, Option>
120
- } {
121
- const optionsWithStringValues = config.fieldMeta.options.map(x => ({
122
- label: x.label,
123
- value: x.value.toString(),
124
- }))
125
-
126
- const valuesToOptionsWithStringValues = Object.fromEntries(
127
- optionsWithStringValues.map(option => [option.value, option])
128
- )
129
- const parseValue = (value: string) =>
130
- config.fieldMeta.type === 'integer' ? parseInt(value) : value
131
-
132
- return {
133
- fieldKey: config.fieldKey,
134
- label: config.label,
135
- description: config.description,
136
- displayMode: config.fieldMeta.displayMode,
137
- type: config.fieldMeta.type,
138
- options: optionsWithStringValues,
139
- valuesToOptionsWithStringValues,
140
- defaultValue: config.fieldMeta.defaultValue.map(x => valuesToOptionsWithStringValues[x]),
141
- deserialize: data => {
142
- // if we get null from the GraphQL API (which will only happen if field read access control failed)
143
- // we'll just show it as nothing being selected for now.
144
- const values: readonly string[] | readonly number[] = data[config.fieldKey] ?? []
145
- const selectedOptions = values.map(x => valuesToOptionsWithStringValues[x])
146
- return selectedOptions
147
- },
148
- serialize: value => ({ [config.fieldKey]: value.map(x => parseValue(x.value)) }),
149
- graphqlSelection: config.fieldKey,
150
- }
151
- }
1
+ import { useState } from 'react'
2
+ import { useFilter, useListFormatter } from '@react-aria/i18n'
3
+
4
+ import { Checkbox, CheckboxGroup } from '@keystar/ui/checkbox'
5
+ import { Combobox, Item } from '@keystar/ui/combobox'
6
+ import { VStack } from '@keystar/ui/layout'
7
+ import { TagGroup } from '@keystar/ui/tag'
8
+ import { Text } from '@keystar/ui/typography'
9
+
10
+ import type {
11
+ CellComponent,
12
+ FieldController,
13
+ FieldControllerConfig,
14
+ FieldProps,
15
+ } from '../../../../types'
16
+
17
+ export function Field(props: FieldProps<typeof controller>) {
18
+ if (props.field.displayMode === 'checkboxes') return <CheckboxesModeField {...props} />
19
+ return <SelectModeField {...props} />
20
+ }
21
+
22
+ function SelectModeField(props: FieldProps<typeof controller>) {
23
+ const { field, onChange, value } = props
24
+ const [filterText, setFilterText] = useState('')
25
+ const { contains } = useFilter({ sensitivity: 'base' })
26
+ const items = field.options.filter(option => !value.some(x => x.value === option.value))
27
+ const filteredItems = filterText ? items.filter(item => contains(item.label, filterText)) : items
28
+
29
+ return (
30
+ <VStack gap="regular">
31
+ <Combobox
32
+ label={field.label}
33
+ description={field.description}
34
+ isReadOnly={onChange === undefined}
35
+ items={filteredItems}
36
+ loadingState="idle"
37
+ onInputChange={setFilterText}
38
+ inputValue={filterText}
39
+ // selectedKey={null}
40
+ onSelectionChange={key => {
41
+ if (key == null) return
42
+ onChange?.([...value, field.valuesToOptionsWithStringValues[key]])
43
+ }}
44
+ width="auto"
45
+ >
46
+ {item => <Item key={item.value}>{item.label}</Item>}
47
+ </Combobox>
48
+
49
+ <TagGroup
50
+ aria-label={`${field.label} selected items`}
51
+ items={value}
52
+ maxRows={2}
53
+ onRemove={keys => {
54
+ const key = keys.values().next().value
55
+ onChange?.(value.filter(x => x.value !== key))
56
+ }}
57
+ renderEmptyState={() => (
58
+ <Text color="neutralSecondary" size="small">
59
+ No items…
60
+ </Text>
61
+ )}
62
+ >
63
+ {item => <Item key={item.value}>{item.label}</Item>}
64
+ </TagGroup>
65
+ </VStack>
66
+ )
67
+ }
68
+
69
+ function CheckboxesModeField(props: FieldProps<typeof controller>) {
70
+ const { field, onChange, value } = props
71
+ return (
72
+ <CheckboxGroup
73
+ label={field.label}
74
+ description={field.description}
75
+ isReadOnly={onChange === undefined}
76
+ value={value.map(x => x.value)}
77
+ onChange={keys => {
78
+ onChange?.(keys.map(key => field.valuesToOptionsWithStringValues[key]))
79
+ }}
80
+ >
81
+ {field.options.map(option => (
82
+ <Checkbox key={option.value} value={option.value}>
83
+ {option.label}
84
+ </Checkbox>
85
+ ))}
86
+ </CheckboxGroup>
87
+ )
88
+ }
89
+
90
+ export const Cell: CellComponent<typeof controller> = ({ value = [], field }) => {
91
+ const listFormatter = useListFormatter({ style: 'short', type: 'conjunction' })
92
+ const labels = (value as string[]).map(x => field.valuesToOptionsWithStringValues[x].label)
93
+
94
+ const cellContent =
95
+ value.length > 3
96
+ ? listFormatter.format([labels[0], `${value.length - 1} more`])
97
+ : listFormatter.format(labels)
98
+
99
+ return <Text>{cellContent}</Text>
100
+ }
101
+
102
+ export type AdminMultiSelectFieldMeta = {
103
+ options: readonly { label: string; value: string | number }[]
104
+ type: 'string' | 'integer' | 'enum'
105
+ displayMode: 'checkboxes' | 'select'
106
+ defaultValue: string[] | number[]
107
+ }
108
+
109
+ type Config = FieldControllerConfig<AdminMultiSelectFieldMeta>
110
+ type Option = { label: string; value: string }
111
+ type Value = readonly Option[]
112
+
113
+ export function controller(config: Config): FieldController<Value, Option[]> & {
114
+ displayMode: 'checkboxes' | 'select'
115
+ options: Option[]
116
+ type: 'string' | 'integer' | 'enum'
117
+ valuesToOptionsWithStringValues: Record<string, Option>
118
+ } {
119
+ const optionsWithStringValues = config.fieldMeta.options.map(x => ({
120
+ label: x.label,
121
+ value: x.value.toString(),
122
+ }))
123
+
124
+ const valuesToOptionsWithStringValues = Object.fromEntries(
125
+ optionsWithStringValues.map(option => [option.value, option])
126
+ )
127
+ const parseValue = (value: string) =>
128
+ config.fieldMeta.type === 'integer' ? parseInt(value) : value
129
+
130
+ return {
131
+ fieldKey: config.fieldKey,
132
+ label: config.label,
133
+ description: config.description,
134
+ displayMode: config.fieldMeta.displayMode,
135
+ type: config.fieldMeta.type,
136
+ options: optionsWithStringValues,
137
+ valuesToOptionsWithStringValues,
138
+ defaultValue: config.fieldMeta.defaultValue.map(x => valuesToOptionsWithStringValues[x]),
139
+ deserialize: data => {
140
+ // if we get null from the GraphQL API (which will only happen if field read access control failed)
141
+ // we'll just show it as nothing being selected for now.
142
+ const values: readonly string[] | readonly number[] = data[config.fieldKey] ?? []
143
+ const selectedOptions = values.map(x => valuesToOptionsWithStringValues[x])
144
+ return selectedOptions
145
+ },
146
+ serialize: value => ({ [config.fieldKey]: value.map(x => parseValue(x.value)) }),
147
+ graphqlSelection: config.fieldKey,
148
+ }
149
+ }
@@ -3,7 +3,7 @@ import bcryptjs from 'bcryptjs'
3
3
  import dumbPasswords from 'dumb-passwords'
4
4
  import { userInputError } from '../../../lib/core/graphql-errors'
5
5
  import {
6
- type BaseListTypeInfo,
6
+ type BaseCollectionTypeInfo,
7
7
  type CommonFieldConfig,
8
8
  type FieldTypeFunc,
9
9
  fieldType,
@@ -29,8 +29,8 @@ type FieldTypeInfo = {
29
29
  }
30
30
  }
31
31
 
32
- export type PasswordFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
33
- ListTypeInfo,
32
+ export type PasswordFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
33
+ CollectionTypeInfo,
34
34
  FieldTypeInfo
35
35
  > & {
36
36
  validation?: {
@@ -70,9 +70,9 @@ const PasswordFilter = g.inputObject({
70
70
  },
71
71
  })
72
72
 
73
- export function password<ListTypeInfo extends BaseListTypeInfo>(
74
- config: PasswordFieldConfig<ListTypeInfo> = {}
75
- ): FieldTypeFunc<ListTypeInfo> {
73
+ export function password<CollectionTypeInfo extends BaseCollectionTypeInfo>(
74
+ config: PasswordFieldConfig<CollectionTypeInfo> = {}
75
+ ): FieldTypeFunc<CollectionTypeInfo> {
76
76
  const {
77
77
  kdf = {
78
78
  hash: secret => {