#!/bin/bash # Project CLI for Gantt Board (API passthrough) # Usage: ./project.sh [create|list|get|update|delete] [options] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=./lib/api_client.sh source "$SCRIPT_DIR/lib/api_client.sh" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}i${NC} $1"; } log_success() { echo -e "${GREEN}ok${NC} $1"; } log_warning() { echo -e "${YELLOW}warn${NC} $1"; } log_error() { echo -e "${RED}error${NC} $1"; } UUID_PATTERN='^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' check_dependencies() { if ! command -v jq >/dev/null 2>&1; then log_error "jq is required. Install with: brew install jq" exit 1 fi } show_usage() { cat << 'USAGE' Project CLI for Gantt Board USAGE: ./project.sh [COMMAND] [OPTIONS] COMMANDS: create Create a new project list List all projects get Get a specific project update Update a project delete Delete a project CREATE OPTIONS: --name "Name" Project name (required) --description "Description" Project description --color "#hexcolor" Project color LIST OPTIONS: --json Output as JSON UPDATE OPTIONS: --name "Name" --description "Description" --color "#hexcolor" USAGE } resolve_project_id() { local identifier="$1" if [[ "$identifier" =~ $UUID_PATTERN ]]; then echo "$identifier" return 0 fi local response response=$(api_call GET "/projects") local project_id project_id=$(echo "$response" | jq -r --arg q "$identifier" ' .projects | map(select((.name // "") | ascii_downcase | contains($q | ascii_downcase))) | .[0].id // empty ') if [[ -n "$project_id" ]]; then echo "$project_id" return 0 fi log_error "Project '$identifier' not found" return 1 } cmd_create() { local name="" local description="" local color="#3b82f6" while [[ $# -gt 0 ]]; do case "${1:-}" in --name) name="${2:-}"; shift 2 ;; --description) description="${2:-}"; shift 2 ;; --color) color="${2:-}"; shift 2 ;; *) shift ;; esac done if [[ -z "$name" ]]; then log_error "Name is required (use --name)" exit 1 fi local payload payload=$(jq -n --arg name "$name" --arg description "$description" --arg color "$color" ' { name: $name, description: (if $description == "" then null else $description end), color: $color } ') log_info "Creating project..." api_call POST "/projects" "$payload" | jq . } cmd_list() { local output_json=false while [[ $# -gt 0 ]]; do case "${1:-}" in --json) output_json=true; shift ;; *) shift ;; esac done local response response=$(api_call GET "/projects") if [[ "$output_json" == true ]]; then echo "$response" | jq '.projects' return fi local projects projects=$(echo "$response" | jq '.projects') local count count=$(echo "$projects" | jq 'length') log_success "Found $count project(s)" printf "%-36s %-25s %-30s\n" "ID" "NAME" "DESCRIPTION" printf "%-36s %-25s %-30s\n" "------------------------------------" "-------------------------" "------------------------------" echo "$projects" | jq -r '.[] | [.id, (.name // "" | tostring | .[0:23]), (.description // "" | tostring | .[0:28])] | @tsv' \ | while IFS=$'\t' read -r id name desc; do printf "%-36s %-25s %-30s\n" "$id" "$name" "$desc" done } cmd_get() { local identifier="${1:-}" if [[ -z "$identifier" ]]; then log_error "Project ID or name required" exit 1 fi local project_id project_id=$(resolve_project_id "$identifier") log_info "Fetching project $project_id..." api_call GET "/projects/$project_id" | jq '.project' } cmd_update() { local identifier="${1:-}" shift || true if [[ -z "$identifier" ]]; then log_error "Project ID or name required" exit 1 fi local project_id project_id=$(resolve_project_id "$identifier") local updates='{}' while [[ $# -gt 0 ]]; do case "${1:-}" in --name) updates=$(echo "$updates" | jq --arg v "${2:-}" '. + {name: $v}'); shift 2 ;; --description) updates=$(echo "$updates" | jq --arg v "${2:-}" '. + {description: $v}'); shift 2 ;; --color) updates=$(echo "$updates" | jq --arg v "${2:-}" '. + {color: $v}'); shift 2 ;; *) shift ;; esac done if [[ "$updates" == "{}" ]]; then log_warning "No update fields specified" exit 0 fi local payload payload=$(echo "$updates" | jq --arg id "$project_id" '. + {id: $id}') log_info "Updating project $project_id..." api_call PATCH "/projects" "$payload" | jq . } cmd_delete() { local identifier="${1:-}" if [[ -z "$identifier" ]]; then log_error "Project ID or name required" exit 1 fi local project_id project_id=$(resolve_project_id "$identifier") log_info "Deleting project $project_id..." api_call DELETE "/projects" "{\"id\": \"$project_id\"}" | jq . } check_dependencies COMMAND="${1:-}" shift || true case "$COMMAND" in create) cmd_create "$@" ;; list) cmd_list "$@" ;; get) cmd_get "$@" ;; update) cmd_update "$@" ;; delete) cmd_delete "$@" ;; help|--help|-h|"") show_usage ;; *) log_error "Unknown command: $COMMAND" show_usage exit 1 ;; esac