@rjsebening/n8n-nodes-learningsuite 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -91
- package/dist/nodes/LearningSuite/LearningSuite.node.d.ts +6 -0
- package/dist/nodes/LearningSuite/LearningSuite.node.js +10 -6
- package/dist/nodes/LearningSuite/LearningSuite.node.json +18 -0
- package/dist/nodes/LearningSuite/LearningSuiteTrigger.node.js +3 -3
- package/dist/nodes/LearningSuite/descriptions/calendarEvent.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/calendarEvent.properties.js +385 -0
- package/dist/nodes/LearningSuite/descriptions/member.properties.js +1 -1
- package/dist/nodes/LearningSuite/descriptions/module.properties.js +1 -1
- package/dist/nodes/LearningSuite/descriptions/resource.selector.js +5 -0
- package/dist/nodes/LearningSuite/descriptions/trigger.instant.properties.js +3 -3
- package/dist/nodes/LearningSuite/descriptions/webhook.properties.js +2 -2
- package/dist/nodes/LearningSuite/exec.types.d.ts +2 -2
- package/dist/nodes/LearningSuite/execute/calendarEvent.handlers.d.ts +7 -0
- package/dist/nodes/LearningSuite/execute/calendarEvent.handlers.js +235 -0
- package/dist/nodes/LearningSuite/execute/registry.js +2 -0
- package/dist/nodes/LearningSuite/execute/webhook.handlers.js +1 -1
- package/dist/nodes/LearningSuite/methods/loadOptions/calendarEvent.loadOptions.d.ts +5 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/calendarEvent.loadOptions.js +15 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/teamMember.loadOptions.js +1 -1
- package/dist/nodes/LearningSuite/methods/resourceMappers/calendarEvent.resourceMapper.d.ts +3 -0
- package/dist/nodes/LearningSuite/methods/resourceMappers/calendarEvent.resourceMapper.js +35 -0
- package/dist/nodes/LearningSuitePollingTrigger/LearningSuitePollingTrigger.node.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-

|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
9
|
-
An n8n
|
|
9
|
+
An n8n node for the **LearningSuite API** that connects your LearningSuite instance to n8n workflows. It is developed and maintained by its original author, Jörg Sebening — and LearningSuite has published this integration.
|
|
10
10
|
|
|
11
11
|
## What is n8n?
|
|
12
12
|
|
|
13
13
|
n8n is an easy-to-use tool that allows you to automate actions between different web apps, such as LearningSuite. Creating so-called "workflows" between apps automates many of the manual tasks. This can save you or your employees a tremendous amount of time.
|
|
14
14
|
|
|
15
|
-
## ⚖️ Legal Notice
|
|
15
|
+
## ⚖️ Maintainer & Legal Notice
|
|
16
16
|
|
|
17
|
-
This
|
|
17
|
+
This repository is the original source of the LearningSuite n8n integration, developed and maintained by Jörg Sebening ([@rjsebening](https://github.com/rjsebening)) as its official maintainer. LearningSuite has published this integration.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
The node uses the public LearningSuite API. LearningSuite, its trademarks, and its logos belong to LearningSuite.
|
|
20
20
|
|
|
21
21
|
## 🚀 Features
|
|
22
22
|
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **Instant trigger (webhook-based)** with
|
|
23
|
+
- **16 resources** fully supported (Member, Course, Group, Bundle, Hub, Module, Community, Calendar Event, Custom Fields, Popup, Webhook, Role, User, Team Member, AI, API Call)
|
|
24
|
+
- **100 action endpoints** for maximum flexibility
|
|
25
|
+
- **Instant trigger (webhook-based)** with 19 event types for real-time automation
|
|
26
26
|
- **Polling trigger** with 11 event types for scheduled polling
|
|
27
27
|
- **Flexible API call** resource for custom endpoints
|
|
28
28
|
|
|
@@ -30,75 +30,85 @@ This community node uses the public LearningSuite API and is not affiliated with
|
|
|
30
30
|
|
|
31
31
|
### 👤 **Member** (20 operations)
|
|
32
32
|
|
|
33
|
-
- Get by email, get by ID, get
|
|
34
|
-
- Activate
|
|
35
|
-
- Get courses, get course
|
|
33
|
+
- Get member by email, get member by ID, get many members, create a member, update a member, delete a member, find or create member
|
|
34
|
+
- Activate deactivate member, add member to courses, remove member from courses, add member to bundles, remove member from bundles
|
|
35
|
+
- Get member courses, get member course info, get member bundles
|
|
36
36
|
- Get course progress, get module progress, get lesson progress, set course progress, reset course progress
|
|
37
37
|
|
|
38
|
-
### 📚 **Course** (
|
|
38
|
+
### 📚 **Course** (9 operations)
|
|
39
39
|
|
|
40
|
-
- Get published courses, get course modules, get course modules for member
|
|
41
|
-
- Get course members, get course access requests, get course submissions
|
|
40
|
+
- Get published courses, publish course, get course modules, get course modules for member
|
|
41
|
+
- Get course members, get course access requests, get course submissions
|
|
42
|
+
- Create lesson, update lesson
|
|
42
43
|
|
|
43
|
-
### 👥 **Group** (
|
|
44
|
+
### 👥 **Group** (13 operations)
|
|
44
45
|
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
46
|
+
- Create a group, delete a group, find groups by name, find or create group, get group by ID, get many groups
|
|
47
|
+
- Add members to groups, add members to groups summary, remove members from groups
|
|
48
|
+
- Add courses to group, remove courses from group, get group courses, add bundles to group
|
|
48
49
|
|
|
49
50
|
### 📦 **Bundle** (2 operations)
|
|
50
51
|
|
|
51
|
-
- Get
|
|
52
|
+
- Get bundles, get bundle members
|
|
52
53
|
|
|
53
54
|
### 🏠 **Hub** (6 operations)
|
|
54
55
|
|
|
55
|
-
- Get
|
|
56
|
+
- Get many hubs, get hub templates, get hub template variables, create a hub, add hub access, remove hub access
|
|
56
57
|
|
|
57
58
|
### 📖 **Module** (3 operations)
|
|
58
59
|
|
|
59
|
-
- Get module lessons, get module sections, change module access
|
|
60
|
+
- Get module lessons, get module sections, change module access
|
|
60
61
|
|
|
61
|
-
### 💬 **Community** (
|
|
62
|
+
### 💬 **Community** (8 operations)
|
|
62
63
|
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
64
|
+
- Get community areas, get community forums, get community posts, get community badges
|
|
65
|
+
- Create community post, add comment to post
|
|
66
|
+
- Assign badges to member, remove badges from member
|
|
67
|
+
|
|
68
|
+
### 🗓️ **Calendar Event** (4 operations)
|
|
69
|
+
|
|
70
|
+
- Get many calendar events, create a calendar event, update a calendar event, delete a calendar event
|
|
71
|
+
- Reminders (push/email), per-phase link stages (before/during/after), access via members/groups/bundles
|
|
72
|
+
- Update maps fields from incoming items automatically
|
|
66
73
|
|
|
67
74
|
### 🔧 **Custom Fields** (14 operations)
|
|
68
75
|
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
76
|
+
- Retrieve all custom field cards, retrieve custom field cards including their definitions and categories
|
|
77
|
+
- Retrieve custom field categories, retrieve custom field definitions
|
|
78
|
+
- Retrieve the values of a custom field for a user, get all custom field values of a user for a given profile
|
|
79
|
+
- Retrieve custom field profiles of a user, retrieve custom field profiles including their values, retrieve the values of a custom field card profile for a user
|
|
80
|
+
- Retrieve the complete custom field store of a user
|
|
81
|
+
- Set the value of a single custom field for a user, set multiple custom field values for a user in one request, update a custom field value within a profile of a custom field card
|
|
82
|
+
- Upload a file from a public URL and append it to a custom field
|
|
74
83
|
|
|
75
84
|
### 🎯 **Popup** (4 operations)
|
|
76
85
|
|
|
77
|
-
- Get
|
|
86
|
+
- Get many popups, get a popup, trigger popup for member, remove popup trigger for member
|
|
78
87
|
|
|
79
|
-
### 🔗 **Webhook** (
|
|
88
|
+
### 🔗 **Webhook** (6 operations)
|
|
80
89
|
|
|
81
|
-
- Get
|
|
90
|
+
- Get webhook subscription, get webhook subscriptions, create webhook subscription, update webhook subscription, delete webhook subscription
|
|
91
|
+
- Get webhook sample data
|
|
82
92
|
|
|
83
93
|
### 👤 **Team Member** (3 operations)
|
|
84
94
|
|
|
85
|
-
- Get
|
|
95
|
+
- Get team members, get team member by email, get team member by ID
|
|
86
96
|
|
|
87
|
-
### 📢 **User** (
|
|
97
|
+
### 📢 **User** (2 operations)
|
|
88
98
|
|
|
89
|
-
- Send push notification
|
|
99
|
+
- Send push notification, send login email
|
|
90
100
|
|
|
91
101
|
### 🤖 **AI** (4 operations)
|
|
92
102
|
|
|
93
|
-
-
|
|
103
|
+
- Send message to AI agent, send message to AI concierge, list AI agents, list agent actions
|
|
94
104
|
|
|
95
105
|
### 🛡️ **Role** (1 operation)
|
|
96
106
|
|
|
97
|
-
- Get
|
|
107
|
+
- Get many roles
|
|
98
108
|
|
|
99
109
|
### 🛠️ **API Call** (1 operation)
|
|
100
110
|
|
|
101
|
-
-
|
|
111
|
+
- Custom API call (for any endpoint)
|
|
102
112
|
|
|
103
113
|
## 🎣 Trigger Events
|
|
104
114
|
|
|
@@ -106,14 +116,15 @@ The LearningSuite trigger supports the following events:
|
|
|
106
116
|
|
|
107
117
|
### ⚡ Instant Trigger Events (Webhook)
|
|
108
118
|
|
|
109
|
-
- ✅ Community Post Commented
|
|
110
119
|
- ✅ Agent Action Executed
|
|
120
|
+
- ✅ AI Agent Limit for Inaccessible Course Content Exceeded
|
|
121
|
+
- ✅ Community Post Commented
|
|
111
122
|
- ✅ Community Post Created
|
|
112
123
|
- ✅ Community Post Moderated
|
|
113
124
|
- ✅ Course Member Added
|
|
114
125
|
- ✅ Course Progress Changed
|
|
115
126
|
- ✅ Course Updated
|
|
116
|
-
- ✅ Custom Field Value Changed
|
|
127
|
+
- ✅ Custom Field Value Changed Events
|
|
117
128
|
- ✅ Custom Popup Interaction
|
|
118
129
|
- ✅ Exam Completed
|
|
119
130
|
- ✅ Exam Graded
|
|
@@ -273,6 +284,17 @@ The Custom Fields resource supports file, image, video, and audio custom fields.
|
|
|
273
284
|
- The node respects the LearningSuite file limits defined on the custom field, such as `maxFiles`, `maxImages`, `maxVideos`, and `maxAudios`.
|
|
274
285
|
- For custom field cards with multiple profiles, use Profile ID, Profile Index, or Profile Name to target a specific profile. If the card does not allow multiple profiles, profile parameters are ignored and the default profile is used.
|
|
275
286
|
|
|
287
|
+
### Calendar Events
|
|
288
|
+
|
|
289
|
+
The Calendar Event resource works on event **series**, never on single dates — a weekly series is one entry, no matter how often it takes place.
|
|
290
|
+
|
|
291
|
+
- **Get Many** filters by series lifetime: `From Date`/`To Date` select series whose lifetime overlaps the range, widened by one day for timezone tolerance. A series can therefore be returned although none of its dates falls inside the exact range. Calculate the individual dates from `startDate`, `startTime`, `timeZone`, `duration`, `repetitionInterval`, and `endDate`.
|
|
292
|
+
- **Dates and times** use `YYYY-MM-DD` and `HH:mm` and are interpreted in the event's IANA time zone (e.g. `Europe/Berlin`).
|
|
293
|
+
- **Update** maps its fields from the incoming item automatically, so a Get Many result can be piped straight into it. Only mapped fields are sent, everything else keeps its current value.
|
|
294
|
+
- **Clearing a value**: set the field to the expression `{{ null }}`. The API allows this for Description, Duration, and End Date only.
|
|
295
|
+
- **Link Stages** replace the single link with before/during/after phases. As soon as any phase is set, the During phase is required.
|
|
296
|
+
- **Access** (members, groups, bundles) can only be set when creating an event; the update endpoint does not accept it.
|
|
297
|
+
|
|
276
298
|
### ⚡ Instant Webhook Trigger Setup
|
|
277
299
|
|
|
278
300
|
```
|
|
@@ -367,41 +389,7 @@ npm test
|
|
|
367
389
|
|
|
368
390
|
## 📝 Changelog
|
|
369
391
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
#### Custom Fields File Uploads
|
|
373
|
-
|
|
374
|
-
- ✅ Upload file from public URL
|
|
375
|
-
|
|
376
|
-
- ✅ Binary uploads for file, image, video, and audio custom fields
|
|
377
|
-
|
|
378
|
-
- ✅ File Value Mode: add, replace, and replace when the field limit is reached
|
|
379
|
-
|
|
380
|
-
- ✅ Respect custom field file limits (`maxFiles`, `maxImages`, `maxVideos`, `maxAudios`)
|
|
381
|
-
|
|
382
|
-
- ✅ Improved handling for custom field profile cards and default profiles
|
|
383
|
-
|
|
384
|
-
### Version 0.1.0 (2025-09-23)
|
|
385
|
-
|
|
386
|
-
#### Initial Release
|
|
387
|
-
|
|
388
|
-
- ✅ Full LearningSuite API integration
|
|
389
|
-
|
|
390
|
-
- ✅ 15 resources with 90 action endpoints
|
|
391
|
-
|
|
392
|
-
- ✅ Webhook triggers with 18 event types for real-time automation
|
|
393
|
-
|
|
394
|
-
- ✅ Polling triggers with 11 event types
|
|
395
|
-
|
|
396
|
-
- ✅ "Find-or-Create" logic for members and groups
|
|
397
|
-
|
|
398
|
-
- ✅ Custom Fields resource with full CRUD support
|
|
399
|
-
|
|
400
|
-
- ✅ Course progress management (get/set/reset)
|
|
401
|
-
|
|
402
|
-
- ✅ Flexible parameter configuration
|
|
403
|
-
|
|
404
|
-
- ✅ API call resource for custom endpoints
|
|
392
|
+
All notable changes are documented in [CHANGELOG.md](CHANGELOG.md).
|
|
405
393
|
|
|
406
394
|
## 🛠️ Compatibility
|
|
407
395
|
|
|
@@ -419,7 +407,9 @@ This project is licensed under the [MIT License].
|
|
|
419
407
|
|
|
420
408
|
### Report Issues
|
|
421
409
|
|
|
422
|
-
For bugs or feature requests
|
|
410
|
+
For bugs or feature requests **in this node**, please create a [GitHub Issue](https://github.com/rjsebening/n8n-nodes-learningsuite/issues).
|
|
411
|
+
|
|
412
|
+
For questions about the LearningSuite API itself or your LearningSuite account, contact LearningSuite support.
|
|
423
413
|
|
|
424
414
|
### FAQ
|
|
425
415
|
|
|
@@ -440,17 +430,3 @@ A: The default URL is `https://api.learningsuite.io/api/v1`. For custom domains,
|
|
|
440
430
|
⭐ **Like this node?** Give us a star on GitHub!
|
|
441
431
|
|
|
442
432
|
💡 **Feature request?** Open an issue - we're always open to improvements!
|
|
443
|
-
|
|
444
|
-
## 📋 Disclaimer
|
|
445
|
-
|
|
446
|
-
This unofficial community node is not affiliated with, endorsed by, or sponsored by LearningSuite. It exclusively uses the publicly available LearningSuite API in accordance with its Terms of Use.
|
|
447
|
-
|
|
448
|
-
**Important Notes:**
|
|
449
|
-
|
|
450
|
-
- This node is developed and maintained by the community.
|
|
451
|
-
|
|
452
|
-
- For issues with the LearningSuite API, contact official LearningSuite Support.
|
|
453
|
-
|
|
454
|
-
- All LearningSuite trademarks and logos belong to LearningSuite.
|
|
455
|
-
|
|
456
|
-
- This node merely provides an interface to the public API.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type IExecuteFunctions, type INodeExecutionData, type INodeType, type INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
import { getCalendarEventResourceMapperFields } from './methods/resourceMappers/calendarEvent.resourceMapper';
|
|
2
3
|
import { getTemplateVariablesResourceMapperFields } from './methods/resourceMappers/hub.resourceMapper';
|
|
3
4
|
import { getMultipleCustomFieldValueResourceMapperFields } from './methods/resourceMappers/customFields.resourceMapper';
|
|
4
5
|
export declare class LearningSuite implements INodeType {
|
|
@@ -58,11 +59,16 @@ export declare class LearningSuite implements INodeType {
|
|
|
58
59
|
community_getForums(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
|
|
59
60
|
community_getBadges(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
|
|
60
61
|
community_getLatestPosts(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
|
|
62
|
+
calendarEvent_getCalendarEvents(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<{
|
|
63
|
+
name: string;
|
|
64
|
+
value: string;
|
|
65
|
+
}[]>;
|
|
61
66
|
bundle_getBundles(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
|
|
62
67
|
ai_getAgentActions(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
|
|
63
68
|
ai_getAiAgents(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
|
|
64
69
|
};
|
|
65
70
|
resourceMapping: {
|
|
71
|
+
getCalendarEventResourceMapperFields: typeof getCalendarEventResourceMapperFields;
|
|
66
72
|
getTemplateVariablesResourceMapperFields: typeof getTemplateVariablesResourceMapperFields;
|
|
67
73
|
getMultipleCustomFieldValueResourceMapperFields: typeof getMultipleCustomFieldValueResourceMapperFields;
|
|
68
74
|
};
|
|
@@ -38,6 +38,7 @@ const n8n_workflow_1 = require("n8n-workflow");
|
|
|
38
38
|
// methods - loadOptions
|
|
39
39
|
const loAi = __importStar(require("./methods/loadOptions/ai.loadOptions"));
|
|
40
40
|
const loBundle = __importStar(require("./methods/loadOptions/bundle.loadOptions"));
|
|
41
|
+
const loCalendarEvent = __importStar(require("./methods/loadOptions/calendarEvent.loadOptions"));
|
|
41
42
|
const loCommunity = __importStar(require("./methods/loadOptions/community.loadOptions"));
|
|
42
43
|
const loCourse = __importStar(require("./methods/loadOptions/course.loadOptions"));
|
|
43
44
|
const loGroup = __importStar(require("./methods/loadOptions/group.loadOptions"));
|
|
@@ -49,12 +50,14 @@ const loRole = __importStar(require("./methods/loadOptions/role.loadOptions"));
|
|
|
49
50
|
const loWebhook = __importStar(require("./methods/loadOptions/webhook.loadOptions"));
|
|
50
51
|
const loTeamMember = __importStar(require("./methods/loadOptions/teamMember.loadOptions"));
|
|
51
52
|
const loCustomFields = __importStar(require("./methods/loadOptions/customFields.loadOptions"));
|
|
53
|
+
const calendarEvent_resourceMapper_1 = require("./methods/resourceMappers/calendarEvent.resourceMapper");
|
|
52
54
|
const hub_resourceMapper_1 = require("./methods/resourceMappers/hub.resourceMapper");
|
|
53
55
|
const customFields_resourceMapper_1 = require("./methods/resourceMappers/customFields.resourceMapper");
|
|
54
56
|
// properties
|
|
55
57
|
const resource_selector_1 = require("./descriptions/resource.selector");
|
|
56
58
|
const apiCall_properties_1 = require("./descriptions/apiCall.properties");
|
|
57
59
|
const bundle_properties_1 = require("./descriptions/bundle.properties");
|
|
60
|
+
const calendarEvent_properties_1 = require("./descriptions/calendarEvent.properties");
|
|
58
61
|
const community_properties_1 = require("./descriptions/community.properties");
|
|
59
62
|
const course_properties_1 = require("./descriptions/course.properties");
|
|
60
63
|
const group_properties_1 = require("./descriptions/group.properties");
|
|
@@ -71,6 +74,7 @@ const ai_properties_1 = require("./descriptions/ai.properties");
|
|
|
71
74
|
// handlers
|
|
72
75
|
const apiCall_handlers_1 = require("./execute/apiCall.handlers");
|
|
73
76
|
const bundle_handlers_1 = require("./execute/bundle.handlers");
|
|
77
|
+
const calendarEvent_handlers_1 = require("./execute/calendarEvent.handlers");
|
|
74
78
|
const community_handlers_1 = require("./execute/community.handlers");
|
|
75
79
|
const course_handlers_1 = require("./execute/course.handlers");
|
|
76
80
|
const group_handlers_1 = require("./execute/group.handlers");
|
|
@@ -88,6 +92,7 @@ const registry = {
|
|
|
88
92
|
ai: { ...ai_handlers_1.aiHandlers },
|
|
89
93
|
apiCall: { ...apiCall_handlers_1.apiCallHandlers },
|
|
90
94
|
bundle: { ...bundle_handlers_1.bundleHandlers },
|
|
95
|
+
calendarEvent: { ...calendarEvent_handlers_1.calendarEventHandlers },
|
|
91
96
|
community: { ...community_handlers_1.communityHandlers },
|
|
92
97
|
course: { ...course_handlers_1.courseHandlers },
|
|
93
98
|
customFields: { ...customFields_handlers_1.customFieldsHandlers },
|
|
@@ -113,11 +118,11 @@ class LearningSuite {
|
|
|
113
118
|
group: ['transform'],
|
|
114
119
|
version: 1,
|
|
115
120
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
116
|
-
description: 'Interact with LearningSuite API (powered by
|
|
121
|
+
description: 'Interact with LearningSuite API (powered by agentur-systeme.de)',
|
|
117
122
|
defaults: {
|
|
118
123
|
name: 'LearningSuite',
|
|
119
124
|
// @ts-expect-error -- description required by linter
|
|
120
|
-
description: 'Interact with LearningSuite API (powered by
|
|
125
|
+
description: 'Interact with LearningSuite API (powered by agentur-systeme.de)',
|
|
121
126
|
},
|
|
122
127
|
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
123
128
|
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
@@ -130,15 +135,12 @@ class LearningSuite {
|
|
|
130
135
|
description: 'LearningSuite API Test',
|
|
131
136
|
},
|
|
132
137
|
],
|
|
133
|
-
requestDefaults: {
|
|
134
|
-
baseURL: '={{$credentials.baseUrl}}',
|
|
135
|
-
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
|
136
|
-
},
|
|
137
138
|
properties: [
|
|
138
139
|
resource_selector_1.resourceSelector,
|
|
139
140
|
...ai_properties_1.aiProperties,
|
|
140
141
|
...apiCall_properties_1.apiCallProperties,
|
|
141
142
|
...bundle_properties_1.bundleProperties,
|
|
143
|
+
...calendarEvent_properties_1.calendarEventProperties,
|
|
142
144
|
...community_properties_1.communityProperties,
|
|
143
145
|
...course_properties_1.courseProperties,
|
|
144
146
|
...customFields_properties_1.customFieldsProperties,
|
|
@@ -157,6 +159,7 @@ class LearningSuite {
|
|
|
157
159
|
loadOptions: {
|
|
158
160
|
...loAi,
|
|
159
161
|
...loBundle,
|
|
162
|
+
...loCalendarEvent,
|
|
160
163
|
...loCommunity,
|
|
161
164
|
...loCourse,
|
|
162
165
|
...loCustomFields,
|
|
@@ -170,6 +173,7 @@ class LearningSuite {
|
|
|
170
173
|
...loWebhook,
|
|
171
174
|
},
|
|
172
175
|
resourceMapping: {
|
|
176
|
+
getCalendarEventResourceMapperFields: calendarEvent_resourceMapper_1.getCalendarEventResourceMapperFields,
|
|
173
177
|
getTemplateVariablesResourceMapperFields: hub_resourceMapper_1.getTemplateVariablesResourceMapperFields,
|
|
174
178
|
getMultipleCustomFieldValueResourceMapperFields: customFields_resourceMapper_1.getMultipleCustomFieldValueResourceMapperFields,
|
|
175
179
|
},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"node": "n8n-nodes-learningsuite.learningSuite",
|
|
3
|
+
"nodeVersion": "1.0",
|
|
4
|
+
"codexVersion": "1.0",
|
|
5
|
+
"categories": ["Marketing & Content", "Communication"],
|
|
6
|
+
"resources": {
|
|
7
|
+
"credentialDocumentation": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://github.com/rjsebening/n8n-nodes-learningsuite/blob/main/CREDENTIALS.md"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"primaryDocumentation": [
|
|
13
|
+
{
|
|
14
|
+
"url": "https://github.com/rjsebening/n8n-nodes-learningsuite/blob/main/README.md"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -242,7 +242,7 @@ function buildDesiredFilter(event) {
|
|
|
242
242
|
filter.groupId = String(col.groupId);
|
|
243
243
|
break;
|
|
244
244
|
}
|
|
245
|
-
// ---------------- Lesson Completed (
|
|
245
|
+
// ---------------- Lesson Completed (cascading)
|
|
246
246
|
case 'lesson.completed': {
|
|
247
247
|
const col = getCol('additionalLessonCompleted');
|
|
248
248
|
if (col.courseId)
|
|
@@ -288,12 +288,12 @@ class LearningSuiteTrigger {
|
|
|
288
288
|
},
|
|
289
289
|
group: ['trigger'],
|
|
290
290
|
version: 1,
|
|
291
|
-
description: 'Interact with LearningSuite API (powered by
|
|
291
|
+
description: 'Interact with LearningSuite API (powered by agentur-systeme.de)',
|
|
292
292
|
subtitle: '={{$parameter["event"]}}',
|
|
293
293
|
defaults: {
|
|
294
294
|
name: 'LearningSuite Trigger',
|
|
295
295
|
// @ts-expect-error -- description is required by n8n node linting for defaults
|
|
296
|
-
description: 'Interact with LearningSuite API (powered by
|
|
296
|
+
description: 'Interact with LearningSuite API (powered by agentur-systeme.de)',
|
|
297
297
|
},
|
|
298
298
|
inputs: [],
|
|
299
299
|
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calendarEventProperties = void 0;
|
|
4
|
+
const RESOURCE = 'calendarEvent';
|
|
5
|
+
const show = (...operations) => ({
|
|
6
|
+
show: { resource: [RESOURCE], ...(operations.length ? { operation: operations } : {}) },
|
|
7
|
+
});
|
|
8
|
+
function availabilityFields(prefix, label, relationDescription) {
|
|
9
|
+
return [
|
|
10
|
+
{
|
|
11
|
+
displayName: `${label}: Relation`,
|
|
12
|
+
name: `${prefix}Relation`,
|
|
13
|
+
type: 'options',
|
|
14
|
+
options: [
|
|
15
|
+
{ name: 'After Event End', value: 'afterEventEnd' },
|
|
16
|
+
{ name: 'After Event Start', value: 'afterEventStart' },
|
|
17
|
+
{ name: 'Before Event End', value: 'beforeEventEnd' },
|
|
18
|
+
{ name: 'Before Event Start', value: 'beforeEventStart' },
|
|
19
|
+
{ name: 'Not Set (Natural Start/End)', value: '' },
|
|
20
|
+
],
|
|
21
|
+
default: '',
|
|
22
|
+
description: relationDescription,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
displayName: `${label}: Amount`,
|
|
26
|
+
name: `${prefix}Amount`,
|
|
27
|
+
type: 'number',
|
|
28
|
+
typeOptions: { minValue: 0 },
|
|
29
|
+
default: 0,
|
|
30
|
+
description: 'How many units before/after the reference point. Only used when a relation is selected.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
displayName: `${label}: Unit`,
|
|
34
|
+
name: `${prefix}Unit`,
|
|
35
|
+
type: 'options',
|
|
36
|
+
options: [
|
|
37
|
+
{ name: 'Minutes', value: 'minutes' },
|
|
38
|
+
{ name: 'Hours', value: 'hours' },
|
|
39
|
+
{ name: 'Days', value: 'days' },
|
|
40
|
+
],
|
|
41
|
+
default: 'minutes',
|
|
42
|
+
description: 'Unit of the amount. Only used when a relation is selected.',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
function linkStageValues() {
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
displayName: 'URL',
|
|
50
|
+
name: 'url',
|
|
51
|
+
type: 'string',
|
|
52
|
+
default: '',
|
|
53
|
+
required: true,
|
|
54
|
+
placeholder: 'https://zoom.us/j/123456789',
|
|
55
|
+
description: 'Link of this phase. Must be a valid http(s) URL.',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
displayName: 'Enabled',
|
|
59
|
+
name: 'enabled',
|
|
60
|
+
type: 'boolean',
|
|
61
|
+
default: true,
|
|
62
|
+
description: 'Whether this phase is active',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
displayName: 'Button Label',
|
|
66
|
+
name: 'ctaLabel',
|
|
67
|
+
type: 'string',
|
|
68
|
+
default: '',
|
|
69
|
+
description: 'Button text for this phase (max. 40 characters). Leave empty for the default text.',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
displayName: 'Button Icon',
|
|
73
|
+
name: 'iconName',
|
|
74
|
+
type: 'string',
|
|
75
|
+
default: '',
|
|
76
|
+
description: 'Button icon name. Leave empty for the default icon.',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
displayName: 'Button Color',
|
|
80
|
+
name: 'buttonStyle',
|
|
81
|
+
type: 'string',
|
|
82
|
+
default: '',
|
|
83
|
+
placeholder: '#FF0000, primary or black',
|
|
84
|
+
description: 'Button color as a hex code, or "primary"/"black"',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
displayName: 'Status Label',
|
|
88
|
+
name: 'statusLabel',
|
|
89
|
+
type: 'string',
|
|
90
|
+
default: '',
|
|
91
|
+
placeholder: 'LIVE',
|
|
92
|
+
description: 'Short badge text shown on the card while this phase is active (max. 12 characters).',
|
|
93
|
+
},
|
|
94
|
+
...availabilityFields('availableFrom', 'Available From', 'When this phase starts. Leave unset for the natural start (before: open-ended, during: event start, after: event end).'),
|
|
95
|
+
...availabilityFields('availableUntil', 'Available Until', 'When this phase ends. Leave unset for the natural end (before: event start, during: event end, after: open-ended).'),
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
const reminderChannelValues = [
|
|
99
|
+
{
|
|
100
|
+
displayName: 'Enabled',
|
|
101
|
+
name: 'enabled',
|
|
102
|
+
type: 'boolean',
|
|
103
|
+
default: true,
|
|
104
|
+
description: 'Whether the reminder is sent for this channel',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
displayName: 'Lead Minutes',
|
|
108
|
+
name: 'leadMinutes',
|
|
109
|
+
type: 'number',
|
|
110
|
+
typeOptions: { minValue: 1, maxValue: 1440 },
|
|
111
|
+
default: 10,
|
|
112
|
+
description: 'How many minutes before each occurrence the reminder is sent (1-1440)',
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
exports.calendarEventProperties = [
|
|
116
|
+
{
|
|
117
|
+
displayName: 'Operation',
|
|
118
|
+
name: 'operation',
|
|
119
|
+
type: 'options',
|
|
120
|
+
noDataExpression: true,
|
|
121
|
+
default: 'getAll',
|
|
122
|
+
displayOptions: show(),
|
|
123
|
+
options: [
|
|
124
|
+
{
|
|
125
|
+
name: 'Create Calendar Event',
|
|
126
|
+
value: 'create',
|
|
127
|
+
description: 'Create a calendar event series',
|
|
128
|
+
action: 'Create a calendar event',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'Delete Calendar Event',
|
|
132
|
+
value: 'delete',
|
|
133
|
+
description: 'Delete a calendar event series including all of its occurrences',
|
|
134
|
+
action: 'Delete a calendar event',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'Get Many',
|
|
138
|
+
value: 'getAll',
|
|
139
|
+
description: 'List calendar event series (never individual dates)',
|
|
140
|
+
action: 'Get many calendar events',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'Update Calendar Event',
|
|
144
|
+
value: 'update',
|
|
145
|
+
description: 'Update a calendar event series (only the fields you provide)',
|
|
146
|
+
action: 'Update a calendar event',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
displayName: 'From Date',
|
|
152
|
+
name: 'fromDate',
|
|
153
|
+
type: 'string',
|
|
154
|
+
placeholder: '2026-07-20',
|
|
155
|
+
displayOptions: show('getAll'),
|
|
156
|
+
default: '',
|
|
157
|
+
description: 'Start of the range (YYYY-MM-DD, inclusive). Selects series whose lifetime overlaps the range, not their individual dates; the range is widened by one day for timezone tolerance. Leave empty to return every series.',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
displayName: 'To Date',
|
|
161
|
+
name: 'toDate',
|
|
162
|
+
type: 'string',
|
|
163
|
+
placeholder: '2026-12-21',
|
|
164
|
+
displayOptions: show('getAll'),
|
|
165
|
+
default: '',
|
|
166
|
+
description: 'End of the range (YYYY-MM-DD, inclusive). Only usable together with From Date; leave empty for an open-ended range.',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
displayName: 'Limit',
|
|
170
|
+
name: 'limit',
|
|
171
|
+
type: 'number',
|
|
172
|
+
description: 'Max number of results to return',
|
|
173
|
+
displayOptions: show('getAll'),
|
|
174
|
+
typeOptions: { minValue: 1, maxValue: 100 },
|
|
175
|
+
default: 50,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
displayName: 'Offset',
|
|
179
|
+
name: 'offset',
|
|
180
|
+
type: 'number',
|
|
181
|
+
displayOptions: show('getAll'),
|
|
182
|
+
typeOptions: { minValue: 0 },
|
|
183
|
+
default: 0,
|
|
184
|
+
description: 'Number of results to skip for pagination',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
displayName: 'Calendar Event Name or ID',
|
|
188
|
+
name: 'calendarEventSeriesId',
|
|
189
|
+
type: 'options',
|
|
190
|
+
typeOptions: { loadOptionsMethod: 'calendarEvent_getCalendarEvents' },
|
|
191
|
+
displayOptions: show('update', 'delete'),
|
|
192
|
+
default: '',
|
|
193
|
+
required: true,
|
|
194
|
+
description: 'ID of the calendar event series. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
displayName: 'Name',
|
|
198
|
+
name: 'name',
|
|
199
|
+
type: 'string',
|
|
200
|
+
displayOptions: show('create'),
|
|
201
|
+
default: '',
|
|
202
|
+
required: true,
|
|
203
|
+
description: 'Display name of the event, shown on the calendar card (max. 35 characters).',
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
displayName: 'Start Date',
|
|
207
|
+
name: 'startDate',
|
|
208
|
+
type: 'string',
|
|
209
|
+
placeholder: '2026-07-20',
|
|
210
|
+
displayOptions: show('create'),
|
|
211
|
+
default: '',
|
|
212
|
+
required: true,
|
|
213
|
+
description: 'Date of the first occurrence (YYYY-MM-DD), interpreted in the event time zone',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
displayName: 'Start Time',
|
|
217
|
+
name: 'startTime',
|
|
218
|
+
type: 'string',
|
|
219
|
+
placeholder: '18:00',
|
|
220
|
+
displayOptions: show('create'),
|
|
221
|
+
default: '',
|
|
222
|
+
required: true,
|
|
223
|
+
description: 'Start time of every occurrence (HH:mm, 24-hour), interpreted in the event time zone',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
displayName: 'Time Zone',
|
|
227
|
+
name: 'timeZone',
|
|
228
|
+
type: 'string',
|
|
229
|
+
placeholder: 'Europe/Berlin',
|
|
230
|
+
displayOptions: show('create'),
|
|
231
|
+
default: 'Europe/Berlin',
|
|
232
|
+
required: true,
|
|
233
|
+
description: 'IANA time zone for all dates/times of this event, e.g. Europe/Berlin or Europe/Vienna',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
displayName: 'Repetition Interval',
|
|
237
|
+
name: 'repetitionInterval',
|
|
238
|
+
type: 'options',
|
|
239
|
+
displayOptions: show('create'),
|
|
240
|
+
options: [
|
|
241
|
+
{ name: 'One Time', value: 'oneTime', description: 'Single occurrence on the start date' },
|
|
242
|
+
{ name: 'Weekly', value: 'weekly', description: 'Repeats every 7 days' },
|
|
243
|
+
{ name: 'Bi-Weekly', value: 'biWeekly', description: 'Repeats every 14 days' },
|
|
244
|
+
],
|
|
245
|
+
default: 'oneTime',
|
|
246
|
+
required: true,
|
|
247
|
+
description: 'How often the event repeats',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
displayName: 'Link',
|
|
251
|
+
name: 'link',
|
|
252
|
+
type: 'string',
|
|
253
|
+
placeholder: 'https://zoom.us/j/123456789',
|
|
254
|
+
displayOptions: show('create'),
|
|
255
|
+
default: '',
|
|
256
|
+
required: true,
|
|
257
|
+
description: 'The event link members join through, e.g. a Zoom or Meet URL. Must be a valid URL.',
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
displayName: 'Additional Fields',
|
|
261
|
+
name: 'additionalFields',
|
|
262
|
+
type: 'collection',
|
|
263
|
+
placeholder: 'Add Field',
|
|
264
|
+
default: {},
|
|
265
|
+
displayOptions: show('create'),
|
|
266
|
+
options: [
|
|
267
|
+
{
|
|
268
|
+
displayName: 'Bundle Names or IDs',
|
|
269
|
+
name: 'bundleIds',
|
|
270
|
+
type: 'multiOptions',
|
|
271
|
+
typeOptions: { loadOptionsMethod: 'bundle_getBundles' },
|
|
272
|
+
default: [],
|
|
273
|
+
description: 'Bundles whose owners get access to the event. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
displayName: 'Description',
|
|
277
|
+
name: 'description',
|
|
278
|
+
type: 'string',
|
|
279
|
+
typeOptions: { rows: 3 },
|
|
280
|
+
default: '',
|
|
281
|
+
description: 'Short description shown on the calendar card on hover',
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
displayName: 'Duration (Minutes)',
|
|
285
|
+
name: 'duration',
|
|
286
|
+
type: 'number',
|
|
287
|
+
typeOptions: { minValue: 1 },
|
|
288
|
+
default: 60,
|
|
289
|
+
description: 'Duration in minutes (e.g. 60 = one hour). Omit for open-ended events.',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
displayName: 'End Date',
|
|
293
|
+
name: 'endDate',
|
|
294
|
+
type: 'string',
|
|
295
|
+
placeholder: '2026-12-21',
|
|
296
|
+
default: '',
|
|
297
|
+
description: 'Last date a recurring series repeats (YYYY-MM-DD, inclusive). Omit for open-ended series.',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
displayName: 'Group Names or IDs',
|
|
301
|
+
name: 'groupIds',
|
|
302
|
+
type: 'multiOptions',
|
|
303
|
+
typeOptions: { loadOptionsMethod: 'group_getGroups' },
|
|
304
|
+
default: [],
|
|
305
|
+
description: 'Groups whose members get access to the event. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
displayName: 'Member Names or IDs',
|
|
309
|
+
name: 'memberIds',
|
|
310
|
+
type: 'multiOptions',
|
|
311
|
+
typeOptions: { loadOptionsMethod: 'member_getMembers' },
|
|
312
|
+
default: [],
|
|
313
|
+
description: 'Users (IDs or email addresses) that get access to the event. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
displayName: 'Priority',
|
|
317
|
+
name: 'priority',
|
|
318
|
+
type: 'number',
|
|
319
|
+
typeOptions: { minValue: 0, maxValue: 9 },
|
|
320
|
+
default: 3,
|
|
321
|
+
description: 'Display priority 0-9; lower numbers are shown first. Defaults to 3.',
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
displayName: 'Reminders',
|
|
327
|
+
name: 'notificationSettings',
|
|
328
|
+
type: 'fixedCollection',
|
|
329
|
+
placeholder: 'Add Reminder Channel',
|
|
330
|
+
default: {},
|
|
331
|
+
displayOptions: show('create'),
|
|
332
|
+
description: 'Reminder settings of the event. Each enabled channel notifies all users with access before every occurrence. Channels you do not add send nothing.',
|
|
333
|
+
options: [
|
|
334
|
+
{ displayName: 'Push', name: 'push', values: reminderChannelValues },
|
|
335
|
+
{ displayName: 'Email', name: 'email', values: reminderChannelValues },
|
|
336
|
+
],
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
displayName: 'Fields to Update',
|
|
340
|
+
name: 'updateFields',
|
|
341
|
+
type: 'resourceMapper',
|
|
342
|
+
noDataExpression: true,
|
|
343
|
+
required: true,
|
|
344
|
+
default: { mappingMode: 'defineBelow', value: null },
|
|
345
|
+
displayOptions: show('update'),
|
|
346
|
+
description: 'Fields to send to the API. Only mapped fields are changed, everything else keeps its current value. Set a field to the expression {{ null }} to clear it — the API allows that for Description, Duration and End Date only.',
|
|
347
|
+
typeOptions: {
|
|
348
|
+
resourceMapper: {
|
|
349
|
+
resourceMapperMethod: 'getCalendarEventResourceMapperFields',
|
|
350
|
+
mode: 'add',
|
|
351
|
+
fieldWords: { singular: 'field', plural: 'fields' },
|
|
352
|
+
addAllFields: false,
|
|
353
|
+
multiKeyMatch: false,
|
|
354
|
+
supportAutoMap: true,
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
displayName: 'Reminders',
|
|
360
|
+
name: 'notificationSettings',
|
|
361
|
+
type: 'fixedCollection',
|
|
362
|
+
placeholder: 'Add Reminder Channel',
|
|
363
|
+
default: {},
|
|
364
|
+
displayOptions: show('update'),
|
|
365
|
+
description: 'Reminder settings of the event. Leave empty to keep the current reminders; adding it replaces all channels. To stop all reminders, add both channels with Enabled turned off.',
|
|
366
|
+
options: [
|
|
367
|
+
{ displayName: 'Push', name: 'push', values: reminderChannelValues },
|
|
368
|
+
{ displayName: 'Email', name: 'email', values: reminderChannelValues },
|
|
369
|
+
],
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
displayName: 'Link Stages',
|
|
373
|
+
name: 'linkStages',
|
|
374
|
+
type: 'fixedCollection',
|
|
375
|
+
placeholder: 'Add Link Stage',
|
|
376
|
+
default: {},
|
|
377
|
+
displayOptions: show('create', 'update'),
|
|
378
|
+
description: 'Per-phase links of the event. Requires the "During" phase; "Before"/"After" are optional and fall back to the single link. When set, link stages replace all existing phases and take precedence over the single link.',
|
|
379
|
+
options: [
|
|
380
|
+
{ displayName: 'Before', name: 'before', values: linkStageValues() },
|
|
381
|
+
{ displayName: 'During', name: 'during', values: linkStageValues() },
|
|
382
|
+
{ displayName: 'After', name: 'after', values: linkStageValues() },
|
|
383
|
+
],
|
|
384
|
+
},
|
|
385
|
+
];
|
|
@@ -207,7 +207,7 @@ exports.memberProperties = [
|
|
|
207
207
|
displayName: 'Do Not Require Password Change',
|
|
208
208
|
name: 'doNotRequirePasswordChange',
|
|
209
209
|
type: 'boolean',
|
|
210
|
-
default: false, //
|
|
210
|
+
default: false, // <- Example says false
|
|
211
211
|
description: 'Whether the member is not prompted to change their password upon first login, if this option is enabled. This option should only be used if the member has not set a password and should log in using SSO. The default setting is "true," so for privacy reasons, only the member knows their password.',
|
|
212
212
|
},
|
|
213
213
|
{
|
|
@@ -22,6 +22,11 @@ exports.resourceSelector = {
|
|
|
22
22
|
value: 'bundle',
|
|
23
23
|
description: 'List bundles (course packages) and retrieve the members of a bundle',
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
name: 'Calendar Event',
|
|
27
|
+
value: 'calendarEvent',
|
|
28
|
+
description: 'Manage calendar event series of the event plan',
|
|
29
|
+
},
|
|
25
30
|
{
|
|
26
31
|
name: 'Community',
|
|
27
32
|
value: 'community',
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.instantProperties = void 0;
|
|
4
4
|
exports.instantProperties = [
|
|
5
|
-
// Event
|
|
5
|
+
// Event selection (instant only)
|
|
6
6
|
{
|
|
7
7
|
displayName: 'Event',
|
|
8
8
|
name: 'event',
|
|
@@ -388,7 +388,7 @@ exports.instantProperties = [
|
|
|
388
388
|
},
|
|
389
389
|
],
|
|
390
390
|
},
|
|
391
|
-
// Feedback (
|
|
391
|
+
// Feedback (courseInstanceId only)
|
|
392
392
|
{
|
|
393
393
|
displayName: 'Feedback Options',
|
|
394
394
|
name: 'additionalFeedbackOptions',
|
|
@@ -478,7 +478,7 @@ exports.instantProperties = [
|
|
|
478
478
|
},
|
|
479
479
|
],
|
|
480
480
|
},
|
|
481
|
-
// Lesson Completed (
|
|
481
|
+
// Lesson Completed (cascading load options)
|
|
482
482
|
{
|
|
483
483
|
displayName: 'Lesson Completed Options',
|
|
484
484
|
name: 'additionalLessonCompleted',
|
|
@@ -136,7 +136,7 @@ exports.webhookProperties = [
|
|
|
136
136
|
{ name: 'User Activation Status Changed Events', value: 'user-activation-status-changed-events' },
|
|
137
137
|
],
|
|
138
138
|
},
|
|
139
|
-
// ======
|
|
139
|
+
// ====== Options per event (identical to instantProperties) ======
|
|
140
140
|
// Agent Action Executed
|
|
141
141
|
{
|
|
142
142
|
displayName: 'Agent Action Executed Options',
|
|
@@ -600,7 +600,7 @@ exports.webhookProperties = [
|
|
|
600
600
|
},
|
|
601
601
|
],
|
|
602
602
|
},
|
|
603
|
-
// Lesson Completed (
|
|
603
|
+
// Lesson Completed (cascading)
|
|
604
604
|
{
|
|
605
605
|
displayName: 'Lesson Completed Options',
|
|
606
606
|
name: 'additionalLessonCompleted',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IDataObject, IExecuteFunctions } from 'n8n-workflow';
|
|
2
|
-
/**
|
|
2
|
+
/** Unified function type for all execute handlers. */
|
|
3
3
|
export type ExecuteHandler = (ctx: IExecuteFunctions, itemIndex: number) => Promise<IDataObject | IDataObject[]>;
|
|
4
|
-
/** Registry
|
|
4
|
+
/** Registry type: resource -> operation -> handler */
|
|
5
5
|
export type HandlersRegistry = Record<string, Record<string, ExecuteHandler>>;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calendarEventHandlers = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const shared_1 = require("../shared");
|
|
6
|
+
const calendarEvent_resourceMapper_1 = require("../methods/resourceMappers/calendarEvent.resourceMapper");
|
|
7
|
+
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
8
|
+
const TIME_OF_DAY = /^([01][0-9]|2[0-3]):[0-5][0-9]$/;
|
|
9
|
+
const LINK_STAGES = ['before', 'during', 'after'];
|
|
10
|
+
const NULLABLE_FIELDS = ['description', 'duration', 'endDate'];
|
|
11
|
+
function isClearedByUser(ctx, field, value) {
|
|
12
|
+
if (value !== null)
|
|
13
|
+
return false;
|
|
14
|
+
if (!NULLABLE_FIELDS.includes(field)) {
|
|
15
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `The API cannot clear "${field}" — only ${NULLABLE_FIELDS.join(', ')} accept null. Provide a value instead.`);
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
function assertIsoDate(ctx, label, value) {
|
|
20
|
+
if (!ISO_DATE.test(value)) {
|
|
21
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `${label} must be a date in the format YYYY-MM-DD (e.g. 2026-07-20).`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function assertTimeOfDay(ctx, label, value) {
|
|
25
|
+
if (!TIME_OF_DAY.test(value)) {
|
|
26
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `${label} must be a time in the format HH:mm (e.g. 18:00).`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** fixedCollection entries arrive as an object or — with multipleValues — as an array. */
|
|
30
|
+
function firstEntry(value) {
|
|
31
|
+
var _a;
|
|
32
|
+
if (Array.isArray(value))
|
|
33
|
+
return (_a = value[0]) !== null && _a !== void 0 ? _a : undefined;
|
|
34
|
+
if (value && typeof value === 'object')
|
|
35
|
+
return value;
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
function buildAvailability(values, prefix) {
|
|
39
|
+
var _a, _b, _c;
|
|
40
|
+
const relation = String((_a = values[`${prefix}Relation`]) !== null && _a !== void 0 ? _a : '').trim();
|
|
41
|
+
if (!relation)
|
|
42
|
+
return undefined;
|
|
43
|
+
return {
|
|
44
|
+
amount: Number((_b = values[`${prefix}Amount`]) !== null && _b !== void 0 ? _b : 0),
|
|
45
|
+
unit: String((_c = values[`${prefix}Unit`]) !== null && _c !== void 0 ? _c : 'minutes'),
|
|
46
|
+
relation,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function buildLinkStage(ctx, stage, values) {
|
|
50
|
+
var _a, _b, _c, _d, _e;
|
|
51
|
+
const url = String((_a = values.url) !== null && _a !== void 0 ? _a : '').trim();
|
|
52
|
+
if (!url) {
|
|
53
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Link stage "${stage}" requires a URL.`);
|
|
54
|
+
}
|
|
55
|
+
const result = { url };
|
|
56
|
+
if (values.enabled !== undefined)
|
|
57
|
+
result.enabled = values.enabled;
|
|
58
|
+
const ctaLabel = String((_b = values.ctaLabel) !== null && _b !== void 0 ? _b : '').trim();
|
|
59
|
+
if (ctaLabel)
|
|
60
|
+
result.ctaLabel = ctaLabel;
|
|
61
|
+
const iconName = String((_c = values.iconName) !== null && _c !== void 0 ? _c : '').trim();
|
|
62
|
+
if (iconName)
|
|
63
|
+
result.iconName = iconName;
|
|
64
|
+
const buttonStyle = String((_d = values.buttonStyle) !== null && _d !== void 0 ? _d : '').trim();
|
|
65
|
+
if (buttonStyle)
|
|
66
|
+
result.color = buttonStyle;
|
|
67
|
+
const statusLabel = String((_e = values.statusLabel) !== null && _e !== void 0 ? _e : '').trim();
|
|
68
|
+
if (statusLabel)
|
|
69
|
+
result.statusLabel = statusLabel;
|
|
70
|
+
const availableFrom = buildAvailability(values, 'availableFrom');
|
|
71
|
+
if (availableFrom)
|
|
72
|
+
result.availableFrom = availableFrom;
|
|
73
|
+
const availableUntil = buildAvailability(values, 'availableUntil');
|
|
74
|
+
if (availableUntil)
|
|
75
|
+
result.availableUntil = availableUntil;
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
function buildLinkStages(ctx, i) {
|
|
79
|
+
const raw = ctx.getNodeParameter('linkStages', i, {});
|
|
80
|
+
const stages = {};
|
|
81
|
+
for (const stage of LINK_STAGES) {
|
|
82
|
+
const values = firstEntry(raw[stage]);
|
|
83
|
+
if (values)
|
|
84
|
+
stages[stage] = buildLinkStage(ctx, stage, values);
|
|
85
|
+
}
|
|
86
|
+
if (!Object.keys(stages).length)
|
|
87
|
+
return undefined;
|
|
88
|
+
if (!stages.during) {
|
|
89
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Link stages require the "During" phase. Add it, or remove the other phases to keep the single link.');
|
|
90
|
+
}
|
|
91
|
+
return stages;
|
|
92
|
+
}
|
|
93
|
+
function buildNotificationSettings(ctx, i) {
|
|
94
|
+
var _a;
|
|
95
|
+
const raw = ctx.getNodeParameter('notificationSettings', i, {});
|
|
96
|
+
const settings = {};
|
|
97
|
+
for (const channel of ['push', 'email']) {
|
|
98
|
+
const values = firstEntry(raw[channel]);
|
|
99
|
+
if (!values)
|
|
100
|
+
continue;
|
|
101
|
+
settings[channel] = {
|
|
102
|
+
enabled: values.enabled !== false,
|
|
103
|
+
leadMinutes: Number((_a = values.leadMinutes) !== null && _a !== void 0 ? _a : 10),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return Object.keys(settings).length ? settings : undefined;
|
|
107
|
+
}
|
|
108
|
+
const getAll = async (ctx, i) => {
|
|
109
|
+
const fromDate = String(ctx.getNodeParameter('fromDate', i, '') || '').trim();
|
|
110
|
+
const toDate = String(ctx.getNodeParameter('toDate', i, '') || '').trim();
|
|
111
|
+
const limit = ctx.getNodeParameter('limit', i, 50);
|
|
112
|
+
const offset = ctx.getNodeParameter('offset', i, 0);
|
|
113
|
+
if (toDate && !fromDate) {
|
|
114
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'To Date can only be used together with From Date.');
|
|
115
|
+
}
|
|
116
|
+
const qs = { limit, offset };
|
|
117
|
+
if (fromDate) {
|
|
118
|
+
assertIsoDate(ctx, 'From Date', fromDate);
|
|
119
|
+
qs.fromDate = fromDate;
|
|
120
|
+
}
|
|
121
|
+
if (toDate) {
|
|
122
|
+
assertIsoDate(ctx, 'To Date', toDate);
|
|
123
|
+
qs.toDate = toDate;
|
|
124
|
+
}
|
|
125
|
+
return await shared_1.lsRequest.call(ctx, 'GET', '/calendar-events', { qs });
|
|
126
|
+
};
|
|
127
|
+
const create = async (ctx, i) => {
|
|
128
|
+
var _a, _b;
|
|
129
|
+
const name = String(ctx.getNodeParameter('name', i, '') || '').trim();
|
|
130
|
+
const startDate = String(ctx.getNodeParameter('startDate', i, '') || '').trim();
|
|
131
|
+
const startTime = String(ctx.getNodeParameter('startTime', i, '') || '').trim();
|
|
132
|
+
const timeZone = String(ctx.getNodeParameter('timeZone', i, '') || '').trim();
|
|
133
|
+
const repetitionInterval = ctx.getNodeParameter('repetitionInterval', i, 'oneTime');
|
|
134
|
+
const link = String(ctx.getNodeParameter('link', i, '') || '').trim();
|
|
135
|
+
if (!name)
|
|
136
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide a name for the calendar event.');
|
|
137
|
+
if (!timeZone)
|
|
138
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide a time zone, e.g. Europe/Berlin.');
|
|
139
|
+
if (!link)
|
|
140
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide the event link.');
|
|
141
|
+
assertIsoDate(ctx, 'Start Date', startDate);
|
|
142
|
+
assertTimeOfDay(ctx, 'Start Time', startTime);
|
|
143
|
+
const body = { name, startDate, startTime, timeZone, repetitionInterval, link };
|
|
144
|
+
const additionalFields = ctx.getNodeParameter('additionalFields', i, {});
|
|
145
|
+
const description = String((_a = additionalFields.description) !== null && _a !== void 0 ? _a : '').trim();
|
|
146
|
+
if (description)
|
|
147
|
+
body.description = description;
|
|
148
|
+
if (additionalFields.priority !== undefined)
|
|
149
|
+
body.priority = additionalFields.priority;
|
|
150
|
+
if (additionalFields.duration !== undefined)
|
|
151
|
+
body.duration = additionalFields.duration;
|
|
152
|
+
const endDate = String((_b = additionalFields.endDate) !== null && _b !== void 0 ? _b : '').trim();
|
|
153
|
+
if (endDate) {
|
|
154
|
+
assertIsoDate(ctx, 'End Date', endDate);
|
|
155
|
+
body.endDate = endDate;
|
|
156
|
+
}
|
|
157
|
+
const memberIds = (0, shared_1.toIdArray)(additionalFields.memberIds);
|
|
158
|
+
if (memberIds.length)
|
|
159
|
+
body.memberIds = memberIds;
|
|
160
|
+
const groupIds = (0, shared_1.toIdArray)(additionalFields.groupIds);
|
|
161
|
+
if (groupIds.length)
|
|
162
|
+
body.groupIds = groupIds;
|
|
163
|
+
const bundleIds = (0, shared_1.toIdArray)(additionalFields.bundleIds);
|
|
164
|
+
if (bundleIds.length)
|
|
165
|
+
body.bundleIds = bundleIds;
|
|
166
|
+
const notificationSettings = buildNotificationSettings(ctx, i);
|
|
167
|
+
if (notificationSettings)
|
|
168
|
+
body.notificationSettings = notificationSettings;
|
|
169
|
+
const linkStages = buildLinkStages(ctx, i);
|
|
170
|
+
if (linkStages)
|
|
171
|
+
body.linkStages = linkStages;
|
|
172
|
+
return await shared_1.lsRequest.call(ctx, 'POST', '/calendar-events', { body });
|
|
173
|
+
};
|
|
174
|
+
const UPDATE_FIELD_LABELS = {
|
|
175
|
+
startDate: 'Start Date',
|
|
176
|
+
startTime: 'Start Time',
|
|
177
|
+
endDate: 'End Date',
|
|
178
|
+
};
|
|
179
|
+
const update = async (ctx, i) => {
|
|
180
|
+
var _a;
|
|
181
|
+
const calendarEventSeriesId = String(ctx.getNodeParameter('calendarEventSeriesId', i, '') || '').trim();
|
|
182
|
+
if (!calendarEventSeriesId) {
|
|
183
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide the ID of the calendar event.');
|
|
184
|
+
}
|
|
185
|
+
const mapped = ctx.getNodeParameter('updateFields', i, {});
|
|
186
|
+
const values = (_a = mapped === null || mapped === void 0 ? void 0 : mapped.value) !== null && _a !== void 0 ? _a : {};
|
|
187
|
+
const body = {};
|
|
188
|
+
for (const field of calendarEvent_resourceMapper_1.CALENDAR_EVENT_FIELD_IDS) {
|
|
189
|
+
if (!(field in values))
|
|
190
|
+
continue;
|
|
191
|
+
const raw = values[field];
|
|
192
|
+
if (raw === undefined)
|
|
193
|
+
continue;
|
|
194
|
+
if (isClearedByUser(ctx, field, raw)) {
|
|
195
|
+
body[field] = null;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (typeof raw === 'string') {
|
|
199
|
+
const value = raw.trim();
|
|
200
|
+
if (!value)
|
|
201
|
+
continue;
|
|
202
|
+
const label = UPDATE_FIELD_LABELS[field];
|
|
203
|
+
if (field === 'startDate' || field === 'endDate')
|
|
204
|
+
assertIsoDate(ctx, label, value);
|
|
205
|
+
if (field === 'startTime')
|
|
206
|
+
assertTimeOfDay(ctx, label, value);
|
|
207
|
+
body[field] = value;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
body[field] = raw;
|
|
211
|
+
}
|
|
212
|
+
const notificationSettings = buildNotificationSettings(ctx, i);
|
|
213
|
+
if (notificationSettings)
|
|
214
|
+
body.notificationSettings = notificationSettings;
|
|
215
|
+
const linkStages = buildLinkStages(ctx, i);
|
|
216
|
+
if (linkStages)
|
|
217
|
+
body.linkStages = linkStages;
|
|
218
|
+
if (!Object.keys(body).length) {
|
|
219
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide at least one field to update.');
|
|
220
|
+
}
|
|
221
|
+
return await shared_1.lsRequest.call(ctx, 'PATCH', `/calendar-events/${calendarEventSeriesId}`, { body });
|
|
222
|
+
};
|
|
223
|
+
const deleteCalendarEvent = async (ctx, i) => {
|
|
224
|
+
const calendarEventSeriesId = String(ctx.getNodeParameter('calendarEventSeriesId', i, '') || '').trim();
|
|
225
|
+
if (!calendarEventSeriesId) {
|
|
226
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide the ID of the calendar event.');
|
|
227
|
+
}
|
|
228
|
+
return await shared_1.lsRequest.call(ctx, 'DELETE', `/calendar-events/${calendarEventSeriesId}`);
|
|
229
|
+
};
|
|
230
|
+
exports.calendarEventHandlers = {
|
|
231
|
+
getAll,
|
|
232
|
+
create,
|
|
233
|
+
update,
|
|
234
|
+
delete: deleteCalendarEvent,
|
|
235
|
+
};
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.registry = void 0;
|
|
4
4
|
const apiCall_handlers_1 = require("./apiCall.handlers");
|
|
5
5
|
const bundle_handlers_1 = require("./bundle.handlers");
|
|
6
|
+
const calendarEvent_handlers_1 = require("./calendarEvent.handlers");
|
|
6
7
|
const community_handlers_1 = require("./community.handlers");
|
|
7
8
|
const course_handlers_1 = require("./course.handlers");
|
|
8
9
|
const group_handlers_1 = require("./group.handlers");
|
|
@@ -20,6 +21,7 @@ exports.registry = {
|
|
|
20
21
|
ai: ai_handlers_1.aiHandlers,
|
|
21
22
|
apiCall: apiCall_handlers_1.apiCallHandlers,
|
|
22
23
|
bundle: bundle_handlers_1.bundleHandlers,
|
|
24
|
+
calendarEvent: calendarEvent_handlers_1.calendarEventHandlers,
|
|
23
25
|
community: community_handlers_1.communityHandlers,
|
|
24
26
|
course: course_handlers_1.courseHandlers,
|
|
25
27
|
customFields: customFields_handlers_1.customFieldsHandlers,
|
|
@@ -179,7 +179,7 @@ function buildDesiredFilter(ctx, i, eventType) {
|
|
|
179
179
|
filter.groupId = String(col.groupId);
|
|
180
180
|
break;
|
|
181
181
|
}
|
|
182
|
-
// ---------------- Lesson Completed (
|
|
182
|
+
// ---------------- Lesson Completed (cascading)
|
|
183
183
|
case 'lesson.completed': {
|
|
184
184
|
const col = getCol(ctx, i, 'additionalLessonCompleted');
|
|
185
185
|
if (col.courseId)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calendarEvent_getCalendarEvents = calendarEvent_getCalendarEvents;
|
|
4
|
+
const shared_1 = require("../../shared");
|
|
5
|
+
const common_1 = require("./common");
|
|
6
|
+
async function calendarEvent_getCalendarEvents() {
|
|
7
|
+
const res = await shared_1.lsRequest.call(this, 'GET', '/calendar-events', { qs: { limit: 100 } });
|
|
8
|
+
const rows = (0, common_1.ensureArray)(res);
|
|
9
|
+
return rows.map((e) => {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
const when = [e.startDate, e.startTime].filter(Boolean).join(' ');
|
|
12
|
+
const label = e.name ? `${e.name}${when ? ` — ${when}` : ''}` : ((_a = e.id) !== null && _a !== void 0 ? _a : 'Unknown');
|
|
13
|
+
return { name: String(label), value: String((_b = e.id) !== null && _b !== void 0 ? _b : label) };
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -6,7 +6,7 @@ const shared_1 = require("../../shared");
|
|
|
6
6
|
const common_1 = require("./common");
|
|
7
7
|
function buildLabel(m) {
|
|
8
8
|
var _a, _b;
|
|
9
|
-
const fullName = (m === null || m === void 0 ? void 0 : m.fullName) || [m === null || m === void 0 ? void 0 : m.firstName, m === null || m === void 0 ? void 0 : m.lastName].filter(Boolean).join(' ') || '
|
|
9
|
+
const fullName = (m === null || m === void 0 ? void 0 : m.fullName) || [m === null || m === void 0 ? void 0 : m.firstName, m === null || m === void 0 ? void 0 : m.lastName].filter(Boolean).join(' ') || 'Unknown';
|
|
10
10
|
const role = (_a = m === null || m === void 0 ? void 0 : m.roleId) !== null && _a !== void 0 ? _a : '—';
|
|
11
11
|
const email = (_b = m === null || m === void 0 ? void 0 : m.email) !== null && _b !== void 0 ? _b : '';
|
|
12
12
|
return [fullName, role, email].filter(Boolean).join(' - ');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CALENDAR_EVENT_FIELD_IDS = void 0;
|
|
4
|
+
exports.getCalendarEventResourceMapperFields = getCalendarEventResourceMapperFields;
|
|
5
|
+
const CALENDAR_EVENT_FIELDS = [
|
|
6
|
+
{ id: 'name', displayName: 'Name (Max. 35 Characters)', type: 'string' },
|
|
7
|
+
{ id: 'description', displayName: 'Description', type: 'string' },
|
|
8
|
+
{ id: 'priority', displayName: 'Priority (0-9, Lower Shows First)', type: 'number' },
|
|
9
|
+
{ id: 'startDate', displayName: 'Start Date (YYYY-MM-DD)', type: 'string' },
|
|
10
|
+
{ id: 'startTime', displayName: 'Start Time (HH:mm)', type: 'string' },
|
|
11
|
+
{ id: 'duration', displayName: 'Duration (Minutes)', type: 'number' },
|
|
12
|
+
{ id: 'timeZone', displayName: 'Time Zone (IANA, e.g. Europe/Berlin)', type: 'string' },
|
|
13
|
+
{
|
|
14
|
+
id: 'repetitionInterval',
|
|
15
|
+
displayName: 'Repetition Interval',
|
|
16
|
+
type: 'options',
|
|
17
|
+
options: [
|
|
18
|
+
{ name: 'One Time', value: 'oneTime' },
|
|
19
|
+
{ name: 'Weekly', value: 'weekly' },
|
|
20
|
+
{ name: 'Bi-Weekly', value: 'biWeekly' },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
{ id: 'endDate', displayName: 'End Date (YYYY-MM-DD)', type: 'string' },
|
|
24
|
+
{ id: 'link', displayName: 'Link (Event URL)', type: 'string' },
|
|
25
|
+
].map((field) => ({
|
|
26
|
+
...field,
|
|
27
|
+
required: false,
|
|
28
|
+
display: true,
|
|
29
|
+
defaultMatch: false,
|
|
30
|
+
canBeUsedToMatch: false,
|
|
31
|
+
}));
|
|
32
|
+
exports.CALENDAR_EVENT_FIELD_IDS = CALENDAR_EVENT_FIELDS.map((field) => field.id);
|
|
33
|
+
async function getCalendarEventResourceMapperFields() {
|
|
34
|
+
return { fields: CALENDAR_EVENT_FIELDS };
|
|
35
|
+
}
|
|
@@ -149,12 +149,12 @@ class LearningSuitePollingTrigger {
|
|
|
149
149
|
group: ['trigger', 'schedule'],
|
|
150
150
|
version: 1,
|
|
151
151
|
polling: true,
|
|
152
|
-
description: 'Polling Trigger node for LearningSuite API (powered by
|
|
152
|
+
description: 'Polling Trigger node for LearningSuite API (powered by agentur-systeme.de)',
|
|
153
153
|
subtitle: '={{$parameter["event"]}}',
|
|
154
154
|
defaults: {
|
|
155
155
|
name: 'LearningSuite Polling Trigger',
|
|
156
156
|
// @ts-expect-error -- description is required by n8n node linting for defaults
|
|
157
|
-
description: 'Polling Trigger node for LearningSuite API (powered by
|
|
157
|
+
description: 'Polling Trigger node for LearningSuite API (powered by agentur-systeme.de)',
|
|
158
158
|
},
|
|
159
159
|
inputs: [],
|
|
160
160
|
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|