add temporal service to builds. (#2842)

This commit is contained in:
Max Novich
2025-06-10 08:17:45 -07:00
committed by GitHub
parent f23fc192e4
commit cb6a819de4
44 changed files with 5145 additions and 180 deletions
+1
View File
@@ -7,3 +7,4 @@ src/bin/goose-npm/
/src/bin/*.cmd
/playwright-report/
/test-results/
/src/bin/temporal-service
+1 -1
View File
@@ -10,7 +10,7 @@
"license": {
"name": "Apache-2.0"
},
"version": "1.0.24"
"version": "1.0.26"
},
"paths": {
"/agent/tools": {
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="22.6666" cy="21.3333" r="21.3333" fill="#101010"/>
<path d="M15.9289 14.9289C19.8342 11.0237 26.1663 11.0237 30.0715 14.9289C33.9768 18.8342 33.9768 25.1663 30.0715 29.0715C26.1663 32.9768 19.8342 32.9768 15.9289 29.0715C12.0237 25.1663 12.0237 18.8342 15.9289 14.9289ZM28.6574 16.343C25.5333 13.2188 20.4672 13.2188 17.343 16.343C14.2188 19.4672 14.2188 24.5333 17.343 27.6574C20.4672 30.7816 25.5333 30.7816 28.6574 27.6574C31.7816 24.5333 31.7816 19.4672 28.6574 16.343ZM24.0002 22.0002H26.5002V24.0002H23.0002C22.4479 24.0002 22.0002 23.5525 22.0002 23.0002V18.5002H24.0002V22.0002Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 718 B

+1 -1
View File
@@ -336,7 +336,7 @@ export default function RecipeEditor({ config }: RecipeEditorProps) {
<button
onClick={() => setIsScheduleModalOpen(true)}
disabled={!requiredFieldsAreFilled()}
className="w-full p-3 bg-green-500 text-white rounded-lg hover:bg-green-600 disabled:opacity-50 disabled:hover:bg-green-500"
className="w-full h-[60px] rounded-none border-t text-gray-900 dark:text-white hover:bg-gray-50 dark:border-gray-600 text-lg font-medium"
>
Create Schedule from Recipe
</button>
@@ -7,6 +7,7 @@ import cronstrue from 'cronstrue';
import * as yaml from 'yaml';
import { Buffer } from 'buffer';
import { Recipe } from '../../recipe';
import ClockIcon from '../../assets/clock-icon.svg';
type FrequencyValue = 'once' | 'hourly' | 'daily' | 'weekly' | 'monthly';
@@ -499,17 +500,24 @@ export const CreateScheduleModal: React.FC<CreateScheduleModalProps> = ({
return (
<div className="fixed inset-0 bg-black/20 backdrop-blur-sm z-40 flex items-center justify-center p-4">
<Card className="w-full max-w-md bg-bgApp shadow-xl rounded-lg z-50 flex flex-col max-h-[90vh] overflow-hidden">
<div className="px-6 pt-6 pb-4 flex-shrink-0">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
Create New Schedule
</h2>
<Card className="w-full max-w-md bg-bgApp shadow-xl rounded-3xl z-50 flex flex-col max-h-[90vh] overflow-hidden">
<div className="px-8 pt-8 pb-4 flex-shrink-0 text-center">
<div className="flex flex-col items-center">
<img src={ClockIcon} alt="Clock" className="w-11 h-11 mb-2" />
<h2 className="text-base font-semibold text-gray-900 dark:text-white">
Create New Schedule
</h2>
<p className="text-base text-gray-500 dark:text-gray-400 mt-2 max-w-sm">
Create a new schedule using the settings below to do things like automatically run
tasks or create files
</p>
</div>
</div>
<form
id="new-schedule-form"
onSubmit={handleLocalSubmit}
className="px-6 py-4 space-y-4 flex-grow overflow-y-auto"
className="px-8 py-4 space-y-4 flex-grow overflow-y-auto"
>
{apiErrorExternally && (
<p className="text-red-500 text-sm mb-3 p-2 bg-red-100 dark:bg-red-900/30 rounded-md border border-red-500/50">
@@ -524,7 +532,7 @@ export const CreateScheduleModal: React.FC<CreateScheduleModalProps> = ({
<div>
<label htmlFor="scheduleId-modal" className={modalLabelClassName}>
Schedule ID:
Name:
</label>
<Input
type="text"
@@ -537,30 +545,30 @@ export const CreateScheduleModal: React.FC<CreateScheduleModalProps> = ({
</div>
<div>
<label className={modalLabelClassName}>Recipe Source:</label>
<label className={modalLabelClassName}>Source:</label>
<div className="space-y-2">
<div className="flex gap-2">
<div className="flex bg-gray-100 dark:bg-gray-700 rounded-full p-1">
<button
type="button"
onClick={() => setSourceType('file')}
className={`px-3 py-2 text-sm rounded-md border ${
className={`flex-1 px-4 py-2 text-sm font-medium rounded-full transition-all ${
sourceType === 'file'
? 'bg-blue-500 text-white border-blue-500'
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-white shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
}`}
>
YAML File
YAML
</button>
<button
type="button"
onClick={() => setSourceType('deeplink')}
className={`px-3 py-2 text-sm rounded-md border ${
className={`flex-1 px-4 py-2 text-sm font-medium rounded-full transition-all ${
sourceType === 'deeplink'
? 'bg-blue-500 text-white border-blue-500'
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-white shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
}`}
>
Deep Link
Deep link
</button>
</div>
@@ -570,7 +578,7 @@ export const CreateScheduleModal: React.FC<CreateScheduleModalProps> = ({
type="button"
variant="outline"
onClick={handleBrowseFile}
className="w-full justify-center"
className="w-full justify-center rounded-full"
>
Browse for YAML file...
</Button>
@@ -589,6 +597,7 @@ export const CreateScheduleModal: React.FC<CreateScheduleModalProps> = ({
value={deepLinkInput}
onChange={(e) => handleDeepLinkChange(e.target.value)}
placeholder="Paste goose://bot or goose://recipe link here..."
className="rounded-full"
/>
{parsedRecipe && (
<div className="mt-2 p-2 bg-green-100 dark:bg-green-900/30 rounded-md border border-green-500/50">
@@ -739,6 +748,15 @@ export const CreateScheduleModal: React.FC<CreateScheduleModalProps> = ({
{/* Actions */}
<div className="mt-[8px] ml-[-24px] mr-[-24px] pt-[16px]">
<Button
type="submit"
form="new-schedule-form"
variant="ghost"
disabled={isLoadingExternally}
className="w-full h-[60px] rounded-none border-t text-gray-900 dark:text-white hover:bg-gray-50 dark:border-gray-600 text-lg font-medium"
>
{isLoadingExternally ? 'Creating...' : 'Create Schedule'}
</Button>
<Button
type="button"
variant="ghost"
@@ -748,15 +766,6 @@ export const CreateScheduleModal: React.FC<CreateScheduleModalProps> = ({
>
Cancel
</Button>
<Button
type="submit"
form="new-schedule-form"
variant="default"
disabled={isLoadingExternally}
className="w-full h-[60px] rounded-none border-t dark:border-gray-600 text-lg dark:text-white dark:border-gray-600 font-regular"
>
{isLoadingExternally ? 'Creating...' : 'Create Schedule'}
</Button>
</div>
</Card>
</div>
@@ -86,12 +86,8 @@ export const ScheduleFromRecipeModal: React.FC<ScheduleFromRecipeModalProps> = (
Recipe Details:
</h3>
<div className="bg-gray-50 dark:bg-gray-800 p-3 rounded-md">
<p className="text-sm font-medium text-gray-900 dark:text-white">
{recipe.title}
</p>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
{recipe.description}
</p>
<p className="text-sm font-medium text-gray-900 dark:text-white">{recipe.title}</p>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">{recipe.description}</p>
</div>
</div>
@@ -100,22 +96,13 @@ export const ScheduleFromRecipeModal: React.FC<ScheduleFromRecipeModalProps> = (
Recipe Deep Link:
</label>
<div className="flex items-center">
<Input
type="text"
value={deepLink}
readOnly
className="flex-1 text-xs font-mono"
/>
<Input type="text" value={deepLink} readOnly className="flex-1 text-xs font-mono" />
<Button
type="button"
onClick={handleCopy}
className="ml-2 px-3 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 flex items-center"
>
{copied ? (
<Check className="w-4 h-4" />
) : (
<Copy className="w-4 h-4" />
)}
{copied ? <Check className="w-4 h-4" /> : <Copy className="w-4 h-4" />}
</Button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
@@ -129,14 +116,14 @@ export const ScheduleFromRecipeModal: React.FC<ScheduleFromRecipeModalProps> = (
type="button"
variant="outline"
onClick={handleClose}
className="flex-1"
className="flex-1 rounded-xl hover:bg-bgSubtle text-textSubtle"
>
Cancel
</Button>
<Button
type="button"
onClick={handleCreateSchedule}
className="flex-1 bg-green-500 hover:bg-green-600 text-white"
className="flex-1 bg-bgAppInverse text-sm text-textProminentInverse rounded-xl hover:bg-bgStandardInverse transition-colors"
>
Create Schedule
</Button>
@@ -16,11 +16,12 @@ import MoreMenuLayout from '../more_menu/MoreMenuLayout';
import { Card } from '../ui/card';
import { Button } from '../ui/button';
import { TrashIcon } from '../icons/TrashIcon';
import { Plus, RefreshCw, Pause, Play, Edit, Square, Eye } from 'lucide-react';
import { Plus, RefreshCw, Pause, Play, Edit, Square, Eye, MoreHorizontal } from 'lucide-react';
import { CreateScheduleModal, NewSchedulePayload } from './CreateScheduleModal';
import { EditScheduleModal } from './EditScheduleModal';
import ScheduleDetailView from './ScheduleDetailView';
import { toastError, toastSuccess } from '../../toasts';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
import cronstrue from 'cronstrue';
interface SchedulesViewProps {
@@ -67,7 +68,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose }) => {
useEffect(() => {
if (viewingScheduleId === null) {
fetchSchedules();
// Check for pending deep link from recipe editor
const pendingDeepLink = localStorage.getItem('pendingScheduleDeepLink');
if (pendingDeepLink) {
@@ -382,7 +383,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose }) => {
onClick={handleRefresh}
disabled={isRefreshing || isLoading}
variant="outline"
className="w-full md:w-auto flex items-center gap-2 justify-center"
className="w-full md:w-auto flex items-center gap-2 justify-center rounded-full [&>svg]:!size-4"
>
<RefreshCw className={`h-4 w-4 ${isRefreshing ? 'animate-spin' : ''}`} />
{isRefreshing ? 'Refreshing...' : 'Refresh'}
@@ -453,111 +454,118 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose }) => {
</p>
)}
</div>
<div className="flex-shrink-0 flex items-center gap-1">
{!job.currently_running && (
<>
<div className="flex-shrink-0">
<Popover>
<PopoverTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={(e) => {
e.stopPropagation();
handleOpenEditModal(job);
}}
className="text-gray-500 dark:text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 hover:bg-blue-100/50 dark:hover:bg-blue-900/30"
title={`Edit schedule ${job.id}`}
disabled={
pausingScheduleIds.has(job.id) ||
deletingScheduleIds.has(job.id) ||
isSubmitting
}
className="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-100/50 dark:hover:bg-gray-800/50"
>
<Edit className="w-4 h-4" />
<MoreHorizontal className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={(e) => {
e.stopPropagation();
if (job.paused) {
handleUnpauseSchedule(job.id);
} else {
handlePauseSchedule(job.id);
}
}}
className={`${
job.paused
? 'text-green-500 dark:text-green-400 hover:text-green-600 dark:hover:text-green-300 hover:bg-green-100/50 dark:hover:bg-green-900/30'
: 'text-orange-500 dark:text-orange-400 hover:text-orange-600 dark:hover:text-orange-300 hover:bg-orange-100/50 dark:hover:bg-orange-900/30'
}`}
title={
job.paused
? `Unpause schedule ${job.id}`
: `Pause schedule ${job.id}`
}
disabled={
pausingScheduleIds.has(job.id) || deletingScheduleIds.has(job.id)
}
>
{job.paused ? (
<Play className="w-4 h-4" />
) : (
<Pause className="w-4 h-4" />
</PopoverTrigger>
<PopoverContent
className="w-48 p-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 shadow-lg"
align="end"
>
<div className="space-y-1">
{!job.currently_running && (
<>
<button
onClick={(e) => {
e.stopPropagation();
handleOpenEditModal(job);
}}
disabled={
pausingScheduleIds.has(job.id) ||
deletingScheduleIds.has(job.id) ||
isSubmitting
}
className="w-full flex items-center justify-between px-3 py-2 text-sm text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
>
<span>Edit</span>
<Edit className="w-4 h-4" />
</button>
<button
onClick={(e) => {
e.stopPropagation();
if (job.paused) {
handleUnpauseSchedule(job.id);
} else {
handlePauseSchedule(job.id);
}
}}
disabled={
pausingScheduleIds.has(job.id) ||
deletingScheduleIds.has(job.id)
}
className="w-full flex items-center justify-between px-3 py-2 text-sm text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
>
<span>{job.paused ? 'Resume schedule' : 'Stop schedule'}</span>
{job.paused ? (
<Play className="w-4 h-4" />
) : (
<Pause className="w-4 h-4" />
)}
</button>
</>
)}
</Button>
</>
)}
{job.currently_running && (
<>
<Button
variant="ghost"
size="icon"
onClick={(e) => {
e.stopPropagation();
handleInspectRunningJob(job.id);
}}
className="text-blue-500 dark:text-blue-400 hover:text-blue-600 dark:hover:text-blue-300 hover:bg-blue-100/50 dark:hover:bg-blue-900/30"
title={`Inspect running job ${job.id}`}
disabled={
inspectingScheduleIds.has(job.id) || killingScheduleIds.has(job.id)
}
>
<Eye className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={(e) => {
e.stopPropagation();
handleKillRunningJob(job.id);
}}
className="text-red-500 dark:text-red-400 hover:text-red-600 dark:hover:text-red-300 hover:bg-red-100/50 dark:hover:bg-red-900/30"
title={`Kill running job ${job.id}`}
disabled={
killingScheduleIds.has(job.id) || inspectingScheduleIds.has(job.id)
}
>
<Square className="w-4 h-4" />
</Button>
</>
)}
<Button
variant="ghost"
size="icon"
onClick={(e) => {
e.stopPropagation();
handleDeleteSchedule(job.id);
}}
className="text-gray-500 dark:text-gray-400 hover:text-red-500 dark:hover:text-red-400 hover:bg-red-100/50 dark:hover:bg-red-900/30"
title={`Delete schedule ${job.id}`}
disabled={
pausingScheduleIds.has(job.id) ||
deletingScheduleIds.has(job.id) ||
killingScheduleIds.has(job.id) ||
inspectingScheduleIds.has(job.id)
}
>
<TrashIcon className="w-5 h-5" />
</Button>
{job.currently_running && (
<>
<button
onClick={(e) => {
e.stopPropagation();
handleInspectRunningJob(job.id);
}}
disabled={
inspectingScheduleIds.has(job.id) ||
killingScheduleIds.has(job.id)
}
className="w-full flex items-center justify-between px-3 py-2 text-sm text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
>
<span>Inspect</span>
<Eye className="w-4 h-4" />
</button>
<button
onClick={(e) => {
e.stopPropagation();
handleKillRunningJob(job.id);
}}
disabled={
killingScheduleIds.has(job.id) ||
inspectingScheduleIds.has(job.id)
}
className="w-full flex items-center justify-between px-3 py-2 text-sm text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
>
<span>Kill job</span>
<Square className="w-4 h-4" />
</button>
</>
)}
<hr className="border-gray-200 dark:border-gray-600 my-1" />
<button
onClick={(e) => {
e.stopPropagation();
handleDeleteSchedule(job.id);
}}
disabled={
pausingScheduleIds.has(job.id) ||
deletingScheduleIds.has(job.id) ||
killingScheduleIds.has(job.id) ||
inspectingScheduleIds.has(job.id)
}
className="w-full flex items-center justify-between px-3 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
>
<span>Delete</span>
<TrashIcon className="w-4 h-4" />
</button>
</div>
</PopoverContent>
</Popover>
</div>
</div>
</Card>