@paris-ias/trees 1.8.56 → 1.8.57

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 (32) hide show
  1. package/dist/form/fellowships.js +4 -4
  2. package/dist/form/people.js +4 -4
  3. package/dist/graphql/schemas/schema.apex.graphql +3 -3
  4. package/lib/buildSchemas.ts +4 -4
  5. package/lib/generate.ts +2 -2
  6. package/package.json +1 -1
  7. package/readme.md +609 -74
  8. package/src/{action/graphql/server/apex.types.action.graphql → actions/graphql/server/apex.types.actions.graphql} +4 -4
  9. package/src/{action/models/action.ts → actions/models/actions.ts} +1 -1
  10. package/src/{affiliation/models/affiliation.ts → affiliations/models/affiliations.ts} +1 -1
  11. package/src/{affiliation/models/member.ts → affiliations/models/members.ts} +2 -2
  12. package/src/{affiliation/models/partner.ts → affiliations/models/partners.ts} +2 -2
  13. package/src/index.ts +8 -8
  14. package/src/misc/models/organizers.ts +3 -3
  15. package/src/misc/models/sponsor.ts +3 -3
  16. package/src/people/models/experiences.ts +3 -3
  17. package/src/people/models/people.ts +2 -3
  18. package/dist/graphql/schemas/apex-resolvers-list.json +0 -45
  19. package/dist/graphql/schemas/website-resolvers-list.json +0 -22
  20. /package/dist/form/{action.js → actions.js} +0 -0
  21. /package/dist/form/{affiliation.js → affiliations.js} +0 -0
  22. /package/dist/graphql/client/{action/query.get.action.gql → actions/query.get.actions.gql} +0 -0
  23. /package/dist/graphql/client/{action/query.list.action.gql → actions/query.list.actions.gql} +0 -0
  24. /package/dist/graphql/client/{affiliation → affiliations}/query.get.affiliations.gql +0 -0
  25. /package/dist/graphql/client/{affiliation → affiliations}/query.list.affiliations.gql +0 -0
  26. /package/dist/list/{action.js → actions.js} +0 -0
  27. /package/dist/list/{affiliation.js → affiliations.js} +0 -0
  28. /package/src/{action/graphql/client/query.get.action.gql → actions/graphql/client/query.get.actions.gql} +0 -0
  29. /package/src/{action/graphql/client/query.list.action.gql → actions/graphql/client/query.list.actions.gql} +0 -0
  30. /package/src/{affiliation → affiliations}/graphql/client/query.get.affiliations.gql +0 -0
  31. /package/src/{affiliation → affiliations}/graphql/client/query.list.affiliations.gql +0 -0
  32. /package/src/{affiliation → affiliations}/graphql/server/shared.types.affiliations.graphql +0 -0
@@ -92,7 +92,7 @@ export default {
92
92
  "experiences": [
93
93
  {
94
94
  "experiences": {
95
- "affiliation": "",
95
+ "affiliations": "",
96
96
  "positions": [
97
97
  {
98
98
  "positions": {
@@ -634,11 +634,11 @@ export default {
634
634
  "type": "OBJECT",
635
635
  "meta": "experiences",
636
636
  "items": {
637
- "affiliation": {
638
- "label": "affiliation",
637
+ "affiliations": {
638
+ "label": "affiliations",
639
639
  "component": "DocumentPicker",
640
640
  "type": "DOCUMENT",
641
- "meta": "affiliation",
641
+ "meta": "affiliations",
642
642
  "rules": {
643
643
  "required": true
644
644
  },
@@ -10,7 +10,7 @@ export default {
10
10
  "experiences": [
11
11
  {
12
12
  "experiences": {
13
- "affiliation": "",
13
+ "affiliations": "",
14
14
  "positions": [
15
15
  {
16
16
  "positions": {
@@ -150,11 +150,11 @@ export default {
150
150
  "type": "OBJECT",
151
151
  "meta": "experiences",
152
152
  "items": {
153
- "affiliation": {
154
- "label": "affiliation",
153
+ "affiliations": {
154
+ "label": "affiliations",
155
155
  "component": "DocumentPicker",
156
156
  "type": "DOCUMENT",
157
- "meta": "affiliation",
157
+ "meta": "affiliations",
158
158
  "rules": {
159
159
  "required": true
160
160
  },
@@ -1,4 +1,4 @@
1
- type Action {
1
+ type Actions {
2
2
  appId: String
3
3
  color: String
4
4
  link: String
@@ -6,12 +6,12 @@ type Action {
6
6
  name: String
7
7
  video: AWSURL
8
8
  slots: [String]
9
- slug: Slug
9
+ slug: AWSJSON
10
10
  }
11
11
 
12
12
  type ActionList {
13
13
  total: Int!
14
- items: [Action]
14
+ items: [Actions]
15
15
  }
16
16
 
17
17
  input FellowshipDetailsInput {
@@ -72,7 +72,7 @@ const websiteSchema: DocumentNode = mergeTypeDefs(
72
72
  fs.writeFileSync(APEX_SCHEMA_PATH, print(apexSchema), "utf8")
73
73
  fs.writeFileSync(WEBSITE_SCHEMA_PATH, print(websiteSchema), "utf8")
74
74
 
75
- function extractResolvers(appId: string, schema: DocumentNode): string {
75
+ /* function extractResolvers(appId: string, schema: DocumentNode): string {
76
76
  const queries: string[] = []
77
77
  const mutations: string[] = []
78
78
 
@@ -98,12 +98,12 @@ function extractResolvers(appId: string, schema: DocumentNode): string {
98
98
  }
99
99
 
100
100
  const apexResolversFile = extractResolvers("apex", apexSchema)
101
- const websiteResolversFile = extractResolvers("website", websiteSchema)
101
+ const websiteResolversFile = extractResolvers("website", websiteSchema) */
102
102
 
103
103
  console.log("✅ Schemas generated successfully:")
104
104
  console.log(` - Website schema : ${WEBSITE_SCHEMA_PATH}`)
105
105
  console.log(` - Apex schema : ${APEX_SCHEMA_PATH}`)
106
106
 
107
- console.log("✅ Resolvers list generated:")
107
+ /* console.log("✅ Resolvers list generated:")
108
108
  console.log(` - Website resolvers : ${websiteResolversFile}`)
109
- console.log(` - Apex resolvers : ${apexResolversFile}`)
109
+ console.log(` - Apex resolvers : ${apexResolversFile}`) */
package/lib/generate.ts CHANGED
@@ -464,13 +464,13 @@ const Modules = [
464
464
  "news",
465
465
  "people",
466
466
  "publications",
467
- "affiliation",
467
+ "affiliations",
468
468
  "disciplines",
469
469
  "mailing",
470
470
  "files",
471
471
  "tags",
472
472
  "users",
473
- "action",
473
+ "actions",
474
474
  // "taxonomy", //TODO: à definir
475
475
  ]
476
476
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paris-ias/trees",
3
- "version": "1.8.56",
3
+ "version": "1.8.57",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/readme.md CHANGED
@@ -1,116 +1,651 @@
1
- # Types Project
1
+ <div align="center">
2
2
 
3
- This project provides type definitions and utilities for various modules in the system. It includes interfaces, schemas, and configuration for different entities like projects, news, people, and more.
3
+ # 🌳 @paris-ias/trees
4
4
 
5
- ## Table of Contents
5
+ **Isomorphic Forest Types Module**
6
6
 
7
- - [Types Project](#types-project)
8
- - [Table of Contents](#table-of-contents)
9
- - [Installation](#installation)
10
- - [Usage](#usage)
11
- - [Structure](#structure)
12
- - [Modules](#modules)
13
- - [Projects](#projects)
14
- - [News](#news)
15
- - [People](#people)
16
- - [Fellowships](#fellowships)
17
- - [Publications](#publications)
18
- - [Events](#events)
19
- - [Other Modules \& submodules](#other-modules--submodules)
20
- - [Contributing](#contributing)
21
- - [Repository Update Convention](#repository-update-convention)
22
- - [License](#license)
7
+ _The foundational data model layer for the Paris IAS ecosystem_
23
8
 
24
- ## Installation
9
+ [![npm version](https://img.shields.io/npm/v/@paris-ias/trees?style=flat&colorA=020420&colorB=00DC82)](https://npmjs.com/package/@paris-ias/trees)
10
+ [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg?style=flat&colorA=020420&colorB=00DC82)](LICENSE)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue?style=flat&colorA=020420&colorB=00DC82)](https://www.typescriptlang.org/)
25
12
 
26
- To install the dependencies, run:
13
+ [Features](#-features) [Installation](#-installation) [Quick Start](#-quick-start) • [Documentation](DOCUMENTATION.md) • [Architecture](#-architecture)
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ## 🎯 What is @paris-ias/trees?
20
+
21
+ The trees module is the **single source of truth** for all data structures in the Isomorphic Forest architecture. It implements the core principle of **isomorphic forests**: each data model generates multiple tree structures with identical shapes but different values depending on context.
22
+
23
+ ```mermaid
24
+ graph LR
25
+ A[Single Model Definition] --> B[Schema Tree]
26
+ A --> C[Form Tree]
27
+ A --> D[List Tree]
28
+ A --> E[Defaults Tree]
29
+ A --> F[GraphQL Operations]
30
+
31
+ B --> G[Type Safety]
32
+ C --> H[Dynamic Forms]
33
+ D --> I[Smart Lists]
34
+ E --> J[Initialization]
35
+ F --> K[API Integration]
36
+
37
+ style A fill:#e1f5fe
38
+ style B fill:#f3e5f5
39
+ style C fill:#e8f5e8
40
+ style D fill:#fff3e0
41
+ style E fill:#fce4ec
42
+ style F fill:#e3f2fd
43
+ ```
44
+
45
+ ### Why Isomorphic Forests?
46
+
47
+ - **🎨 Single Source of Truth**: Define your data model once, generate everything else
48
+ - **🔄 Automatic Synchronization**: Changes propagate to forms, lists, APIs, and schemas automatically
49
+ - **🌍 I18n by Default**: Built-in internationalization support at the primitive level
50
+ - **🧩 Infinite Composition**: Template system enables unlimited reusable components
51
+ - **⚡ Type Safety**: Full TypeScript support with generated type definitions
52
+ - **📡 GraphQL Ready**: Automatically generates client operations and server schemas
53
+
54
+ ---
55
+
56
+ ## ✨ Features
57
+
58
+ ### 🏗️ Five Element Categories
59
+
60
+ Every data model is composed of five fundamental types that can be infinitely composed:
61
+
62
+ | Type | Description | Use Case |
63
+ | -------------- | -------------------------------------- | ---------------------------------------- |
64
+ | **Primitive** | Basic values (string, number, boolean) | Input fields, text areas, switches |
65
+ | **Object** | Nested structures | Grouped fields, complex entities |
66
+ | **Collection** | Arrays of elements | Lists, multi-select, repeatable sections |
67
+ | **Template** | References to reusable models | Shared components, composition |
68
+ | **Document** | Database entity references | Relations, lookups, foreign keys |
69
+
70
+ ### 🌲 Generated Trees
71
+
72
+ Each model definition generates several distinct outputs:
73
+
74
+ ```typescript
75
+ // 1. Schema Tree - Type definitions and validation, first part used by forms
76
+ {
77
+ lastname: { type: "PRIMITIVE", component: "TextField", rules: { required: true } },
78
+ ...
79
+ },
80
+
81
+ // 3. List Tree - Filtering, pagination, views and sorting
82
+ People: {
83
+ filters: { status: { type: "Select" } , ...},
84
+ sort: { nameasc: { value: ["lastname", 1] }, ... }
85
+ views: { grid: { default: true, icon: "view-grid" }, ... } // will translate in an expected FormViewsGrid component displaying PeopleGridItems components
86
+ ...
87
+ },
88
+
89
+ // 4. Defaults Tree - Initial values
90
+ {
91
+ _defaults: { firstname: "", lastname: "", ... }
92
+ ...
93
+ }
94
+
95
+ ```
96
+
97
+ ```graphql
98
+ ## 5. GraphQL Operations - Ready-to-use queries and mutations
99
+
100
+ query getPeople($appId: ID = "iea", $itemId: ID = "", $lang: String = "en") {
101
+ getPeople(appId: $appId, itemId: $itemId, lang: $lang) {
102
+ lastname
103
+ affiliations {
104
+ affiliation {
105
+ image {
106
+ alt
107
+ backgroundColor
108
+ caption
109
+ copyright
110
+ license
111
+ licenseUrl
112
+ url
113
+ }
114
+ location {
115
+ ...
116
+
117
+ ## 6. GraphQL Schema
118
+
119
+ type People {
120
+ appId: String
121
+ firstname: String!
122
+ lastname: String!
123
+ ...
124
+
125
+ ## 7. GraphQL Client Imports
126
+
127
+
128
+ import("@paris-ias/trees/dist/graphql/client/people/query.list.people.gql")
129
+ import("@paris-ias/trees/dist/graphql/client/people/query.get.people.gql")
130
+
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 📦 Installation
27
136
 
28
137
  ```bash
29
- yarn add @paris-ias/data
138
+ # Using npm
139
+ npm install @paris-ias/trees
140
+
141
+ # Using yarn
142
+ yarn add @paris-ias/trees
143
+
144
+ # Using pnpm
145
+ pnpm add @paris-ias/trees
30
146
  ```
31
147
 
32
- ## Usage
148
+ ---
149
+
150
+ ## 🚀 Quick Start
151
+
152
+ ### Importing Generated Trees
153
+
154
+ ```typescript
155
+ // Import form and list configurations
156
+ import { formPeople, listPeople } from "@paris-ias/trees"
33
157
 
34
- A precompiled version of the common objects is produced during CI. It is available in the `dist` folder. It can be imported to produce lists and forms using the related packages produced by Paris IAS.
158
+ // Import GraphQL operations directly
159
+ import("@paris-ias/trees/dist/graphql/client/people/query.list.people.gql")
160
+ import("@paris-ias/trees/dist/graphql/client/events/query.get.events.gql")
161
+ import(
162
+ "@paris-ias/trees/dist/graphql/client/publications/mutation.create.publication.gql"
163
+ )
164
+ ```
165
+
166
+ ### Defining a New Model
167
+
168
+ ```typescript
169
+ import { Model, formType } from "@paris-ias/trees"
170
+
171
+ const myModel: Model = {
172
+ // List configuration
173
+ list: {
174
+ create: true,
175
+ filters: {
176
+ status: { type: "Select" },
177
+ category: { type: "Select" },
178
+ },
179
+ sort: {
180
+ nameasc: {
181
+ icon: "sort-alphabetical-ascending",
182
+ text: "by-name-from-a-to-z",
183
+ value: ["name", 1],
184
+ },
185
+ },
186
+ views: {
187
+ dense: { default: true, icon: "view-grid" },
188
+ },
189
+ },
190
+
191
+ // Form schema
192
+ form: {
193
+ name: {
194
+ type: formType.Primitive,
195
+ component: "TextField",
196
+ label: "name",
197
+ i18n: true,
198
+ rules: { required: true, min: 1, max: 200 },
199
+ },
200
+ description: {
201
+ type: formType.Primitive,
202
+ component: "TextArea",
203
+ label: "description",
204
+ i18n: true,
205
+ },
206
+ // Reuse existing templates
207
+ socials: {
208
+ type: formType.Template,
209
+ component: "ObjectKeyPairContainer",
210
+ label: "socials",
211
+ },
212
+ },
213
+ }
214
+ ```
215
+
216
+ ### Using Templates for Composition
217
+
218
+ ```typescript
219
+ // Reference existing templates
220
+ form: {
221
+ // Use the built-in socials template
222
+ socials: {
223
+ type: formType.Template,
224
+ component: "ObjectKeyPairContainer",
225
+ label: "socials"
226
+ },
227
+
228
+ // Use the position template
229
+ positions: {
230
+ type: formType.Template,
231
+ component: "ArrayContainer",
232
+ label: "positions"
233
+ },
234
+
235
+ // Use the location template
236
+ location: {
237
+ type: formType.Template,
238
+ component: "ObjectField",
239
+ label: "location"
240
+ }
241
+ }
242
+ ```
243
+
244
+ ---
245
+
246
+ ## 🏛️ Architecture
247
+
248
+ ### Core Concepts
249
+
250
+ The trees module implements the **Isomorphic Forest** principle:
251
+
252
+ 1. **Single Definition**: One model definition serves as the source of truth
253
+ 2. **Multiple Trees**: Each model generates multiple trees with identical structure
254
+ 3. **Different Values**: Each tree contains values appropriate for its context
255
+ 4. **Type Safety**: Full TypeScript support throughout the generation process
256
+
257
+ ```mermaid
258
+ graph TD
259
+ A[Data Model Definition] --> B[Schema Tree]
260
+ A --> C[Form Tree]
261
+ A --> D[List Tree]
262
+ A --> E[Defaults Tree]
263
+ A --> F[GraphQL Client Tree]
264
+
265
+ B --> G[Generated GraphQL Schema]
266
+ C --> H[Dynamic Forms]
267
+ D --> I[List Generation]
268
+ E --> J[Default Values]
269
+ F --> K[Client Operations]
270
+
271
+ G --> L[Type Safety & Caching]
272
+ H --> M[UI Components]
273
+ I --> N[Filters & Sorting]
274
+ J --> O[Initialization]
275
+ K --> P[API Integration]
276
+
277
+ style A fill:#e1f5fe
278
+ style B fill:#f3e5f5
279
+ style C fill:#e8f5e8
280
+ style D fill:#fff3e0
281
+ style E fill:#fce4ec
282
+ style F fill:#e3f2fd
283
+ ```
35
284
 
36
- You can also import and use the types and utilities provided by this project in your code as follows:
285
+ ### Directory (simplified) Structure
37
286
 
38
- ```ts
39
- import { projects, news, people } from '@paris-ias/data';
287
+ ```
288
+ @paris-ias/trees/
289
+ ├── src/ # Source type definitions
290
+ │ ├── index.ts # Template registry & exports
291
+ │ ├── model.ts # Base model interface
292
+ │ ├── form.ts # Form type definitions
293
+ │ ├── list.ts # List configuration
294
+ │ ├── people/ # People model
295
+ │ │ ├── models/ # TypeScript definitions
296
+ │ │ └── graphql/ # GraphQL operations
297
+ │ │ ├── client/ # Client-side queries
298
+ │ │ └── server/ # Server-side schema
299
+ │ ├── events/ # Events model
300
+ │ ├── publications/ # Publications model
301
+ │ ├── projects/ # Projects model
302
+ │ ├── fellowships/ # Fellowships model
303
+ │ └── ... # Other models
304
+ ├── lib/ # Generation utilities
305
+ │ ├── generate.ts # Core generation engine
306
+ │ ├── buildSchemas.ts # GraphQL schema builder
307
+ │ ├── buildClientGraphQL.ts # Client operations organizer
308
+ │ └── utils.ts # File I/O utilities
309
+ └── dist/ # Generated output (created by build)
310
+ ├── list/ # List configurations
311
+ ├── form/ # Form schemas
312
+ └── graphql/ # GraphQL files
313
+ ├── schemas/ # Server schemas
314
+ │ ├── schema.website.graphql
315
+ │ └── schema.apex.graphql
316
+ └── client/ # Client operations
317
+ ├── people/ # People operations
318
+ ├── events/ # Events operations
319
+ └── ... # Other operations
320
+ ```
321
+
322
+ ---
323
+
324
+ ## 📚 Available Models
325
+
326
+ The module includes comprehensive data models for academic and research contexts. It is freely extensible:
327
+
328
+ ### Core Entities - matching expected documents
329
+
330
+ | Model | Description | Key Features |
331
+ | ---------------- | ----------------------------- | --------------------------------------------------------- |
332
+ | **People** | Academic profiles & directory | Affiliations, positions, social links, consent management |
333
+ | **Events** | Conferences & workshops | Time slots, speakers, locations, registration |
334
+ | **Publications** | Research papers & articles | Authors, metadata, citations, related content |
335
+ | **Projects** | Research projects | Team members, timeline, funding, deliverables |
336
+ | **Fellowships** | Fellowship programs | Applications, cohorts, program details |
337
+ | **News** | Announcements & articles | Rich media, categorization, publishing workflow |
338
+
339
+ ### Reusable Templates
340
+
341
+ | Template | Purpose | Fields |
342
+ | ------------ | ------------------ | ----------------------------------------------- |
343
+ | **socials** | Social media links | Website, ORCID, LinkedIn, Twitter, GitHub, etc. |
344
+ | **position** | Job positions | Role, department, institution, duration |
345
+ | **location** | Geographic data | Address, coordinates, venue details |
346
+ | **consent** | GDPR compliance | Privacy settings, data usage permissions |
347
+ | **groups** | User roles | Access control, membership management |
348
+ | **video** | Video content | URL, metadata, licensing, thumbnails |
349
+
350
+ ---
351
+
352
+ ## 🔧 Development
353
+
354
+ ### Generate All Trees
355
+
356
+ ```bash
357
+ # Generate all outputs (trees + GraphQL)
358
+ npm run generate
359
+
360
+ # Generate only module trees
361
+ npm run generate:modules
362
+
363
+ # Generate only GraphQL schemas
364
+ npm run generate:schemas
365
+
366
+ # Generate only GraphQL client operations
367
+ npm run generate:client
368
+
369
+ # Development mode with watch
370
+ npm run dev
371
+ ```
372
+
373
+ ### Visualize Dependencies
374
+
375
+ ```bash
376
+ # Generate dependency graph
377
+ npm run draw
378
+
379
+ # Output: dependency-graph.svg
380
+ ```
381
+
382
+ ### Project Structure Commands
383
+
384
+ ```bash
385
+ # Clean generated files
386
+ npm run clean
387
+
388
+ # Full rebuild
389
+ npm run clean && npm run generate
390
+ ```
391
+
392
+ ---
393
+
394
+ ## 🌐 Internationalization
395
+
396
+ Every primitive field supports internationalization out of the box:
397
+
398
+ ```typescript
399
+ // Enable i18n for a field
400
+ form: {
401
+ title: {
402
+ type: formType.Primitive,
403
+ component: "TextField",
404
+ label: "title",
405
+ i18n: true // 🌍 Enables multi-language support, fr and en for now
406
+ }
407
+ }
408
+
409
+ // Generated default structure
410
+ {
411
+ title: {
412
+ en: "",
413
+ fr: "",
414
+ }
415
+ }
416
+
417
+ // Or single-language when i18n is false
418
+ {
419
+ title: ""
420
+ }
421
+ ```
422
+
423
+ ---
424
+
425
+ ## 🔒 Validation System
426
+
427
+ Comprehensive validation rules for all field types:
428
+
429
+ ```typescript
430
+ interface Rules {
431
+ required?: boolean // Field is mandatory
432
+ min?: number // Minimum length/value
433
+ max?: number // Maximum length/value
434
+ url?: boolean // Valid URL
435
+ email?: boolean // Valid email
436
+ orcid?: boolean // Valid ORCID ID
437
+ color?: boolean // Valid color code
438
+ date?: boolean // Valid date
439
+ pattern?: RegExp // Custom regex pattern
440
+ custom?: Function // Custom validator
441
+ }
40
442
 
41
443
  // Example usage
444
+ form: {
445
+ email: {
446
+ type: formType.Primitive,
447
+ component: "TextField",
448
+ label: "email",
449
+ rules: {
450
+ required: true,
451
+ email: true
452
+ }
453
+ },
454
+ website: {
455
+ type: formType.Primitive,
456
+ component: "TextField",
457
+ label: "website",
458
+ rules: {
459
+ url: true
460
+ }
461
+ }
462
+ }
463
+ ```
464
+
465
+ ---
466
+
467
+ ## 🎭 Conditional Visibility, Disability or Function execution
468
+
469
+ Produce operations based on other field values in forms, and lists filters:
470
+
471
+ ```typescript
472
+ form: {
473
+ userType: {
474
+ type: formType.Primitive,
475
+ component: "Select",
476
+ label: "user-type"
477
+ },
478
+ fellowshipYear: {
479
+ type: formType.Primitive,
480
+ component: "Select",
481
+ label: "fellowship-year",
482
+ visibility: {
483
+ default: false,
484
+ switchIf: [{ userType: "fellow" }] // Only show for fellows
485
+ }
486
+ }
487
+ }
488
+ ```
489
+
490
+ ---
491
+
492
+ ## 📡 GraphQL Integration
493
+
494
+ ### Automatic Schema Generation
495
+
496
+ Server-side GraphQL schemas are automatically generated:
497
+
498
+ ```graphql
499
+ # Generated in dist/graphql/schemas/schema.website.graphql
500
+ type People {
501
+ id: ID!
502
+ firstname: String!
503
+ lastname: String!
504
+ email: String
505
+ socials: Socials
506
+ positions: [Position]
507
+ }
42
508
 
509
+ type Socials {
510
+ website: String
511
+ orcid: String
512
+ linkedin: String
513
+ twitter: String
514
+ }
43
515
  ```
44
- ## Structure
45
516
 
517
+ ### Client Operations
46
518
 
47
- ## Modules
519
+ Ready-to-use GraphQL operations for all models:
48
520
 
49
- ### Projects
521
+ ```typescript
522
+ // List queries
523
+ import("@paris-ias/trees/dist/graphql/client/people/query.list.people.gql")
524
+ import("@paris-ias/trees/dist/graphql/client/events/query.list.events.gql")
50
525
 
51
- Provides type definitions and utilities for handling projects.
526
+ // Get single item
527
+ import("@paris-ias/trees/dist/graphql/client/people/query.get.people.gql")
528
+ import("@paris-ias/trees/dist/graphql/client/events/query.get.events.gql")
52
529
 
53
- ### News
530
+ // Mutations
531
+ import("@paris-ias/trees/dist/graphql/client/people/mutation.upsert.people.gql")
532
+ import("@paris-ias/trees/dist/graphql/client/events/mutation.upsert.events.gql")
533
+ ```
534
+
535
+ ---
536
+
537
+ ## 🤝 Integration with Ecosystem
538
+
539
+ The trees module is the foundation for the entire Paris IAS ecosystem:
540
+
541
+ ### 🎨 [@paris-ias/form](../form)
542
+
543
+ Consumes form trees to generate dynamic, type-safe forms with validation
544
+
545
+ ### 📋 [@paris-ias/list](../list)
546
+
547
+ Uses list trees for advanced filtering, sorting, and view management
548
+
549
+ ### 🌱 [Seed Project](../seed)
550
+
551
+ Academic content management system built on trees, used foir the Paris IAS website public content
552
+
553
+ ### 🏔️ [Apex Project](../Apex)
554
+
555
+ Full-stack application framework
556
+
557
+ ---
558
+
559
+ ## 📖 Full Documentation
560
+
561
+ For comprehensive documentation including:
54
562
 
55
- Provides type definitions and utilities for handling news articles.
563
+ - Detailed architecture explanations
564
+ - Advanced template composition
565
+ - Error handling and validation
566
+ - Generation process internals
567
+ - Best practices and patterns
56
568
 
57
- ### People
569
+ **👉 See [DOCUMENTATION.md](DOCUMENTATION.md)**
58
570
 
59
- Provides type definitions and utilities for handling people entities.
571
+ ---
60
572
 
61
- ### Fellowships
573
+ ## 🤝 Contributing
62
574
 
63
- ### Publications
575
+ We welcome contributions! Please follow these steps:
64
576
 
65
- ### Events
577
+ 1. **Fork** the repository
578
+ 2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
579
+ 3. **Define** your model in `src/[type]/models/`
580
+ 4. **Add** GraphQL operations in `src/[type]/graphql/client/` if needed
581
+ 5. **Test** generation (`npm run generate`)
582
+ 6. **Commit** your changes (`git commit -m 'Add amazing feature'`)
583
+ 7. **Push** to the branch (`git push origin feature/amazing-feature`)
584
+ 8. **Open** a Pull Request
66
585
 
67
- ### Other Modules & submodules
586
+ ### Contribution Guidelines
68
587
 
69
- - Tags
70
- - Image
71
- - Affiliations
72
- - Positions
73
- - Consent
74
- - Files
75
- - Related
76
- - Related Projects
77
- - Related Publications
78
- - Related News
79
- - Related Events
80
- - Related People
588
+ - Follow existing naming conventions
589
+ - Add comprehensive validation rules
590
+ - Include JSDoc comments for public APIs
591
+ - Test all generated outputs
592
+ - Update documentation for new features
593
+ - Consider backward compatibility
81
594
 
82
- ## Contributing
595
+ ---
596
+
597
+ ## 📊 Version Management
598
+
599
+ We follow [Semantic Versioning](https://semver.org/):
600
+
601
+ ```bash
602
+ # Major version (breaking changes)
603
+ npm version major
604
+
605
+ # Minor version (new features, backward compatible)
606
+ npm version minor
607
+
608
+ # Patch version (bug fixes)
609
+ npm version patch
610
+ ```
611
+
612
+ ---
613
+
614
+ ## 📄 License
615
+
616
+ This project is licensed under the **GNU Affero General Public License v3.0** - see the [LICENSE](LICENSE) file for details.
617
+
618
+ ```
619
+ Copyright (C) 2024 Paris Institute for Advanced Study
620
+ Author: Antoine Cordelois
621
+
622
+ This program is free software: you can redistribute it and/or modify
623
+ it under the terms of the GNU Affero General Public License as published
624
+ by the Free Software Foundation, either version 3 of the License, or
625
+ (at your option) any later version.
626
+ ```
83
627
 
84
- We welcome contributions to this project. Please follow the guidelines below:
628
+ ---
85
629
 
86
- 1. Fork the repository.
87
- 2. Create a new branch for your feature or bugfix.
88
- 3. Make your changes and commit them with clear and concise messages.
89
- 4. Push your changes to your fork.
90
- 5. Create a pull request to the main repository.
630
+ ## 🙏 Acknowledgments
91
631
 
92
- ## Repository Update Convention
632
+ Developed and maintained by the **Paris Institute for Advanced Study** as part of its projects.
93
633
 
94
- We follow the semantic versioning convention to upgrade the repository version [semver](https://semver.org/).
634
+ Imagined and designed by Antoine Cordelois, with the great help of Hamed Bouare.
95
635
 
96
- - For a major change in the project, upgrade the package version using:
636
+ ---
97
637
 
98
- ```bash
99
- npm version major
100
- ```
638
+ ### Contributors
101
639
 
102
- - For a minor change, use the command:
640
+ <a href="https://github.com/Billybobbonnet"><img src="https://github.com/Billybobbonnet.png" width="60px" alt="billybobbonnet" /></a>
641
+ <a href="https://github.com/hbouare"><img src="https://github.com/hbouare.png" width="60px" alt="hbouare" /></a>
103
642
 
104
- ```bash
105
- npm version minor
106
- ```
643
+ ---
107
644
 
108
- - For a fix (patch), use:
645
+ <div align="center">
109
646
 
110
- ```bash
111
- npm version patch
112
- ```
647
+ **[Documentation](DOCUMENTATION.md)** • **[Issues](https://github.com/IEA-Paris/Apex/issues)** • **[Discussions](https://github.com/IEA-Paris/Apex/discussions)**
113
648
 
114
- ## License
649
+ Made with ❤️ by [Paris IAS](https://www.paris-iea.fr)
115
650
 
116
- This project is licensed under the AGPL v3 License. See the [LICENSE](LICENSE) file for details.
651
+ </div>
@@ -1,4 +1,4 @@
1
- type Action {
1
+ type Actions {
2
2
  appId: String
3
3
  color: String
4
4
  link: String
@@ -6,10 +6,10 @@ type Action {
6
6
  name: String
7
7
  video: AWSURL
8
8
  slots: [String]
9
- slug: Slug
9
+ slug: AWSJSON
10
10
  }
11
11
 
12
12
  type ActionList {
13
13
  total: Int!
14
- items: [Action]
15
- }
14
+ items: [Actions]
15
+ }
@@ -1,7 +1,7 @@
1
1
  import { Image } from "../../files/models/image"
2
2
  import Model from "../../model"
3
3
  import { formType } from "../../form"
4
- export interface Action {
4
+ export interface Actions {
5
5
  color?: string
6
6
  link: string
7
7
  image: Image
@@ -3,7 +3,7 @@ import { Location } from "../../misc/models/location"
3
3
  import Model from "../../model"
4
4
  import { formType } from "../../form"
5
5
 
6
- export interface Affiliation {
6
+ export interface Affiliations {
7
7
  location?: Location
8
8
  image?: Image
9
9
  name: string
@@ -1,7 +1,7 @@
1
- import config, { Affiliation } from "./affiliation"
1
+ import config, { Affiliations } from "./affiliations"
2
2
  import Model from "../../model"
3
3
 
4
- export interface Member extends Affiliation {}
4
+ export interface Member extends Affiliations {}
5
5
 
6
6
  const defaultConfig: Model = {
7
7
  aliases: ["affiliations"],
@@ -1,7 +1,7 @@
1
- import config, { Affiliation } from "./affiliation"
1
+ import config, { Affiliations } from "./affiliations"
2
2
  import Model from "../../model"
3
3
 
4
- export interface Partner extends Affiliation {}
4
+ export interface Partner extends Affiliations {}
5
5
  const defaultConfig: Model = {
6
6
  aliases: ["affiliations"],
7
7
  ...config,
package/src/index.ts CHANGED
@@ -2,8 +2,8 @@ import { ModuleType } from "../lib/generate"
2
2
  import Model from "./model"
3
3
  import { Sort, Views } from "./list"
4
4
  import { Form, formType } from "./form"
5
- import defaultConfigAction from "./action/models/action"
6
- import defaultConfigAffilation from "./affiliation/models/affiliation"
5
+ import defaultConfigActions from "./actions/models/actions"
6
+ import defaultConfigAffilations from "./affiliations/models/affiliations"
7
7
  import defaultConfigArticle from "./publications/models/article"
8
8
  import defaultConfigExperiences, {
9
9
  ExperiencesForm,
@@ -28,10 +28,10 @@ import defaultConfigGroup, { GroupsForm } from "./people/models/groups"
28
28
  import defaultConfigImage from "./files/models/image"
29
29
  import defaultConfigLocation, { LocationForm } from "./misc/models/location"
30
30
  import defaultConfigMailing from "./mailing/models/mailing"
31
- import defaultConfigMember from "./affiliation/models/member"
31
+ import defaultConfigMembers from "./affiliations/models/members"
32
32
  import defaultConfigNews from "./news/models/news"
33
33
  import defaultConfigOrganizers from "./misc/models/organizers"
34
- import defaultConfigPartner from "./affiliation/models/partner"
34
+ import defaultConfigPartners from "./affiliations/models/partners"
35
35
  import defaultConfigPeople from "./people/models/people"
36
36
  import defaultConfigPosition, { PositionForm } from "./people/models/position"
37
37
  import defaultConfigProject from "./projects/models/projects"
@@ -55,9 +55,9 @@ type ConfigValue =
55
55
  | SocialsForm
56
56
 
57
57
  const templates: Record<string, ConfigValue> = {
58
- action: defaultConfigAction,
58
+ actions: defaultConfigActions,
59
59
  workExperience: defaultConfigExperiences,
60
- affiliation: defaultConfigAffilation,
60
+ affiliations: defaultConfigAffilations,
61
61
  apps: defautConfigApp,
62
62
  article: defaultConfigArticle,
63
63
  consent: defaultConfigConsent,
@@ -75,10 +75,10 @@ const templates: Record<string, ConfigValue> = {
75
75
  image: defaultConfigImage,
76
76
  location: defaultConfigLocation,
77
77
  mailing: defaultConfigMailing,
78
- member: defaultConfigMember,
78
+ members: defaultConfigMembers,
79
79
  news: defaultConfigNews,
80
80
  organizers: defaultConfigOrganizers,
81
- partner: defaultConfigPartner,
81
+ partners: defaultConfigPartners,
82
82
  people: defaultConfigPeople,
83
83
  positions: defaultConfigPosition,
84
84
  projects: defaultConfigProject,
@@ -1,10 +1,10 @@
1
1
  import configPeople, { People } from "../../people/models/people"
2
2
  import configAffiliation, {
3
- Affiliation,
4
- } from "../../affiliation/models/affiliation"
3
+ Affiliations,
4
+ } from "../../affiliations/models/affiliations"
5
5
  import Model from "../../model"
6
6
 
7
- export interface Organizer extends People, Affiliation {}
7
+ export interface Organizer extends People, Affiliations {}
8
8
  const defaultConfig: Model = {
9
9
  aliases: ["people", "affiliations"],
10
10
  ...configPeople,
@@ -1,10 +1,10 @@
1
1
  import configPeople, { People } from "../../people/models/people"
2
2
  import configAffiliation, {
3
- Affiliation,
4
- } from "../../affiliation/models/affiliation"
3
+ Affiliations,
4
+ } from "../../affiliations/models/affiliations"
5
5
  import Model from "../../model"
6
6
 
7
- export interface Sponsor extends People, Affiliation {}
7
+ export interface Sponsor extends People, Affiliations {}
8
8
  const defaultConfig: Model = {
9
9
  aliases: ["people", "affiliations"],
10
10
  ...configPeople,
@@ -11,11 +11,11 @@ export interface ExperiencesForm {
11
11
 
12
12
  const defaultConfig: ExperiencesForm = {
13
13
  form: {
14
- affiliation: {
15
- label: "affiliation",
14
+ affiliations: {
15
+ label: "affiliations",
16
16
  component: "DocumentPicker",
17
17
  type: formType.Document,
18
- meta: "affiliation",
18
+ meta: "affiliations",
19
19
  rules: {
20
20
  required: true,
21
21
  },
@@ -1,4 +1,4 @@
1
- import { Affiliation } from "../../affiliation/models/affiliation"
1
+ import { Affiliations } from "../../affiliations/models/affiliations"
2
2
  import { Image } from "../../files/models/image"
3
3
  import { Socials } from "../../misc/models/socials"
4
4
  import { Position } from "./position"
@@ -15,7 +15,7 @@ export interface People {
15
15
  name: string
16
16
  firstname: string
17
17
  lastname: string
18
- affiliations?: [{ affiliation: Affiliation; positions: [Position] }]
18
+ affiliations?: [{ affiliation: Affiliations; positions: [Position] }]
19
19
  image?: Image
20
20
  socials?: Socials
21
21
  biography?: string
@@ -28,7 +28,6 @@ export interface People {
28
28
  }
29
29
 
30
30
  const defaultConfig: Model = {
31
- source: "gql",
32
31
  list: {
33
32
  create: true, // allow to create new items
34
33
 
@@ -1,45 +0,0 @@
1
- [
2
- "mutations/blockUser",
3
- "mutations/bookEvent",
4
- "mutations/changePassword",
5
- "mutations/createNomenclature",
6
- "mutations/deleteAccount",
7
- "mutations/forgotPassword",
8
- "mutations/inviteUser",
9
- "mutations/updateUser",
10
- "mutations/upsertApp",
11
- "mutations/upsertEvent",
12
- "queries/buildFiltersValues",
13
- "queries/getAction",
14
- "queries/getAffiliation",
15
- "queries/getApp",
16
- "queries/getDiscipline",
17
- "queries/getEvent",
18
- "queries/getFellowship",
19
- "queries/getFile",
20
- "queries/getMailing",
21
- "queries/getNews",
22
- "queries/getPeople",
23
- "queries/getPresignedUploadUrl",
24
- "queries/getProject",
25
- "queries/getPublication",
26
- "queries/getTag",
27
- "queries/getUser",
28
- "queries/listActions",
29
- "queries/listAffiliations",
30
- "queries/listApps",
31
- "queries/listDisciplines",
32
- "queries/listEvents",
33
- "queries/listFellowships",
34
- "queries/listFiles",
35
- "queries/listMailing",
36
- "queries/listNews",
37
- "queries/listPeople",
38
- "queries/listProjects",
39
- "queries/listPublications",
40
- "queries/listTags",
41
- "queries/listUsers",
42
- "queries/login",
43
- "queries/search",
44
- "queries/searchOptions"
45
- ]
@@ -1,22 +0,0 @@
1
- [
2
- "mutations/bookEvent",
3
- "queries/buildFiltersValues",
4
- "queries/getApp",
5
- "queries/getEvent",
6
- "queries/getFellowship",
7
- "queries/getNews",
8
- "queries/getPeople",
9
- "queries/getPresignedUploadUrl",
10
- "queries/getProject",
11
- "queries/getPublication",
12
- "queries/getUser",
13
- "queries/listEvents",
14
- "queries/listFellowships",
15
- "queries/listNews",
16
- "queries/listPeople",
17
- "queries/listProjects",
18
- "queries/listPublications",
19
- "queries/listUsers",
20
- "queries/login",
21
- "queries/search"
22
- ]
File without changes
File without changes
File without changes
File without changes