diff --git a/db/migrations/20251013051821_task_log/down.sql b/db/migrations/20251013051821_task_log/down.sql new file mode 100644 index 00000000..0fe9c8c9 --- /dev/null +++ b/db/migrations/20251013051821_task_log/down.sql @@ -0,0 +1,3 @@ +ALTER TABLE public.tasks +DROP CONSTRAINT task_log_array, +DROP COLUMN log; diff --git a/db/migrations/20251013051821_task_log/seed.sql b/db/migrations/20251013051821_task_log/seed.sql new file mode 100644 index 00000000..20b12a93 --- /dev/null +++ b/db/migrations/20251013051821_task_log/seed.sql @@ -0,0 +1,3 @@ +UPDATE tasks +SET log = '[{"cwd":"/tmp/automa/tasks/13","type":"system","model":"claude-sonnet-4-20250514","tools":["Task","Bash","Glob","Grep","LS","exit_plan_mode","Read","Edit","MultiEdit","Write","NotebookRead","NotebookEdit","WebFetch","TodoRead","TodoWrite","WebSearch"],"subtype":"init","timestamp":1760336733.008,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","mcp_servers":[],"apiKeySource":"ANTHROPIC_API_KEY","permissionMode":"bypassPermissions"},{"type":"assistant","message":{"id":"msg_019ynBuiz23vZY91tx14VtjW","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":4,"service_tier":"standard","output_tokens":6,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":3484},"cache_read_input_tokens":9997,"cache_creation_input_tokens":3484},"content":[{"text":"I''ll help you set the default repo & bot to the first option during task creation in `TaskCreate.tsx`. Let me start by examining the file to understand the current implementation.","type":"text"}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336736.498,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_019ynBuiz23vZY91tx14VtjW","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":4,"service_tier":"standard","output_tokens":6,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":3484},"cache_read_input_tokens":9997,"cache_creation_input_tokens":3484},"content":[{"id":"toolu_01TUojrA6XpCRnGQ5MuURZ1F","name":"TodoWrite","type":"tool_use","input":{"todos":[{"id":"1","status":"pending","content":"Examine TaskCreate.tsx to understand current implementation","priority":"high"},{"id":"2","status":"pending","content":"Add useEffect to set default repo & bot to first option","priority":"high"},{"id":"3","status":"pending","content":"Ensure disabled repository options are ignored","priority":"high"}]}}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336738.146,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable","tool_use_id":"toolu_01TUojrA6XpCRnGQ5MuURZ1F"}]},"timestamp":1760336738.181,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_01NevP3or2SSPrnReEnVk9XX","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":31,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":463},"cache_read_input_tokens":13481,"cache_creation_input_tokens":463},"content":[{"id":"toolu_01R5ssUQDiBfjSKfCw7DmzTR","name":"Glob","type":"tool_use","input":{"pattern":"**/TaskCreate.tsx"}}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336740.898,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"/tmp/automa/tasks/13/packages/console/src/tasks/views/TaskCreate/TaskCreate.tsx","tool_use_id":"toolu_01R5ssUQDiBfjSKfCw7DmzTR"}]},"timestamp":1760336740.916,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_01FBXhYD6WmGEyha1NEkJpMA","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":25,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":95},"cache_read_input_tokens":13944,"cache_creation_input_tokens":95},"content":[{"id":"toolu_014dXZ4ouG8nCccY7yZ5QbZC","name":"TodoWrite","type":"tool_use","input":{"todos":[{"id":"1","status":"in_progress","content":"Examine TaskCreate.tsx to understand current implementation","priority":"high"},{"id":"2","status":"pending","content":"Add useEffect to set default repo & bot to first option","priority":"high"},{"id":"3","status":"pending","content":"Ensure disabled repository options are ignored","priority":"high"}]}}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336744.511,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable","tool_use_id":"toolu_014dXZ4ouG8nCccY7yZ5QbZC"}]},"timestamp":1760336744.552,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_01AjUyaPzrZtYnZFK5ZCEnKg","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":25,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":197},"cache_read_input_tokens":14039,"cache_creation_input_tokens":197},"content":[{"id":"toolu_01C48WKA94n9KsqSgJWv9JYQ","name":"Read","type":"tool_use","input":{"file_path":"/tmp/automa/tasks/13/packages/console/src/tasks/views/TaskCreate/TaskCreate.tsx"}}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336747.585,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":" 1→import React, { useEffect, useMemo } from ''react'';\n 2→import { Navigate, useLocation } from ''react-router-dom'';\n 3→import { useMutation, useQuery } from ''@apollo/client'';\n 4→import { zodResolver } from ''@hookform/resolvers/zod'';\n 5→import { Plugs } from ''@phosphor-icons/react'';\n 6→import { Controller, SubmitHandler, useForm } from ''react-hook-form'';\n 7→\n 8→import { taskCreateSchema } from ''@automa/common'';\n 9→\n 10→import { getFragment } from ''gql'';\n 11→import { TaskCreateInput } from ''gql/graphql'';\n 12→import { Avatar, Button, Flex, Input, toast, Typography } from ''shared'';\n 13→import ComboBox from ''shared/components/ComboBox'';\n 14→import InputEditor from ''shared/components/InputEditor'';\n 15→\n 16→import { TASK_FRAGMENT } from ''tasks'';\n 17→\n 18→import { TaskCreateProps } from ''./types'';\n 19→\n 20→import {\n 21→ BOT_INSTALLATIONS_AS_OPTIONS_QUERY,\n 22→ REPOSITORIES_AS_OPTIONS_QUERY,\n 23→ TASK_CREATE_MUTATION,\n 24→} from ''./TaskCreate.queries'';\n 25→\n 26→const TaskCreate: React.FC = ({ org }) => {\n 27→ const location = useLocation();\n 28→\n 29→ const {\n 30→ register,\n 31→ control,\n 32→ handleSubmit,\n 33→ formState: { errors },\n 34→ setValue,\n 35→ } = useForm({\n 36→ resolver: zodResolver(taskCreateSchema),\n 37→ });\n 38→\n 39→ const searchParams = useMemo(\n 40→ () => new URLSearchParams(location.search),\n 41→ [location.search],\n 42→ );\n 43→\n 44→ // Load bot installations\n 45→ const { data: botInstallationsData, loading: botInstallationsLoading } =\n 46→ useQuery(BOT_INSTALLATIONS_AS_OPTIONS_QUERY, {\n 47→ variables: {\n 48→ org_id: org.id,\n 49→ },\n 50→ });\n 51→\n 52→ const botInstallations = useMemo(\n 53→ () =>\n 54→ (botInstallationsData?.botInstallations ?? []).map((botInstallation) => ({\n 55→ ...botInstallation,\n 56→ value: `${botInstallation.bot.org.name}/${botInstallation.bot.name}`,\n 57→ })),\n 58→ [botInstallationsData],\n 59→ );\n 60→\n 61→ useEffect(() => {\n 62→ const botInstallationId = parseInt(searchParams.get(''bot'') ?? ''0'', 10);\n 63→\n 64→ if (!botInstallationId) return;\n 65→\n 66→ const botInstallation = botInstallations.find(\n 67→ (installation) => installation.id === botInstallationId,\n 68→ );\n 69→\n 70→ if (!botInstallation) return;\n 71→\n 72→ setValue(''bot_installation_id'', botInstallation.id);\n 73→ }, [searchParams, botInstallations, setValue]);\n 74→\n 75→ // Load repositories\n 76→ const { data: repositoriesData, loading: repositoriesLoading } = useQuery(\n 77→ REPOSITORIES_AS_OPTIONS_QUERY,\n 78→ {\n 79→ variables: {\n 80→ org_id: org.id,\n 81→ },\n 82→ },\n 83→ );\n 84→\n 85→ const repositories = useMemo(\n 86→ () =>\n 87→ (repositoriesData?.repos ?? []).map((repo) => ({\n 88→ ...repo,\n 89→ disabled: !repo.has_installation,\n 90→ value: repo.name,\n 91→ })),\n 92→ [repositoriesData],\n 93→ );\n 94→\n 95→ useEffect(() => {\n 96→ const repoId = parseInt(searchParams.get(''repo'') ?? ''0'', 10);\n 97→\n 98→ if (!repoId) return;\n 99→\n 100→ const repo = repositories.find((repo) => repo.id === repoId);\n 101→\n 102→ if (!repo) return;\n 103→\n 104→ setValue(''repo_id'', repo.id);\n 105→ }, [searchParams, repositories, setValue]);\n 106→\n 107→ // TODO: Handle error\n 108→ const [taskCreate, { data, loading, error }] = useMutation(\n 109→ TASK_CREATE_MUTATION,\n 110→ {\n 111→ update(cache, { data }) {\n 112→ if (!data) return;\n 113→\n 114→ cache.modify({\n 115→ fields: {\n 116→ tasks(existing = {}, details) {\n 117→ if (!details.storeFieldName.includes(`\"org_id\":${org.id}`))\n 118→ return existing;\n 119→\n 120→ const newTaskRef = cache.writeFragment({\n 121→ data: getFragment(TASK_FRAGMENT, data.taskCreate),\n 122→ fragment: TASK_FRAGMENT,\n 123→ fragmentName: ''Task'',\n 124→ });\n 125→\n 126→ return [newTaskRef, ...existing];\n 127→ },\n 128→ },\n 129→ });\n 130→ },\n 131→ },\n 132→ );\n 133→\n 134→ const onSubmit: SubmitHandler = async (data) => {\n 135→ await taskCreate({\n 136→ variables: {\n 137→ org_id: org.id,\n 138→ input: data,\n 139→ },\n 140→ });\n 141→\n 142→ toast({\n 143→ variant: ''success'',\n 144→ title: ''Task created'',\n 145→ });\n 146→ };\n 147→\n 148→ if (!loading && data) {\n 149→ const task = getFragment(TASK_FRAGMENT, data.taskCreate);\n 150→\n 151→ return ;\n 152→ }\n 153→\n 154→ return (\n 155→ \n 156→ \n 157→ Create task\n 158→ \n 159→
\n 160→ \n 161→ \n 170→ {\n 174→ return (\n 175→ \n 187→ );\n 188→ }}\n 189→ />\n 190→ (\n 194→ (\n 209→ \n 210→ \n 218→ {value}\n 219→ \n 220→ )}\n 221→ />\n 222→ )}\n 223→ />\n 224→ (\n 228→ (\n 243→ \n 248→ {value}\n 249→ {disabled && }\n 250→ \n 251→ )}\n 252→ />\n 253→ )}\n 254→ />\n 255→ \n 256→ \n 259→
\n 260→
\n 261→ );\n 262→};\n 263→\n 264→export default TaskCreate;\n 265→","tool_use_id":"toolu_01C48WKA94n9KsqSgJWv9JYQ"}]},"timestamp":1760336747.622,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_015JRcqP1VUszvGjKD9cknxL","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":33,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":2961},"cache_read_input_tokens":14236,"cache_creation_input_tokens":2961},"content":[{"id":"toolu_01EBm1iwqCieboEBHMcLigsK","name":"TodoWrite","type":"tool_use","input":{"todos":[{"id":"1","status":"completed","content":"Examine TaskCreate.tsx to understand current implementation","priority":"high"},{"id":"2","status":"in_progress","content":"Add useEffect to set default repo & bot to first option","priority":"high"},{"id":"3","status":"pending","content":"Ensure disabled repository options are ignored","priority":"high"}]}}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336751.091,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable","tool_use_id":"toolu_01EBm1iwqCieboEBHMcLigsK"}]},"timestamp":1760336751.128,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_01KATpwCPLXPhBvzoHHpy94p","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":4,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":197},"cache_read_input_tokens":17197,"cache_creation_input_tokens":197},"content":[{"text":"Now I''ll add the `useEffect` to set default values for both repo and bot to the first available option, ensuring we ignore disabled repository options:","type":"text"}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336754.442,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_01KATpwCPLXPhBvzoHHpy94p","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":4,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":197},"cache_read_input_tokens":17197,"cache_creation_input_tokens":197},"content":[{"id":"toolu_01HWx3gdd3tu8MzfzSszWiZj","name":"Edit","type":"tool_use","input":{"file_path":"/tmp/automa/tasks/13/packages/console/src/tasks/views/TaskCreate/TaskCreate.tsx","new_string":" useEffect(() => {\n const repoId = parseInt(searchParams.get(''repo'') ?? ''0'', 10);\n\n if (!repoId) return;\n\n const repo = repositories.find((repo) => repo.id === repoId);\n\n if (!repo) return;\n\n setValue(''repo_id'', repo.id);\n }, [searchParams, repositories, setValue]);\n\n // Set default repo and bot to first option if not already selected from URL\n useEffect(() => {\n const hasRepoParam = searchParams.has(''repo'');\n const hasBotParam = searchParams.has(''bot'');\n\n if (!hasRepoParam && repositories.length > 0) {\n const firstEnabledRepo = repositories.find((repo) => !repo.disabled);\n if (firstEnabledRepo) {\n setValue(''repo_id'', firstEnabledRepo.id);\n }\n }\n\n if (!hasBotParam && botInstallations.length > 0) {\n setValue(''bot_installation_id'', botInstallations[0].id);\n }\n }, [searchParams, repositories, botInstallations, setValue]);","old_string":" useEffect(() => {\n const repoId = parseInt(searchParams.get(''repo'') ?? ''0'', 10);\n\n if (!repoId) return;\n\n const repo = repositories.find((repo) => repo.id === repoId);\n\n if (!repo) return;\n\n setValue(''repo_id'', repo.id);\n }, [searchParams, repositories, setValue]);"}}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336758.705,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"The file /tmp/automa/tasks/13/packages/console/src/tasks/views/TaskCreate/TaskCreate.tsx has been updated. Here''s the result of running `cat -n` on a snippet of the edited file:\n 91→ })),\n 92→ [repositoriesData],\n 93→ );\n 94→\n 95→ useEffect(() => {\n 96→ const repoId = parseInt(searchParams.get(''repo'') ?? ''0'', 10);\n 97→\n 98→ if (!repoId) return;\n 99→\n 100→ const repo = repositories.find((repo) => repo.id === repoId);\n 101→\n 102→ if (!repo) return;\n 103→\n 104→ setValue(''repo_id'', repo.id);\n 105→ }, [searchParams, repositories, setValue]);\n 106→\n 107→ // Set default repo and bot to first option if not already selected from URL\n 108→ useEffect(() => {\n 109→ const hasRepoParam = searchParams.has(''repo'');\n 110→ const hasBotParam = searchParams.has(''bot'');\n 111→\n 112→ if (!hasRepoParam && repositories.length > 0) {\n 113→ const firstEnabledRepo = repositories.find((repo) => !repo.disabled);\n 114→ if (firstEnabledRepo) {\n 115→ setValue(''repo_id'', firstEnabledRepo.id);\n 116→ }\n 117→ }\n 118→\n 119→ if (!hasBotParam && botInstallations.length > 0) {\n 120→ setValue(''bot_installation_id'', botInstallations[0].id);\n 121→ }\n 122→ }, [searchParams, repositories, botInstallations, setValue]);\n 123→\n 124→ // TODO: Handle error\n 125→ const [taskCreate, { data, loading, error }] = useMutation(\n 126→ TASK_CREATE_MUTATION,","tool_use_id":"toolu_01HWx3gdd3tu8MzfzSszWiZj"}]},"timestamp":1760336758.742,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_01RmbRi686CvW3Ywfoc61i7b","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":25,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":1017},"cache_read_input_tokens":17394,"cache_creation_input_tokens":1017},"content":[{"id":"toolu_01Qio2gpUedxrn4te4YL4ts3","name":"TodoWrite","type":"tool_use","input":{"todos":[{"id":"1","status":"completed","content":"Examine TaskCreate.tsx to understand current implementation","priority":"high"},{"id":"2","status":"completed","content":"Add useEffect to set default repo & bot to first option","priority":"high"},{"id":"3","status":"completed","content":"Ensure disabled repository options are ignored","priority":"high"}]}}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336762.314,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable","tool_use_id":"toolu_01Qio2gpUedxrn4te4YL4ts3"}]},"timestamp":1760336762.336,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"assistant","message":{"id":"msg_01ACRPJKrNvK95GZKeqE2Vx4","role":"assistant","type":"message","model":"claude-sonnet-4-20250514","usage":{"input_tokens":7,"service_tier":"standard","output_tokens":1,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":195},"cache_read_input_tokens":18411,"cache_creation_input_tokens":195},"content":[{"text":"I''ve successfully implemented the requested feature in `TaskCreate.tsx:107-122`. The new `useEffect` hook:\n\n1. Sets the default repository to the first enabled option (ignoring disabled ones) when no repo URL parameter exists\n2. Sets the default bot to the first available option when no bot URL parameter exists \n3. Uses `setValue` without `getValues` as requested\n4. Only applies defaults if options aren''t already selected via URL parameters","type":"text"}],"stop_reason":null,"stop_sequence":null},"timestamp":1760336767.176,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","parent_tool_use_id":null},{"type":"result","usage":{"input_tokens":106,"output_tokens":1594,"server_tool_use":{"web_search_requests":0},"cache_read_input_tokens":237398,"cache_creation_input_tokens":17218},"result":"I''ve successfully implemented the requested feature in `TaskCreate.tsx:107-122`. The new `useEffect` hook:\n\n1. Sets the default repository to the first enabled option (ignoring disabled ones) when no repo URL parameter exists\n2. Sets the default bot to the first available option when no bot URL parameter exists \n3. Uses `setValue` without `getValues` as requested\n4. Only applies defaults if options aren''t already selected via URL parameters","subtype":"success","is_error":false,"num_turns":17,"timestamp":1760336767.22,"session_id":"a8180f29-dfc0-47af-b846-f0d89fc4a72a","duration_ms":34251,"total_cost_usd":0.1603693,"duration_api_ms":35887}]' +WHERE id = 2; diff --git a/db/migrations/20251013051821_task_log/up.sql b/db/migrations/20251013051821_task_log/up.sql new file mode 100644 index 00000000..b8ec5a4c --- /dev/null +++ b/db/migrations/20251013051821_task_log/up.sql @@ -0,0 +1,3 @@ +ALTER TABLE public.tasks +ADD COLUMN log JSONB NOT NULL DEFAULT '[]', +ADD CONSTRAINT task_log_array CHECK (jsonb_typeof(log) = 'array'); diff --git a/db/schema.sql b/db/schema.sql index 887bb979..9c569258 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -402,7 +402,9 @@ CREATE TABLE public.tasks ( proposal_token character varying(255), proposal_base_commit character varying(40), created_at timestamp without time zone DEFAULT now() NOT NULL, - cost_in_cents integer + cost_in_cents integer, + log jsonb DEFAULT '[]'::jsonb NOT NULL, + CONSTRAINT task_log_array CHECK ((jsonb_typeof(log) = 'array'::text)) ); diff --git a/packages/api/src/graphql/schema/tasks.graphql b/packages/api/src/graphql/schema/tasks.graphql index 26001959..f4e2729e 100644 --- a/packages/api/src/graphql/schema/tasks.graphql +++ b/packages/api/src/graphql/schema/tasks.graphql @@ -23,6 +23,7 @@ type Task { state: TaskState! created_at: DateTime! cost_in_cents: Int + log: JSON! org: Org! diff --git a/packages/api/src/routes/code/download.ts b/packages/api/src/routes/bot/code/download.ts similarity index 97% rename from packages/api/src/routes/code/download.ts rename to packages/api/src/routes/bot/code/download.ts index 7748930d..ef524581 100644 --- a/packages/api/src/routes/code/download.ts +++ b/packages/api/src/routes/bot/code/download.ts @@ -8,9 +8,9 @@ import { c as createTar } from 'tar'; import z from 'zod'; import { $ } from 'zx'; -import { caller } from '../../clients/github'; +import { getBot, getRepo, getTask } from '../utils'; -import { getBot, getRepo, getTask } from './utils'; +import { caller } from '../../../clients/github'; export default async function (app: FastifyInstance) { app.withTypeProvider().post( diff --git a/packages/api/src/routes/code/propose.ts b/packages/api/src/routes/bot/code/propose.ts similarity index 98% rename from packages/api/src/routes/code/propose.ts rename to packages/api/src/routes/bot/code/propose.ts index 2985ab60..e1a13078 100644 --- a/packages/api/src/routes/code/propose.ts +++ b/packages/api/src/routes/bot/code/propose.ts @@ -7,12 +7,12 @@ import { $ } from 'zx'; import { integration, task_item, task_state } from '@automa/prisma'; -import { env } from '../../env'; +import { env } from '../../../env'; -import { caller } from '../../clients/github'; -import { taskUpdateState } from '../../db'; +import { getBot, getRepo, getTask } from '../utils'; -import { getBot, getRepo, getTask } from './utils'; +import { caller } from '../../../clients/github'; +import { taskUpdateState } from '../../../db'; type PullRequest = { id: number; diff --git a/packages/api/src/routes/bot/task/log.ts b/packages/api/src/routes/bot/task/log.ts new file mode 100644 index 00000000..efb780f5 --- /dev/null +++ b/packages/api/src/routes/bot/task/log.ts @@ -0,0 +1,68 @@ +import { FastifyInstance } from 'fastify'; +import { ZodTypeProvider } from 'fastify-type-provider-zod'; +import z from 'zod'; + +export default async function (app: FastifyInstance) { + app.withTypeProvider().post( + '/log', + { + schema: { + body: z.object({ + events: z.array( + z.object({ + task: z.object({ + id: z.number(), + token: z.string(), + }), + event: z + .object({ + type: z.string(), + timestamp: z.number(), + }) + .passthrough(), + }), + ), + }), + }, + }, + async (request, reply) => { + const { events } = request.body; + + if (!events || events.length === 0) { + return reply.code(204).send(); + } + + const payloadJson = JSON.stringify(events); + + await app.prisma.$executeRaw` + WITH payload AS ( + SELECT + (e->'task'->>'id')::int AS task_id, + (e->'task'->>'token') AS token, + (e->'event')::jsonb AS event + FROM jsonb_array_elements(${payloadJson}::jsonb) AS e + ), + valid AS ( + SELECT p.task_id, p.event + FROM payload p + JOIN public.tasks t + ON t.id = p.task_id + AND t.token = p.token + ), + grouped AS ( + SELECT + task_id, + jsonb_agg(event ORDER BY (event->>'timestamp')::numeric) AS events + FROM valid + GROUP BY task_id + ) + UPDATE public.tasks t + SET log = t.log || g.events + FROM grouped g + WHERE t.id = g.task_id; + `; + + return reply.send(); + }, + ); +} diff --git a/packages/api/src/routes/code/utils.ts b/packages/api/src/routes/bot/utils.ts similarity index 100% rename from packages/api/src/routes/code/utils.ts rename to packages/api/src/routes/bot/utils.ts diff --git a/packages/api/test/routes/code/download.test.ts b/packages/api/test/routes/bot/code/download.test.ts similarity index 99% rename from packages/api/test/routes/code/download.test.ts rename to packages/api/test/routes/bot/code/download.test.ts index 3bc19df5..1ca051b6 100644 --- a/packages/api/test/routes/code/download.test.ts +++ b/packages/api/test/routes/bot/code/download.test.ts @@ -9,10 +9,10 @@ import * as tar from 'tar'; import { bots, orgs, repos, tasks } from '@automa/prisma'; -import { quibbleSandbox, zxCmdArgsStub, zxCmdStub } from '../../mocks'; -import { call, seedBots, seedOrgs, seedRepos, server } from '../../utils'; +import { quibbleSandbox, zxCmdArgsStub, zxCmdStub } from '../../../mocks'; +import { call, seedBots, seedOrgs, seedRepos, server } from '../../../utils'; -suite('code/download', () => { +suite('bot/code/download', () => { let app: FastifyInstance, response: LightMyRequestResponse; let org: orgs, bot: bots, repo: repos, task: tasks; let sandbox: SinonSandbox, postStub: SinonStub, tarCreateStub: SinonStub; @@ -817,7 +817,7 @@ const download = async ( app: FastifyInstance, task: Pick, ) => - call(app, '/code/download', { + call(app, '/bot/code/download', { method: 'POST', payload: { task, diff --git a/packages/api/test/routes/code/propose.test.ts b/packages/api/test/routes/bot/code/propose.test.ts similarity index 99% rename from packages/api/test/routes/code/propose.test.ts rename to packages/api/test/routes/bot/code/propose.test.ts index f9b068eb..ba23b0d0 100644 --- a/packages/api/test/routes/code/propose.test.ts +++ b/packages/api/test/routes/bot/code/propose.test.ts @@ -7,8 +7,8 @@ import axios from 'axios'; import { bots, orgs, repos, tasks } from '@automa/prisma'; -import { quibbleSandbox, zxCmdArgsStub, zxCmdStub } from '../../mocks'; -import { call, seedBots, seedOrgs, seedRepos, server } from '../../utils'; +import { quibbleSandbox, zxCmdArgsStub, zxCmdStub } from '../../../mocks'; +import { call, seedBots, seedOrgs, seedRepos, server } from '../../../utils'; const diff = [ 'diff --git a/file.txt b/file.txt', @@ -20,7 +20,7 @@ const diff = [ '+new', ].join('\n'); -suite('code/propose', () => { +suite('bot/code/propose', () => { let app: FastifyInstance, response: LightMyRequestResponse; let org: orgs, bot: bots, repo: repos, task: tasks; let sandbox: SinonSandbox, postStub: SinonStub, getStub: SinonStub; @@ -113,7 +113,7 @@ suite('code/propose', () => { suite('with empty body', () => { setup(async () => { - response = await call(app, '/code/propose', { + response = await call(app, '/bot/code/propose', { method: 'POST', payload: {}, }); @@ -318,7 +318,7 @@ suite('code/propose', () => { suite('with missing proposal token', () => { setup(async () => { - response = await call(app, '/code/propose', { + response = await call(app, '/bot/code/propose', { method: 'POST', payload: { task: { @@ -364,7 +364,7 @@ suite('code/propose', () => { suite('with null proposal token', () => { setup(async () => { - response = await call(app, '/code/propose', { + response = await call(app, '/bot/code/propose', { method: 'POST', payload: { task: { @@ -411,7 +411,7 @@ suite('code/propose', () => { suite('with missing proposal diff', () => { setup(async () => { - response = await call(app, '/code/propose', { + response = await call(app, '/bot/code/propose', { method: 'POST', payload: { task: { @@ -457,7 +457,7 @@ suite('code/propose', () => { suite('with null proposal diff', () => { setup(async () => { - response = await call(app, '/code/propose', { + response = await call(app, '/bot/code/propose', { method: 'POST', payload: { task: { @@ -2533,7 +2533,7 @@ const propose = async ( }, metadata?: Record, ) => - call(app, '/code/propose', { + call(app, '/bot/code/propose', { method: 'POST', payload: { task, diff --git a/packages/common/src/graphql.ts b/packages/common/src/graphql.ts index fa35cffc..a5027318 100644 --- a/packages/common/src/graphql.ts +++ b/packages/common/src/graphql.ts @@ -342,6 +342,7 @@ export type Task = { id: Scalars['Int']['output']; is_scheduled: Scalars['Boolean']['output']; items: Array; + log: Scalars['JSON']['output']; org: Org; state: TaskState; title: Scalars['String']['output']; @@ -763,6 +764,7 @@ export type TaskResolvers; is_scheduled?: Resolver; items?: Resolver, ParentType, ContextType>; + log?: Resolver; org?: Resolver; state?: Resolver; title?: Resolver; diff --git a/packages/console/src/gql/gql.ts b/packages/console/src/gql/gql.ts index a94e37ad..a5e5f88a 100644 --- a/packages/console/src/gql/gql.ts +++ b/packages/console/src/gql/gql.ts @@ -39,7 +39,7 @@ const documents = { "\n query Repos($org_id: Int!) {\n repos(org_id: $org_id) {\n id\n ...Repo\n }\n }\n": types.ReposDocument, "\n fragment Task on Task {\n id\n title\n is_scheduled\n state\n created_at\n items {\n type\n ...TaskItem\n }\n }\n": types.TaskFragmentDoc, "\n fragment TaskItem on TaskItem {\n id\n type\n data\n created_at\n actor_user {\n ...UserAvatar\n }\n bot {\n id\n name\n short_description\n image_url\n org {\n id\n name\n }\n }\n repo {\n id\n name\n org {\n id\n provider_type\n provider_name\n }\n }\n activity {\n id\n type\n from_state\n to_state\n }\n }\n": types.TaskItemFragmentDoc, - "\n query Task($org_id: Int!, $id: Int!) {\n task(org_id: $org_id, id: $id) {\n id\n ...Task\n }\n }\n": types.TaskDocument, + "\n query Task($org_id: Int!, $id: Int!) {\n task(org_id: $org_id, id: $id) {\n id\n ...Task\n log\n }\n }\n": types.TaskDocument, "\n mutation TaskCreate($org_id: Int!, $input: TaskCreateInput!) {\n taskCreate(org_id: $org_id, input: $input) {\n ...Task\n }\n }\n": types.TaskCreateDocument, "\n query BotInstallationsAsOptions($org_id: Int!) {\n botInstallations(org_id: $org_id, filter: { type: manual }) {\n id\n bot {\n id\n name\n image_url\n org {\n id\n name\n }\n }\n }\n }\n": types.BotInstallationsAsOptionsDocument, "\n query RepositoriesAsOptions($org_id: Int!) {\n repos(org_id: $org_id, filter: { is_archived: false }) {\n id\n name\n has_installation\n }\n }\n": types.RepositoriesAsOptionsDocument, @@ -169,7 +169,7 @@ export function gql(source: "\n fragment TaskItem on TaskItem {\n id\n ty /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query Task($org_id: Int!, $id: Int!) {\n task(org_id: $org_id, id: $id) {\n id\n ...Task\n }\n }\n"): (typeof documents)["\n query Task($org_id: Int!, $id: Int!) {\n task(org_id: $org_id, id: $id) {\n id\n ...Task\n }\n }\n"]; +export function gql(source: "\n query Task($org_id: Int!, $id: Int!) {\n task(org_id: $org_id, id: $id) {\n id\n ...Task\n log\n }\n }\n"): (typeof documents)["\n query Task($org_id: Int!, $id: Int!) {\n task(org_id: $org_id, id: $id) {\n id\n ...Task\n log\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/console/src/gql/graphql.ts b/packages/console/src/gql/graphql.ts index 6561156e..2398427c 100644 --- a/packages/console/src/gql/graphql.ts +++ b/packages/console/src/gql/graphql.ts @@ -338,6 +338,7 @@ export type Task = { id: Scalars['Int']['output']; is_scheduled: Scalars['Boolean']['output']; items: Array; + log: Scalars['JSON']['output']; org: Org; state: TaskState; title: Scalars['String']['output']; @@ -625,7 +626,7 @@ export type TaskQueryVariables = Exact<{ export type TaskQuery = { __typename?: 'Query', task: ( - { __typename?: 'Task', id: number } + { __typename?: 'Task', id: number, log: any } & { ' $fragmentRefs'?: { 'TaskFragment': TaskFragment } } ) }; @@ -727,7 +728,7 @@ export const IntegrationsDocument = {"kind":"Document","definitions":[{"kind":"O export const RepoDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Repo"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"repo"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"is_private"}},{"kind":"Field","name":{"kind":"Name","value":"is_archived"}},{"kind":"Field","name":{"kind":"Name","value":"has_installation"}}]}}]}}]} as unknown as DocumentNode; export const RepoTasksDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RepoTasks"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"repo_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tasks"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"repo_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"repo_id"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"Task"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserAvatar"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"providers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_id"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TaskItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TaskItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"actor_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserAvatar"}}]}},{"kind":"Field","name":{"kind":"Name","value":"bot"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"short_description"}},{"kind":"Field","name":{"kind":"Name","value":"image_url"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"repo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"activity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"from_state"}},{"kind":"Field","name":{"kind":"Name","value":"to_state"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Task"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Task"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"is_scheduled"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TaskItem"}}]}}]}}]} as unknown as DocumentNode; export const ReposDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Repos"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"repos"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"Repo"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Repo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Repo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"is_private"}},{"kind":"Field","name":{"kind":"Name","value":"is_archived"}},{"kind":"Field","name":{"kind":"Name","value":"has_installation"}},{"kind":"Field","name":{"kind":"Name","value":"tasks_count"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]} as unknown as DocumentNode; -export const TaskDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Task"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"task"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"Task"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserAvatar"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"providers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_id"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TaskItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TaskItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"actor_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserAvatar"}}]}},{"kind":"Field","name":{"kind":"Name","value":"bot"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"short_description"}},{"kind":"Field","name":{"kind":"Name","value":"image_url"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"repo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"activity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"from_state"}},{"kind":"Field","name":{"kind":"Name","value":"to_state"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Task"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Task"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"is_scheduled"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TaskItem"}}]}}]}}]} as unknown as DocumentNode; +export const TaskDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Task"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"task"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"Task"}},{"kind":"Field","name":{"kind":"Name","value":"log"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserAvatar"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"providers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_id"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TaskItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TaskItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"actor_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserAvatar"}}]}},{"kind":"Field","name":{"kind":"Name","value":"bot"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"short_description"}},{"kind":"Field","name":{"kind":"Name","value":"image_url"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"repo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"activity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"from_state"}},{"kind":"Field","name":{"kind":"Name","value":"to_state"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Task"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Task"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"is_scheduled"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TaskItem"}}]}}]}}]} as unknown as DocumentNode; export const TaskCreateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TaskCreate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaskCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"taskCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Task"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserAvatar"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"providers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_id"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TaskItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TaskItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"actor_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserAvatar"}}]}},{"kind":"Field","name":{"kind":"Name","value":"bot"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"short_description"}},{"kind":"Field","name":{"kind":"Name","value":"image_url"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"repo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"provider_type"}},{"kind":"Field","name":{"kind":"Name","value":"provider_name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"activity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"from_state"}},{"kind":"Field","name":{"kind":"Name","value":"to_state"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Task"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Task"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"is_scheduled"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TaskItem"}}]}}]}}]} as unknown as DocumentNode; export const BotInstallationsAsOptionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"BotInstallationsAsOptions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"botInstallations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"type"},"value":{"kind":"EnumValue","value":"manual"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"bot"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"image_url"}},{"kind":"Field","name":{"kind":"Name","value":"org"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const RepositoriesAsOptionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RepositoriesAsOptions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"repos"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"org_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"org_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"is_archived"},"value":{"kind":"BooleanValue","value":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"has_installation"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/console/src/tasks/views/Task/Task.queries.ts b/packages/console/src/tasks/views/Task/Task.queries.ts index b8bf9024..3b3b6a12 100644 --- a/packages/console/src/tasks/views/Task/Task.queries.ts +++ b/packages/console/src/tasks/views/Task/Task.queries.ts @@ -5,6 +5,7 @@ export const TASK_QUERY = gql(` task(org_id: $org_id, id: $id) { id ...Task + log } } `); diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 1b1b5a20..334ee9dc 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -174,11 +174,12 @@ model tasks { title String @db.VarChar(255) is_scheduled Boolean @default(false) state task_state @default(started) - cost_in_cents Int? token String @db.VarChar(255) proposal_token String? @db.VarChar(255) proposal_base_commit String? @db.VarChar(40) created_at DateTime @default(now()) @db.Timestamp(6) + cost_in_cents Int? + log Json @default("[]") task_items task_items[] orgs orgs @relation(fields: [org_id], references: [id], onDelete: Cascade, onUpdate: NoAction)