Add CLI tools for task CRUD and file attachments

This commit is contained in:
Max 2026-02-21 17:17:24 -06:00
parent 9453f88df4
commit 89e1cbcbb7
3 changed files with 256 additions and 0 deletions

79
scripts/attach-file.sh Executable file
View File

@ -0,0 +1,79 @@
#!/bin/bash
# Attach a file to a gantt board task
# Usage: ./attach-file.sh <task-id> <file-path>
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")
TASK_ID="$1"
FILE_PATH="$2"
if [[ -z "$TASK_ID" || -z "$FILE_PATH" ]]; then
echo "Usage: $0 <task-id> <file-path>"
exit 1
fi
if [[ ! -f "$FILE_PATH" ]]; then
echo "Error: File not found: $FILE_PATH"
exit 1
fi
FILENAME=$(basename "$FILE_PATH")
# Determine MIME type based on extension
EXTENSION="${FILENAME##*.}"
case "$EXTENSION" in
md|markdown) MIME_TYPE="text/markdown" ;;
txt) MIME_TYPE="text/plain" ;;
json) MIME_TYPE="application/json" ;;
pdf) MIME_TYPE="application/pdf" ;;
png) MIME_TYPE="image/png" ;;
jpg|jpeg) MIME_TYPE="image/jpeg" ;;
gif) MIME_TYPE="image/gif" ;;
*) MIME_TYPE="application/octet-stream" ;;
esac
# Convert file to base64 data URL
BASE64_CONTENT=$(base64 -i "$FILE_PATH" | tr -d '\n')
DATA_URL="data:$MIME_TYPE;base64,$BASE64_CONTENT"
# Generate attachment ID and timestamp
ATTACHMENT_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
FILE_SIZE=$(stat -f%z "$FILE_PATH")
# Get current task attachments
echo "Fetching current task..."
CURRENT_ATTACHMENTS=$(curl -s "$SUPABASE_URL/rest/v1/tasks?id=eq.$TASK_ID&select=attachments" "${HEADERS[@]}" | jq 'if type == "array" then .[0].attachments // [] else .attachments // [] end')
# Create new attachment object (field names must match UI expectations)
NEW_ATTACHMENT=$(jq -n \
--arg id "$ATTACHMENT_ID" \
--arg name "$FILENAME" \
--arg type "$MIME_TYPE" \
--argjson size "$FILE_SIZE" \
--arg dataUrl "$DATA_URL" \
--arg uploadedAt "$NOW" \
'{
id: $id,
name: $name,
type: $type,
size: $size,
dataUrl: $dataUrl,
uploadedAt: $uploadedAt
}')
# Merge with existing attachments
UPDATED_ATTACHMENTS=$(echo "$CURRENT_ATTACHMENTS" | jq --argjson new "$NEW_ATTACHMENT" '. + [$new]')
# Update task
echo "Attaching file to task..."
curl -s -X PATCH "$SUPABASE_URL/rest/v1/tasks?id=eq.$TASK_ID" \
"${HEADERS[@]}" \
-d "{\"attachments\": $UPDATED_ATTACHMENTS, \"updated_at\": \"$NOW\"}" | jq '.'
echo ""
echo "✅ Attached: $FILENAME"
echo " Size: $FILE_SIZE bytes"
echo " Type: $MIME_TYPE"

100
scripts/gantt-task-crud.sh Executable file
View File

@ -0,0 +1,100 @@
#!/bin/bash
# Gantt Board Task CRUD Operations
# Usage: ./task-crud.sh [create|read|update|delete|list] [args...]
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")
function list_tasks() {
local status_filter="${1:-}"
local url="$SUPABASE_URL/rest/v1/tasks?select=*&order=created_at.desc"
if [[ -n "$status_filter" ]]; then
url="$SUPABASE_URL/rest/v1/tasks?select=*&status=eq.$status_filter&order=created_at.desc"
fi
curl -s "$url" "${HEADERS[@]}" | jq '.'
}
function get_task() {
local task_id="$1"
curl -s "$SUPABASE_URL/rest/v1/tasks?id=eq.$task_id&select=*" "${HEADERS[@]}" | jq '.[0]'
}
function create_task() {
local title="$1"
local status="${2:-open}"
local priority="${3:-medium}"
local project_id="${4:-1}"
local assignee_id="${5:-9c29cc99-81a1-4e75-8dff-cd7cc5ceb5aa}"
local uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
local now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
curl -s -X POST "$SUPABASE_URL/rest/v1/tasks" \
"${HEADERS[@]}" \
-d "{
\"id\": \"$uuid\",
\"title\": \"$title\",
\"status\": \"$status\",
\"priority\": \"$priority\",
\"project_id\": \"$project_id\",
\"assignee_id\": \"$assignee_id\",
\"created_at\": \"$now\",
\"updated_at\": \"$now\",
\"comments\": [],
\"tags\": [],
\"attachments\": []
}" | jq '.'
echo "Created task: $uuid"
}
function update_task() {
local task_id="$1"
local field="$2"
local value="$3"
local now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
curl -s -X PATCH "$SUPABASE_URL/rest/v1/tasks?id=eq.$task_id" \
"${HEADERS[@]}" \
-d "{\"$field\": \"$value\", \"updated_at\": \"$now\"}" | jq '.'
echo "Updated task $task_id: $field = $value"
}
function delete_task() {
local task_id="$1"
curl -s -X DELETE "$SUPABASE_URL/rest/v1/tasks?id=eq.$task_id" "${HEADERS[@]}"
echo "Deleted task: $task_id"
}
# Main
case "$1" in
list)
list_tasks "$2"
;;
get)
get_task "$2"
;;
create)
create_task "$2" "$3" "$4" "$5" "$6"
;;
update)
update_task "$2" "$3" "$4"
;;
delete)
delete_task "$2"
;;
*)
echo "Usage: $0 [list|get|create|update|delete] [args...]"
echo ""
echo "Examples:"
echo " $0 list # List all tasks"
echo " $0 list open # List open tasks"
echo " $0 get <task-id> # Get specific task"
echo " $0 create \"Task title\" open medium # Create task"
echo " $0 update <task-id> status done # Update task status"
echo " $0 delete <task-id> # Delete task"
;;
esac

77
scripts/view-attachment.sh Executable file
View File

@ -0,0 +1,77 @@
#!/bin/bash
# View attachment from a gantt board task
# Usage: ./view-attachment.sh <task-id> [attachment-index]
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")
TASK_ID="$1"
ATTACHMENT_INDEX="${2:-0}"
if [[ -z "$TASK_ID" ]]; then
echo "Usage: $0 <task-id> [attachment-index]"
echo ""
echo "Examples:"
echo " $0 33ebc71e-7d40-456c-8f98-bb3578d2bb2b # View first attachment"
echo " $0 33ebc71e-7d40-456c-8f98-bb3578d2bb2b 0 # View first attachment (explicit)"
exit 1
fi
# Fetch task with attachments
echo "Fetching task attachments..."
TASK_DATA=$(curl -s "$SUPABASE_URL/rest/v1/tasks?id=eq.$TASK_ID&select=title,attachments" "${HEADERS[@]}")
# Extract attachments array
ATTACHMENTS=$(echo "$TASK_DATA" | jq -r 'if type == "array" then (.[0].attachments // []) else (.attachments // []) end')
ATTACHMENT_COUNT=$(echo "$ATTACHMENTS" | jq 'length')
if [[ "$ATTACHMENT_COUNT" -eq 0 ]]; then
echo "❌ No attachments found on this task."
exit 1
fi
echo ""
echo "Found $ATTACHMENT_COUNT attachment(s):"
echo "$ATTACHMENTS" | jq -r '.[] | " - \(.name) (\(.size) bytes, \(.type))"'
echo ""
# Get the requested attachment
ATTACHMENT=$(echo "$ATTACHMENTS" | jq -r ".[$ATTACHMENT_INDEX]")
if [[ "$ATTACHMENT" == "null" ]]; then
echo "❌ Attachment index $ATTACHMENT_INDEX not found."
exit 1
fi
FILENAME=$(echo "$ATTACHMENT" | jq -r '.name')
MIME_TYPE=$(echo "$ATTACHMENT" | jq -r '.type')
DATA_URL=$(echo "$ATTACHMENT" | jq -r '.url')
# Extract base64 content from data URL (remove data:mime/type;base64, prefix)
BASE64_CONTENT=$(echo "$DATA_URL" | sed 's/^data:[^;]*;base64,//')
# Decode to temp file
TEMP_FILE="/tmp/gantt-attachment-$(date +%s)-$FILENAME"
echo "$BASE64_CONTENT" | base64 -d > "$TEMP_FILE"
echo "📎 Attachment: $FILENAME"
echo "📋 Type: $MIME_TYPE"
echo "📊 Size: $(stat -f%z "$TEMP_FILE") bytes"
echo ""
echo "--- CONTENT ---"
echo ""
# Display based on type
if [[ "$MIME_TYPE" == text/* ]] || [[ "$FILENAME" == *.md ]] || [[ "$FILENAME" == *.txt ]]; then
cat "$TEMP_FILE"
else
echo "(Binary file - saved to: $TEMP_FILE)"
echo "Open with: open '$TEMP_FILE'"
fi
echo ""
echo "---------------"
# Clean up temp file
rm -f "$TEMP_FILE"