gantt-board/scripts/project.sh

377 lines
10 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# Project CLI for Gantt Board
# CRUD operations for projects
# Usage: ./project.sh [create|list|get|update|delete] [options]
set -e
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SUPABASE_URL="https://qnatchrjlpehiijwtreh.supabase.co"
SERVICE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFuYXRjaHJqbHBlaGlpand0cmVoIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc3MTY0MDQzNiwiZXhwIjoyMDg3MjE2NDM2fQ.rHoc3NfL59S4lejU4-ArSzox1krQkQG-TnfXb6sslm0"
HEADERS=(-H "apikey: $SERVICE_KEY" -H "Authorization: Bearer $SERVICE_KEY" -H "Content-Type: application/json")
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Helper Functions
log_info() { echo -e "${BLUE}${NC} $1"; }
log_success() { echo -e "${GREEN}${NC} $1"; }
log_warning() { echo -e "${YELLOW}${NC} $1"; }
log_error() { echo -e "${RED}${NC} $1"; }
# Check dependencies
check_dependencies() {
if ! command -v jq &> /dev/null; then
log_error "jq is required but not installed. Install with: brew install jq"
exit 1
fi
if ! command -v uuidgen &> /dev/null; then
log_error "uuidgen is required but not installed."
exit 1
fi
}
# Generate UUID
generate_uuid() {
uuidgen | tr '[:upper:]' '[:lower:]'
}
# Get current timestamp ISO format
get_timestamp() {
date -u +"%Y-%m-%dT%H:%M:%SZ"
}
# Show usage
show_usage() {
cat << EOF
Project CLI for Gantt Board
USAGE:
./project.sh [COMMAND] [OPTIONS]
COMMANDS:
create Create a new project
list List all projects
get <id> Get a specific project by ID or name
update <id> Update a project
delete <id> Delete a project
CREATE OPTIONS:
--name "Name" Project name (required)
--description "Description" Project description
--color "#hexcolor" Project color for UI
LIST OPTIONS:
--json Output as JSON
UPDATE OPTIONS:
--name "Name"
--description "Description"
--color "#hexcolor"
EXAMPLES:
# Create project
./project.sh create --name "Web Projects" --description "All web development work"
# List all active projects
./project.sh list
# Get project by ID
./project.sh get a1b2c3d4-0001-0000-0000-000000000001
# Update project
./project.sh update a1b2c3d4-0001-0000-0000-000000000001 --status archived
# Delete project
./project.sh delete a1b2c3d4-0001-0000-0000-000000000001
EOF
}
# Resolve project name to ID
resolve_project_id() {
local identifier="$1"
# Check if it's already a UUID
if [[ "$identifier" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]]; then
echo "$identifier"
return 0
fi
# Search by name (case-insensitive)
local project_id
project_id=$(curl -s "${SUPABASE_URL}/rest/v1/projects?name=ilike.*${identifier}*&select=id" \
"${HEADERS[@]}" | jq -r '.[0].id // empty')
if [[ -n "$project_id" ]]; then
echo "$project_id"
return 0
fi
# Try exact match
local encoded_name
encoded_name=$(printf '%s' "$identifier" | jq -sRr @uri)
project_id=$(curl -s "${SUPABASE_URL}/rest/v1/projects?name=eq.${encoded_name}&select=id" \
"${HEADERS[@]}" | jq -r '.[0].id // empty')
if [[ -n "$project_id" ]]; then
echo "$project_id"
return 0
fi
log_error "Project '$identifier' not found"
return 1
}
# Create command
cmd_create() {
local name=""
local description=""
local color="#3b82f6"
# Parse arguments
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
# Validate required fields
if [[ -z "$name" ]]; then
log_error "Name is required (use --name)"
exit 1
fi
# Generate project data
local project_id
project_id=$(generate_uuid)
local timestamp
timestamp=$(get_timestamp)
# Build JSON payload
local json_payload
json_payload=$(jq -n \
--arg id "$project_id" \
--arg name "$name" \
--arg color "$color" \
--arg created_at "$timestamp" \
'{
id: $id,
name: $name,
color: $color,
created_at: $created_at
}')
# Add optional fields
if [[ -n "$description" ]]; then
json_payload=$(echo "$json_payload" | jq --arg v "$description" '. + {description: $v}')
fi
# Create project
log_info "Creating project..."
local response
response=$(curl -s -X POST "${SUPABASE_URL}/rest/v1/projects" \
"${HEADERS[@]}" \
-d "$json_payload")
# Supabase returns empty on success, or error JSON on failure
if [[ -z "$response" ]]; then
log_success "Project created: $project_id"
elif [[ "$response" == *"error"* ]] || [[ "$response" == *""*"code"* ]]; then
log_error "Failed to create project"
echo "$response" | jq . 2>/dev/null || echo "$response"
exit 1
else
log_success "Project created: $project_id"
echo "$response" | jq . 2>/dev/null || echo "$response"
fi
}
# List command
cmd_list() {
local output_json=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case "${1:-}" in
--json) output_json=true; shift ;;
*) shift ;;
esac
done
# Build query
local query="${SUPABASE_URL}/rest/v1/projects?select=*&order=created_at.desc"
log_info "Fetching projects..."
local response
response=$(curl -s "$query" "${HEADERS[@]}")
if [[ "$output_json" == true ]]; then
echo "$response" | jq .
else
# Table output
local count
count=$(echo "$response" | jq 'length')
log_success "Found $count project(s)"
# Print header
printf "%-36s %-25s %-30s\n" "ID" "NAME" "DESCRIPTION"
printf "%-36s %-25s %-30s\n" "------------------------------------" "-------------------------" "------------------------------"
# Print rows
echo "$response" | 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
fi
}
# Get command
cmd_get() {
local identifier="$1"
if [[ -z "$identifier" ]]; then
log_error "Project ID or name required. Usage: ./project.sh get <id-or-name>"
exit 1
fi
local project_id
project_id=$(resolve_project_id "$identifier")
log_info "Fetching project $project_id..."
local response
response=$(curl -s "${SUPABASE_URL}/rest/v1/projects?id=eq.${project_id}&select=*" \
"${HEADERS[@]}")
local project
project=$(echo "$response" | jq '.[0] // empty')
if [[ -n "$project" && "$project" != "{}" && "$project" != "null" ]]; then
echo "$project" | jq .
else
log_error "Project not found: $identifier"
exit 1
fi
}
# Update command
cmd_update() {
local identifier="$1"
shift
if [[ -z "$identifier" ]]; then
log_error "Project ID or name required. Usage: ./project.sh update <id-or-name> [options]"
exit 1
fi
local project_id
project_id=$(resolve_project_id "$identifier")
# Build update payload
local update_fields="{}"
while [[ $# -gt 0 ]]; do
case "${1:-}" in
--name) update_fields=$(echo "$update_fields" | jq --arg v "$2" '. + {name: $v}'); shift 2 ;;
--description) update_fields=$(echo "$update_fields" | jq --arg v "$2" '. + {description: $v}'); shift 2 ;;
--color) update_fields=$(echo "$update_fields" | jq --arg v "$2" '. + {color: $v}'); shift 2 ;;
*) shift ;;
esac
done
# Check if we have anything to update
if [[ "$update_fields" == "{}" ]]; then
log_warning "No update fields specified"
exit 0
fi
# Add updated_at timestamp
local timestamp
timestamp=$(get_timestamp)
update_fields=$(echo "$update_fields" | jq --arg t "$timestamp" '. + {updated_at: $t}')
log_info "Updating project $project_id..."
local response
response=$(curl -s -X PATCH "${SUPABASE_URL}/rest/v1/projects?id=eq.${project_id}" \
"${HEADERS[@]}" \
-d "$update_fields")
if [[ -z "$response" || "$response" == "[]" || ! "$response" == *"error"* ]]; then
log_success "Project updated: $project_id"
else
log_error "Failed to update project"
echo "$response" | jq . 2>/dev/null || echo "$response"
exit 1
fi
}
# Delete command
cmd_delete() {
local identifier="$1"
if [[ -z "$identifier" ]]; then
log_error "Project ID or name required. Usage: ./project.sh delete <id-or-name>"
exit 1
fi
local project_id
project_id=$(resolve_project_id "$identifier")
log_info "Deleting project $project_id..."
local response
response=$(curl -s -X DELETE "${SUPABASE_URL}/rest/v1/projects?id=eq.${project_id}" \
"${HEADERS[@]}")
if [[ -z "$response" || "$response" == "[]" ]]; then
log_success "Project deleted: $project_id"
else
log_error "Failed to delete project"
echo "$response" | jq . 2>/dev/null || echo "$response"
exit 1
fi
}
# Main execution
check_dependencies
# Parse command
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
;;
"")
show_usage
;;
*)
log_error "Unknown command: $COMMAND"
show_usage
exit 1
;;
esac