Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default {
key: "workday-change-business-title",
name: "Change Business Title",
description: "Change the business title of a worker. [See the documentation](https://community.workday.com/sites/default/files/file-hosting/restapi/#common/v1/post-/workers/-ID-/businessTitleChanges)",
version: "0.0.3",
version: "0.0.4",
annotations: {
destructiveHint: false,
openWorldHint: true,
Expand Down
78 changes: 78 additions & 0 deletions components/workday/actions/close-mentorship/close-mentorship.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import workday from "../../workday.app.mjs";
import { ConfigurationError } from "@pipedream/platform";

export default {
key: "workday-close-mentorship",
name: "Close Mentorship",
description: "End a mentorship for a given ID. [See the Documentation](https://community.workday.com/sites/default/files/file-hosting/restapi/#talentManagement/v2/post-/mentorships/-ID-/close)",
version: "0.0.1",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},

type: "action",
props: {
workday,
mentorshipId: {
propDefinition: [
workday,
"mentorshipId",
],
},
comment: {
type: "string",
label: "Comment",
description: "Last event comment (optional). Example: `Lorem ipsum dolor sit amet, ...`",
optional: true,
},
startDate: {
type: "string",
label: "Start Date",
description: "Start date for the mentorship (ISO 8601). Example: `2025-10-18T07:00:00.000Z`",
},
endDate: {
type: "string",
label: "End Date",
description: "End date for the mentorship (ISO 8601). Example: `2025-10-18T07:00:00.000Z`",
},
Comment on lines +30 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add validation for required date fields.

The startDate and endDate fields are required but lack validation. This is inconsistent with the validation provided for closeMentorshipReason (lines 53-60). Without validation, the action could fail with unclear errors if these fields are missing or empty.

Apply this diff to add validation:

  async run({ $ }) {
+   if (!this.startDate || !this.startDate.trim()) {
+     throw new ConfigurationError("Start Date is required and cannot be empty.");
+   }
+   if (!this.endDate || !this.endDate.trim()) {
+     throw new ConfigurationError("End Date is required and cannot be empty.");
+   }
    if (
      !this.closeMentorshipReason ||
🤖 Prompt for AI Agents
In components/workday/actions/close-mentorship/close-mentorship.mjs around lines
30 to 39, the startDate and endDate schema entries are missing validation; make
them required and add a validate function like closeMentorshipReason has that
ensures the value is present and non-empty and also checks the value is a valid
ISO 8601 date (e.g., attempt Date.parse(value) and reject if NaN). Update both
startDate and endDate to include required: true and a validate handler that
returns a descriptive error string when empty or not a valid ISO date.

closeMentorshipReason: {
type: "object",
label: "Close Mentorship Reason",
description: "Example: `{ \"id\": \"00000000000000000000000000000000\" }`",
},
descriptor: {
type: "string",
label: "Descriptor",
description: "Display name. Example: `Lorem ipsum dolor sit ame`",
optional: true,
},
},
async run({ $ }) {
if (
!this.closeMentorshipReason ||
typeof this.closeMentorshipReason !== "object" ||
!this.closeMentorshipReason.id ||
!this.closeMentorshipReason.id.trim()
) {
throw new ConfigurationError("closeMentorshipReason is required and must be an object with a non-empty id property.");
}

const data = {
closeMentorshipReason: this.closeMentorshipReason,
startDate: this.startDate,
endDate: this.endDate,
};
if (this.comment) data.comment = this.comment;
if (this.descriptor) data.descriptor = this.descriptor;

const response = await this.workday.closeMentorship({
id: this.mentorshipId,
data,
$,
});
$.export("$summary", `Mentorship ${this.mentorshipId} closed`);
return response;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import workday from "../../workday.app.mjs";
import { ConfigurationError } from "@pipedream/platform";
import utils from "../../sources/common/utils.mjs";

export default {
key: "workday-create-digital-course",
name: "Create Digital Course",
description: "Create a digital learning course. [See the Documentation](https://community.workday.com/sites/default/files/file-hosting/restapi/#learning/v1/post-/manageDigitalCourses)",
version: "0.0.1",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},
type: "action",
props: {
workday,
topics: {
type: "string[]",
label: "Topics",
description: "The topics of the learning course event. Example: `[ { \"descriptor\": \"Leadership\", \"id\": \"topic-id-1\" } ]`",
},
title: {
type: "string",
label: "Title",
description: "Course title. Example: `Digital Leadership 101`",
},
availabilityStatus: {
type: "object",
label: "Availability Status",
description: "The status of the learning course event. Example: `{ \"id\": \"status-id-1\" }`",
},
lessons: {
type: "string[]",
label: "Lessons",
description: "The course lessons of the learning course event. Example: `[ { \"title\": \"Lesson 1\", \"type\": { \"id\": \"type-id\" }, \"order\": 1, \"url\": \"https://...\", \"required\": true } ]`",
},
description: {
type: "string",
label: "Description",
description: "Course description. Example: `Learn digital leadership strategies for remote teams.`",
},
},
async run({ $ }) {
const parsedTopics = utils.parseJsonInput(this.topics);
const parsedLessons = utils.parseJsonInput(this.lessons);

if (!Array.isArray(parsedTopics) || parsedTopics.length === 0) {
throw new ConfigurationError("`topics` must be a non-empty array.");
}
for (const t of parsedTopics) {
if (!t.id || !t.descriptor) {
throw new ConfigurationError("Each topic must have both `id` and `descriptor`.");
}
}

if (!Array.isArray(parsedLessons) || parsedLessons.length === 0) {
throw new ConfigurationError("`lessons` must be a non-empty array.");
}
for (const l of parsedLessons) {
if (!l.title || !l.type?.id || typeof l.order !== "number" || !l.url) {
throw new ConfigurationError("Each lesson must include `title`, `type` (object with id), `order` (integer), and `url`.");
}
}

if (!this.title || !this.title.trim()) {
throw new ConfigurationError("`title` is required.");
}
if (!this.availabilityStatus || typeof this.availabilityStatus !== "object" || !this.availabilityStatus.id) {
throw new ConfigurationError("`availabilityStatus` is required and must be an object with a non-empty 'id'.");
}
Comment on lines +69 to +71
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Ensure availabilityStatus.id is a non-empty string.
Avoid sending non-string/blank IDs.

-    if (!this.availabilityStatus || typeof this.availabilityStatus !== "object" || !this.availabilityStatus.id) {
+    if (!this.availabilityStatus || typeof this.availabilityStatus !== "object"
+      || typeof this.availabilityStatus.id !== "string"
+      || !this.availabilityStatus.id.trim()) {
       throw new ConfigurationError("`availabilityStatus` is required and must be an object with a non-empty 'id'.");
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!this.availabilityStatus || typeof this.availabilityStatus !== "object" || !this.availabilityStatus.id) {
throw new ConfigurationError("`availabilityStatus` is required and must be an object with a non-empty 'id'.");
}
if (!this.availabilityStatus || typeof this.availabilityStatus !== "object"
|| typeof this.availabilityStatus.id !== "string"
|| !this.availabilityStatus.id.trim()) {
throw new ConfigurationError("`availabilityStatus` is required and must be an object with a non-empty 'id'.");
}
🤖 Prompt for AI Agents
In components/workday/actions/create-digital-course/create-digital-course.mjs
around lines 69 to 71, the validation currently only checks that
availabilityStatus.id exists but does not ensure it's a non-empty string; update
the guard to verify typeof this.availabilityStatus.id === "string" and that
this.availabilityStatus.id.trim().length > 0, and throw the same
ConfigurationError if the check fails so blank or non-string IDs are rejected
before proceeding.

if (!this.description || !this.description.trim()) {
throw new ConfigurationError("`description` is required.");
}

const data = {
topics: parsedTopics,
title: this.title,
availabilityStatus: this.availabilityStatus,
lessons: parsedLessons,
description: this.description,
};

const response = await this.workday.createDigitalCourse({
$,
data,
});
$.export("$summary", "Digital course created");
return response;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import workday from "../../workday.app.mjs";
import { ConfigurationError } from "@pipedream/platform";

export default {
key: "workday-create-distribution-request",
name: "Create Distribution Request",
description: "Create a new distribution request. [See the Documentation](https://community.workday.com/sites/default/files/file-hosting/restapi/#journeys/v1/post-/distributionRequests)",
version: "0.0.1",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},
type: "action",
props: {
workday,
builder: {
type: "object",
label: "Builder",
description: "A journey builder object. Example: `{ \"id\": \"00000000000000000000000000000000\" }`",
},
category: {
type: "object",
label: "Category",
description: "A journey category object. Example: `{ \"id\": \"00000000000000000000000000000000\" }`",
},
discoverableBuilder: {
type: "object",
label: "Discoverable Builder",
description: "A discoverable journey builder object. Example: `{ \"id\": \"00000000000000000000000000000000\" }`",
},
Comment on lines +27 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Props marked required but treated optional in code

discoverableBuilder and relatedRole are validated/used only if provided, but the props lack optional: true. This will force users to supply them in the UI.

     discoverableBuilder: {
       type: "object",
       label: "Discoverable Builder",
       description: "A discoverable journey builder object. Example: `{ \"id\": \"00000000000000000000000000000000\" }`",
+      optional: true,
     },
@@
     relatedRole: {
       type: "object",
       label: "Related Role",
       description: "Related role object. Example: `{ \"id\": \"00000000000000000000000000000000\" }`",
+      optional: true,
     },

Also applies to: 38-42

🤖 Prompt for AI Agents
In
components/workday/actions/create-distribution-request/create-distribution-request.mjs
around lines 27-31 and 38-42, the properties discoverableBuilder and relatedRole
are currently defined without optional: true but the code only validates/uses
them when provided; to fix this add optional: true to both property definitions
so the UI won't force users to supply them and the schema matches runtime
behavior.

includePreviousRecipients: {
type: "boolean",
label: "Include Previous Recipients",
description: "Whether to include previous recipients. Example: `true`",
optional: true,
},
relatedRole: {
type: "object",
label: "Related Role",
description: "Related role object. Example: `{ \"id\": \"00000000000000000000000000000000\" }`",
},
descriptor: {
type: "string",
label: "Descriptor",
description: "Display name for the instance. Example: `Distribution Request for Training`",
optional: true,
},
},
async run({ $ }) {
if (!this.builder || typeof this.builder !== "object" || !this.builder.id || !this.builder.id.trim()) {
throw new ConfigurationError("Builder is required and must be an object with a non-empty id property.");
}
if (!this.category || typeof this.category !== "object" || !this.category.id || !this.category.id.trim()) {
throw new ConfigurationError("Category is required and must be an object with a non-empty id property.");
}
if (this.discoverableBuilder && (typeof this.discoverableBuilder !== "object" || !this.discoverableBuilder.id || !this.discoverableBuilder.id.trim())) {
throw new ConfigurationError("Discoverable Builder (if provided) must be an object with a non-empty id property.");
}
if (this.relatedRole && (typeof this.relatedRole !== "object" || !this.relatedRole.id || !this.relatedRole.id.trim())) {
throw new ConfigurationError("Related Role (if provided) must be an object with a non-empty id property.");
}

const data = {
builder: this.builder,
category: this.category,
};
if (this.discoverableBuilder) data.discoverableBuilder = this.discoverableBuilder;
if (typeof this.includePreviousRecipients === "boolean") data.includePreviousRecipients = this.includePreviousRecipients;
if (this.relatedRole) data.relatedRole = this.relatedRole;
if (this.descriptor) data.descriptor = this.descriptor;

const response = await this.workday.createDistributionRequest({
$,
data,
});
$.export("$summary", "Distribution request created");
return response;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import workday from "../../workday.app.mjs";
import { ConfigurationError } from "@pipedream/platform";

export default {
key: "workday-initiate-home-contact-information-change",
name: "Initiate Home Contact Information Change",
description: "Initiates a home contact change for a worker. [See the Documentation](https://community.workday.com/sites/default/files/file-hosting/restapi/#person/v4/)",
version: "0.0.1",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},
type: "action",
props: {
workday,
workerId: {
propDefinition: [
workday,
"workerId",
],
},
},
async run({ $ }) {
if (!this.workerId || !this.workerId.trim()) {
throw new ConfigurationError("Worker ID is required.");
}
const response = await this.workday.createHomeContactInformationChange({
workerId: this.workerId,
data: {},
$,
});
$.export("$summary", `Home contact change event initiated for worker ID ${this.workerId}`);
return response;
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default {
key: "workday-create-job-change",
name: "Create Job Change",
description: "Create a job change for a worker. [See the documentation](https://community.workday.com/sites/default/files/file-hosting/restapi/#common/v1/post-/workers/-ID-/jobChanges)",
version: "0.0.3",
version: "0.0.4",
annotations: {
destructiveHint: false,
openWorldHint: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import workday from "../../workday.app.mjs";
import { ConfigurationError } from "@pipedream/platform";

export default {
key: "workday-create-mentorship-for-me",
name: "Create Mentorship For Current User",
description: "Creates a mentorship for the current user. [See the Documentation](https://community.workday.com/sites/default/files/file-hosting/restapi/#talentManagement/v2/post-/createMentorshipForMe)",
version: "0.0.1",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},
type: "action",
props: {
workday,
endDate: {
type: "string",
label: "End Date",
description: "Proposed end date (ISO 8601 format). Example: '2025-10-18T07:00:00.000Z'",
},
startDate: {
type: "string",
label: "Start Date",
description: "Proposed start date (ISO 8601 format). Example: '2025-10-18T07:00:00.000Z'",
},
purpose: {
type: "string",
label: "Purpose",
description: "Purpose of the mentorship.",
},
mentor: {
type: "object",
label: "Mentor",
description: "Object with at least an `id`. Example: `{ id: \"00000000000000000000000000000000\"}`",
},
comment: {
type: "string",
label: "Comment",
description: "Optional. Comment field for notes or special requests.",
optional: true,
},
mentorType: {
type: "object",
label: "Mentor Type",
description: "Object with at least an `id`. Example: `{ id: \"00000000000000000000000000000000\"}`",
optional: true,
},
descriptor: {
type: "string",
label: "Descriptor",
description: "Optional. Display name of the mentorship.",
optional: true,
},
},
async run({ $ }) {
if (!this.endDate || !this.endDate.trim()) throw new ConfigurationError("End Date is required and cannot be empty.");
if (!this.startDate || !this.startDate.trim()) throw new ConfigurationError("Start Date is required and cannot be empty.");
if (!this.purpose || !this.purpose.trim()) throw new ConfigurationError("Purpose is required and cannot be empty.");
if (!this.mentor || typeof this.mentor !== "object" || !this.mentor.id || !this.mentor.id.trim()) {
throw new ConfigurationError("Mentor is required and must be an object with a non-empty id property.");
}
if (this.mentorType !== undefined) {
if (typeof this.mentorType !== "object" || !this.mentorType.id || !this.mentorType.id.trim()) {
throw new ConfigurationError("If provided, mentorType must be an object with a non-empty id property.");
}
}

const data = {
endDate: this.endDate,
startDate: this.startDate,
purpose: this.purpose,
mentor: this.mentor,
};
if (this.comment) data.comment = this.comment;
if (this.mentorType) data.mentorType = this.mentorType;
if (this.descriptor) data.descriptor = this.descriptor;

const response = await this.workday.createMentorshipForMe({
$,
data,
});
$.export("$summary", "Mentorship created for current user");
return response;
},
};
Loading
Loading