Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -0,0 +1,58 @@
import cats from "../../cats.app.mjs";

export default {
key: "cats-add-candidate-pipeline",
name: "Add Candidate to Job Pipeline",
description: "Adds a specific candidate to a job pipeline in CATS. [See the documentation](https://docs.catsone.com/api/v3/#jobs-create-a-job)",
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

Fix incorrect documentation link

The documentation link in the description points to the job creation API endpoint (/jobs-create-a-job), but this action is about adding candidates to job pipelines. Please update the link to point to the correct API endpoint documentation.

-  description: "Adds a specific candidate to a job pipeline in CATS. [See the documentation](https://docs.catsone.com/api/v3/#jobs-create-a-job)",
+  description: "Adds a specific candidate to a job pipeline in CATS. [See the documentation](https://docs.catsone.com/api/v3/#pipeline-create-a-pipeline)",
📝 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
description: "Adds a specific candidate to a job pipeline in CATS. [See the documentation](https://docs.catsone.com/api/v3/#jobs-create-a-job)",
description: "Adds a specific candidate to a job pipeline in CATS. [See the documentation](https://docs.catsone.com/api/v3/#pipeline-create-a-pipeline)",

version: "0.0.1",
type: "action",
props: {
cats,
createActivity: {
type: "boolean",
label: "Create Activity",
description: "Whether a corresponding activity should be created automatically. This mimics what happens when a pipeline is created from the CATS UI.",
optional: true,
},
candidateId: {
propDefinition: [
cats,
"candidateId",
],
},
jobId: {
propDefinition: [
cats,
"jobId",
],
},
rating: {
type: "integer",
label: "Rating",
description: "The record's rating for the job (0-5).",
optional: true,
},
Comment on lines +29 to +34
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

Add input validation for rating range

The rating property is described to accept values between 0-5, but there's no validation to enforce this range.

   rating: {
     type: "integer",
     label: "Rating",
     description: "The record's rating for the job (0-5).",
     optional: true,
+    min: 0,
+    max: 5,
   },
📝 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
rating: {
type: "integer",
label: "Rating",
description: "The record's rating for the job (0-5).",
optional: true,
},
rating: {
type: "integer",
label: "Rating",
description: "The record's rating for the job (0-5).",
optional: true,
min: 0,
max: 5,
},

},
async run({ $ }) {
const { headers } = await this.cats.addCandidateToJobPipeline({
$,
returnFullResponse: true,
params: {
create_activity: this.createActivity,
},
data: {
candidate_id: this.candidateId,
job_id: this.jobId,
rating: this.rating,
},
});

const location = headers.location.split("/");
const pipelineId = location[location.length - 1];
Comment on lines +50 to +51
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

Add robust error handling for location header parsing

The current implementation assumes the location header will always be present and in the expected format. This could lead to runtime errors if the API response changes.

-    const location = headers.location.split("/");
-    const pipelineId = location[location.length - 1];
+    if (!headers?.location) {
+      throw new Error("Failed to get pipeline ID from response");
+    }
+    const pipelineId = headers.location.split("/").pop();
+    if (!pipelineId) {
+      throw new Error("Invalid pipeline ID format in response");
+    }
📝 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
const location = headers.location.split("/");
const pipelineId = location[location.length - 1];
if (!headers?.location) {
throw new Error("Failed to get pipeline ID from response");
}
const pipelineId = headers.location.split("/").pop();
if (!pipelineId) {
throw new Error("Invalid pipeline ID format in response");
}


$.export("$summary", `Successfully added candidate ID ${this.candidateId} to job ID ${this.jobId}`);
return {
pipelineId,
};
},
};
308 changes: 308 additions & 0 deletions components/cats/actions/create-candidate/create-candidate.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
import cats from "../../cats.app.mjs";
import { parseObject } from "../../common/utils.mjs";

export default {
key: "cats-create-candidate",
name: "Create Candidate",
description: "Create a new candidate in your CATS database. [See the documentation](https://docs.catsone.com/api/v3/#candidates-create-a-candidate)",
version: "0.0.1",
type: "action",
props: {
cats,
checkDuplicate: {
propDefinition: [
cats,
"checkDuplicate",
],
},
firstName: {
propDefinition: [
cats,
"firstName",
],
},
middleName: {
propDefinition: [
cats,
"middleName",
],
optional: true,
},
lastName: {
propDefinition: [
cats,
"lastName",
],
},
title: {
propDefinition: [
cats,
"title",
],
optional: true,
},
emails: {
propDefinition: [
cats,
"emails",
],
optional: true,
},
phones: {
propDefinition: [
cats,
"phones",
],
optional: true,
},
addressStreet: {
propDefinition: [
cats,
"addressStreet",
],
optional: true,
},
addressCity: {
propDefinition: [
cats,
"addressCity",
],
optional: true,
},
addressState: {
propDefinition: [
cats,
"addressState",
],
optional: true,
},
addressPostalCode: {
propDefinition: [
cats,
"addressPostalCode",
],
optional: true,
},
countryCode: {
propDefinition: [
cats,
"countryCode",
],
optional: true,
},
socialMediaUrls: {
propDefinition: [
cats,
"socialMediaUrls",
],
optional: true,
},
website: {
type: "string",
label: "Website",
description: "The website of the record.",
optional: true,
},
bestTimeToCall: {
propDefinition: [
cats,
"bestTimeToCall",
],
optional: true,
},
currentEmployer: {
propDefinition: [
cats,
"currentEmployer",
],
optional: true,
},
dateAvailable: {
type: "string",
label: "Date Available",
description: "The date the record is available for an opening. **Format: YYYY-MM-DD**.",
optional: true,
},
currentPay: {
type: "string",
label: "Current Pay",
description: "The current pay of the record.",
optional: true,
},
desiredPay: {
propDefinition: [
cats,
"desiredPay",
],
optional: true,
},
isWillingToRelocate: {
propDefinition: [
cats,
"isWillingToRelocate",
],
optional: true,
},
keySkills: {
propDefinition: [
cats,
"keySkills",
],
optional: true,
},
notes: {
propDefinition: [
cats,
"notes",
],
optional: true,
},
source: {
propDefinition: [
cats,
"source",
],
optional: true,
},
ownerId: {
propDefinition: [
cats,
"ownerId",
],
optional: true,
},
isActive: {
type: "boolean",
label: "Is Active",
description: "A flag indicating if the candidate is active.",
optional: true,
},
isHot: {
propDefinition: [
cats,
"isHot",
],
optional: true,
},
password: {
type: "string",
label: "password",
description: "The candidate's password if they are \"registering\".",
secret: true,
optional: true,
},
customFields: {
propDefinition: [
cats,
"customFields",
],
withLabel: true,
reloadProps: true,
optional: true,
},
workHistory: {
propDefinition: [
cats,
"workHistory",
],
optional: true,
},
},
async additionalProps() {
const props = {};
(this.customFields || []).map(({
label, value,
}) => {
props[value] = {
type: "string",
label: `Custom Field: ${label}`,
optional: true,
};
}, {});

return props;
},
async run({ $ }) {
const {
cats, // eslint-disable-next-line no-unused-vars
customFields,
firstName,
lastName,
ownerId,
middleName,
checkDuplicate,
bestTimeToCall,
currentEmployer,
emails,
phones,
addressStreet,
addressCity,
addressState,
addressPostalCode,
countryCode,
socialMediaUrls,
dateAvailable,
currentPay,
desiredPay,
isWillingToRelocate,
keySkills,
isActive,
isHot,
workHistory,
...data
} = this;

const customFieldsObject = customFields
? customFields.map(({ value }) => {
return {
id: value,
value: data[value],
};
})
: {};

const { headers } = await cats.createCandidate({
$,
returnFullResponse: true,
params: {
check_duplicate: checkDuplicate,
},
data: {
first_name: firstName,
middle_name: middleName,
last_name: lastName,
emails: parseObject(emails),
phones: parseObject(phones),
address: {
street: addressStreet,
city: addressCity,
state: addressState,
postal_code: addressPostalCode,
},
country_code: countryCode,
social_media_urls: parseObject(socialMediaUrls),
best_time_to_call: bestTimeToCall,
current_employer: currentEmployer,
date_available: dateAvailable,
current_pay: currentPay,
desired_pay: desiredPay,
is_willing_to_relocate: isWillingToRelocate,
key_skills: keySkills,
owner_id: ownerId,
is_active: isActive,
is_hot: isHot,
work_history: parseObject(workHistory),
custom_fields: customFieldsObject,
...data,
},
});

const location = headers.location.split("/");
const candidateId = location[location.length - 1];

$.export("$summary", `Created candidate with ID ${candidateId}`);
return {
candidateId,
};
},
};
Loading
Loading