diff --git a/docs/setup/resources/1-developer-console.png b/docs/setup/resources/1-developer-console.png index 9f40fa6..64b591e 100644 Binary files a/docs/setup/resources/1-developer-console.png and b/docs/setup/resources/1-developer-console.png differ diff --git a/docs/setup/resources/2-create-token.png b/docs/setup/resources/2-create-token.png index fb6b77f..330292c 100644 Binary files a/docs/setup/resources/2-create-token.png and b/docs/setup/resources/2-create-token.png differ diff --git a/docs/setup/resources/3-copy-token.png b/docs/setup/resources/3-copy-token.png index 01dc6c6..90c6e4c 100644 Binary files a/docs/setup/resources/3-copy-token.png and b/docs/setup/resources/3-copy-token.png differ diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..2614ee1 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,53 @@ +# Examples + +The `ballerinax/asana` connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-asana/tree/main/examples), covering use cases like cache management, session management, and rate limiting. + +1. [Employee onboarding process automation](https://github.com/ballerina-platform/module-ballerinax-asana/tree/master/examples/employee-onboarding-process-automation) - Automate the onboarding process of new employees using Asana projects and tasks. + +2. [Team workload balancer](https://github.com/ballerina-platform/module-ballerinax-asana/tree/master/examples/team-workload-balancer) - Evaluate and balance the workload of a given team using Asana tasks and assignments. + + +## Prerequisites + +1. Create an Asana personal access token (PAT) to authenticate the connector as described in the [Setup guide](https://central.ballerina.io/ballerinax/asana/latest#setup-guide). + +2. For each example, create a `Config.toml` file the related configuration. Here's an example of how your `Config.toml` file should look: + + ```toml + authToken="" + workspaceId="" + ``` + +## Running an Example + +Execute the following commands to build an example from the source: + +* To build an example: + + ```bash + bal build + ``` + +* To run an example: + + ```bash + bal run + ``` + +## Building the Examples with the Local Module + +**Warning**: Due to the absence of support for reading local repositories for single Ballerina files, the Bala of the module is manually written to the central repository as a workaround. Consequently, the bash script may modify your local Ballerina repositories. + +Execute the following commands to build all the examples against the changes you have made to the module locally: + +* To build all the examples: + + ```bash + ./build.sh build + ``` + +* To run all the examples: + + ```bash + ./build.sh run + ``` diff --git a/examples/build.gradle b/examples/build.gradle new file mode 100644 index 0000000..9046bec --- /dev/null +++ b/examples/build.gradle @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.tools.ant.taskdefs.condition.Os + +apply plugin: 'java' + +def graalvmFlag = "" + +task testExamples { + if (project.hasProperty("balGraalVMTest")) { + graalvmFlag = "--graalvm" + } + doLast { + try { + exec { + workingDir project.projectDir + println("Working dir: ${workingDir}") + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh run && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh run" + } + } + } catch (Exception e) { + println("Example Build failed: " + e.message) + throw e + } + } +} + +task buildExamples { + gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(":asana-examples:test")) { + buildExamples.enabled = false + } else { + testExamples.enabled = false + } + } + doLast { + try { + exec { + workingDir project.projectDir + println("Working dir: ${workingDir}") + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh build && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh build" + } + } + } catch (Exception e) { + println("Example Build failed: " + e.message) + throw e + } + } +} + +buildExamples.dependsOn ":asana-ballerina:build" +testExamples.dependsOn ":asana-ballerina:build" + +// TODO: Enable the examples build once https://github.com/ballerina-platform/ballerina-library/issues/6135 is fixed +// test.dependsOn testExamples +// build.dependsOn buildExamples diff --git a/examples/build.sh b/examples/build.sh new file mode 100755 index 0000000..10fe84c --- /dev/null +++ b/examples/build.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +BAL_EXAMPLES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BAL_CENTRAL_DIR="$HOME/.ballerina/repositories/central.ballerina.io" +BAL_HOME_DIR="$BAL_EXAMPLES_DIR/../ballerina" + +set -e + +case "$1" in +build) + BAL_CMD="build" + ;; +run) + BAL_CMD="run" + ;; +*) + echo "Invalid command provided: '$1'. Please provide 'build' or 'run' as the command." + exit 1 + ;; +esac + +# Read Ballerina package name +BAL_PACKAGE_NAME=$(awk -F'"' '/^name/ {print $2}' "$BAL_HOME_DIR/Ballerina.toml") + +# Push the package to the local repository +cd "$BAL_HOME_DIR" && + bal pack && + bal push --repository=local + +# Remove the cache directories in the repositories +cacheDirs=$(ls -d $BAL_CENTRAL_DIR/cache-* 2>/dev/null) || true +for dir in "${cacheDirs[@]}"; do + [ -d "$dir" ] && rm -r "$dir" +done +echo "Successfully cleaned the cache directories" + +# Create the package directory in the central repository, this will not be present if no modules are pulled +mkdir -p "$BAL_CENTRAL_DIR/bala/ballerinax/$BAL_PACKAGE_NAME" + +# Update the central repository +BAL_DESTINATION_DIR="$HOME/.ballerina/repositories/central.ballerina.io/bala/ballerinax/$BAL_PACKAGE_NAME" +BAL_SOURCE_DIR="$HOME/.ballerina/repositories/local/bala/ballerinax/$BAL_PACKAGE_NAME" +[ -d "$BAL_DESTINATION_DIR" ] && rm -r "$BAL_DESTINATION_DIR" +[ -d "$BAL_SOURCE_DIR" ] && cp -r "$BAL_SOURCE_DIR" "$BAL_DESTINATION_DIR" +echo "Successfully updated the local central repositories" + +echo "$BAL_DESTINATION_DIR" +echo "$BAL_SOURCE_DIR" + +# Loop through examples in the examples directory +cd "$BAL_EXAMPLES_DIR" +for dir in $(find "$BAL_EXAMPLES_DIR" -type d -maxdepth 1 -mindepth 1); do + # Skip the build directory + if [[ "$dir" == *build ]]; then + continue + fi + (cd "$dir" && bal "$BAL_CMD" --offline && cd ..); +done + +# Remove generated JAR files +find "$BAL_HOME_DIR" -maxdepth 1 -type f -name "*.jar" | while read -r JAR_FILE; do + rm "$JAR_FILE" +done diff --git a/examples/employee-onboarding-process-automation/main.bal b/examples/employee-onboarding-process-automation/main.bal index c0ed37d..b967fd3 100644 --- a/examples/employee-onboarding-process-automation/main.bal +++ b/examples/employee-onboarding-process-automation/main.bal @@ -31,15 +31,55 @@ asana:Client asana = check new (asanaConfig); // Function to automate the creation of an employee onboarding project with tasks public function main() returns error? { - record {asana:ProjectCompact[] data?;} projects = check asana->/projects(); - - asana:Tasks_body taskReq = { + // Step 1: Create a new onboarding project + asana:Projects_body projectBody = { data: { - name: "Email Marketing Campaign", - notes: "Create a new email marketing campaign for the upcoming product launch.", - workspace: "", - projects: [""] + name: "Onboarding - " + newEmployeeName, + workspace: workspaceId, + team: teamId } }; - record {asana:TaskResponse data?;} taskCreated = check asana->/tasks.post(taskReq); + + asana:Inline_response_201_5|error projectResponse = asana->/projects.post(projectBody); + if projectResponse is error { + return error("error creating project: " + projectResponse.message()); + } + + string? projectId = projectResponse?.data?.gid; + if projectId is () { + return error("project ID not found in response"); + } + + // Step 2: Add sections to the new project + string[] sections = ["Documentation", "Training", "Setup"]; + foreach string sectionName in sections { + asana:Project_gid_sections_body sectionBody = { + data: { + name: sectionName + } + }; + + asana:Inline_response_200_30|error sectionCreationResult = asana->/projects/[projectId]/sections.post(sectionBody); + if sectionCreationResult is error { + return error("error creating section: " + sectionCreationResult.message()); + } + } + + // Step 3: Create tasks within each section (simplified for brevity) + // In a complete implementation, you'd likely query the sections of the project first to get their IDs. + string[] tasks = ["Complete HR paperwork", "Setup work email", "Attend orientation session"]; + foreach string taskName in tasks { + asana:Tasks_body newTaskPayload = { + data: { + name: taskName, + projects: [projectId], + assignee_section: "" + } + }; + + asana:Inline_response_201_7|error taskCreationResponse = asana->/tasks.post(newTaskPayload); + if taskCreationResponse is error { + return error("error creating task: " + taskCreationResponse.message()); + } + } }