Skip to content

Commit 1d5656a

Browse files
committed
feat(workspaces): add workspace logo upload
1 parent 6259d7d commit 1d5656a

11 files changed

Lines changed: 406 additions & 1220 deletions

File tree

apps/docs/content/docs/en/tools/cloudwatch.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
1111
/>
1212

1313
{/* MANUAL-CONTENT-START:intro */}
14-
[AWS CloudWatch](https://aws.amazon.com/cloudwatch/) is a monitoring and observability service that provides data and actionable insights for AWS resources, applications, and services. CloudWatch collects monitoring and operational data in the form of logs, metrics, and events, giving you a unified view of your AWS environment.
14+
[Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) is a monitoring and observability service that collects and tracks metrics, collects and monitors log files, and sets alarms for your AWS resources. CloudWatch provides a unified view of operational health across your AWS infrastructure and applications.
1515

1616
With the CloudWatch integration, you can:
1717

18-
- **Query Logs (Insights)**: Run CloudWatch Log Insights queries against one or more log groups to analyze log data with a powerful query language
19-
- **Describe Log Groups**: List available CloudWatch log groups in your account, optionally filtered by name prefix
20-
- **Get Log Events**: Retrieve log events from a specific log stream within a log group
21-
- **Describe Log Streams**: List log streams within a log group, ordered by last event time or filtered by name prefix
22-
- **List Metrics**: Browse available CloudWatch metrics, optionally filtered by namespace, metric name, or recent activity
23-
- **Get Metric Statistics**: Retrieve statistical data for a metric over a specified time range with configurable granularity
24-
- **Publish Metric**: Publish custom metric data points to CloudWatch for your own application monitoring
25-
- **Describe Alarms**: List and filter CloudWatch alarms by name prefix, state, or alarm type
18+
- **Query Logs (Insights)**: Run powerful CloudWatch Log Insights queries across one or more log groups to search, analyze, and visualize your log data
19+
- **Describe Log Groups**: List available log groups in your account with metadata like stored bytes, retention settings, and creation time
20+
- **Get Log Events**: Retrieve individual log events from a specific log stream with optional time range filtering
21+
- **Describe Log Streams**: List log streams within a log group, sorted by last event time or filtered by name prefix
22+
- **List Metrics**: Browse available CloudWatch metrics, filtered by namespace or metric name, with support for recently active metrics
23+
- **Get Metric Statistics**: Retrieve statistical data (average, sum, min, max, sample count) for a metric over a specified time range and period
24+
- **Publish Metric**: Publish custom metric data points to CloudWatch with optional units and dimensions
25+
- **Describe Alarms**: List and filter CloudWatch alarms by name prefix, state (OK, ALARM, INSUFFICIENT_DATA), or type (Metric, Composite)
2626

27-
In Sim, the CloudWatch integration enables your agents to monitor AWS infrastructure, analyze application logs, track custom metrics, and respond to alarm states as part of automated DevOps and SRE workflows. This is especially powerful when combined with other AWS integrations like CloudFormation and SNS for end-to-end infrastructure management.
27+
In Sim, the CloudWatch integration enables your agents to monitor application health, analyze logs for errors, track custom business metrics, and respond to alarm states as part of automated observability and incident response workflows. This pairs well with CloudFormation for infrastructure monitoring and SNS for alerting.
2828
{/* MANUAL-CONTENT-END */}
2929

3030

apps/sim/app/workspace/[workspaceId]/settings/hooks/use-profile-picture-upload.ts

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -51,30 +51,33 @@ export function useProfilePictureUpload({
5151
fileInputRef.current?.click()
5252
}, [])
5353

54-
const uploadFileToServer = useCallback(async (file: File): Promise<string> => {
55-
try {
56-
const formData = new FormData()
57-
formData.append('file', file)
58-
formData.append('context', context)
59-
60-
const response = await fetch('/api/files/upload', {
61-
method: 'POST',
62-
body: formData,
63-
})
64-
65-
if (!response.ok) {
66-
const errorData = await response.json().catch(() => ({ error: response.statusText }))
67-
throw new Error(errorData.error || `Failed to upload file: ${response.status}`)
54+
const uploadFileToServer = useCallback(
55+
async (file: File): Promise<string> => {
56+
try {
57+
const formData = new FormData()
58+
formData.append('file', file)
59+
formData.append('context', context)
60+
61+
const response = await fetch('/api/files/upload', {
62+
method: 'POST',
63+
body: formData,
64+
})
65+
66+
if (!response.ok) {
67+
const errorData = await response.json().catch(() => ({ error: response.statusText }))
68+
throw new Error(errorData.error || `Failed to upload file: ${response.status}`)
69+
}
70+
71+
const data = await response.json()
72+
const publicUrl = data.fileInfo?.path || data.path || data.url
73+
logger.info(`Profile picture uploaded successfully via server upload: ${publicUrl}`)
74+
return publicUrl
75+
} catch (error) {
76+
throw new Error(error instanceof Error ? error.message : 'Failed to upload profile picture')
6877
}
69-
70-
const data = await response.json()
71-
const publicUrl = data.fileInfo?.path || data.path || data.url
72-
logger.info(`Profile picture uploaded successfully via server upload: ${publicUrl}`)
73-
return publicUrl
74-
} catch (error) {
75-
throw new Error(error instanceof Error ? error.message : 'Failed to upload profile picture')
76-
}
77-
}, [context])
78+
},
79+
[context]
80+
)
7881

7982
const processFile = useCallback(
8083
async (file: File) => {

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/workspace-header.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,9 @@ export function WorkspaceHeader({
373373
) : (
374374
<div
375375
className='flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center rounded-sm font-medium text-caption text-white leading-none'
376-
style={{ backgroundColor: activeWorkspaceFull.color ?? 'var(--brand-accent)' }}
376+
style={{
377+
backgroundColor: activeWorkspaceFull.color ?? 'var(--brand-accent)',
378+
}}
377379
>
378380
{workspaceInitial}
379381
</div>

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ export { useTaskSelection } from './use-task-selection'
1818
export { useWorkflowOperations } from './use-workflow-operations'
1919
export { useWorkflowSelection } from './use-workflow-selection'
2020
export { useWorkspaceLogoUpload } from './use-workspace-logo-upload'
21-
export { useWorkspaceManagement, type Workspace } from './use-workspace-management'
21+
export { useWorkspaceManagement } from './use-workspace-management'

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ import {
7373
useWorkflowOperations,
7474
useWorkspaceLogoUpload,
7575
useWorkspaceManagement,
76-
type Workspace,
7776
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
7877
import {
7978
createSidebarDragGhost,
@@ -97,6 +96,7 @@ import {
9796
useRenameTask,
9897
useTasks,
9998
} from '@/hooks/queries/tasks'
99+
import type { Workspace } from '@/hooks/queries/workspace'
100100
import { useUpdateWorkflow } from '@/hooks/queries/workflows'
101101
import { useWorkspaceFiles } from '@/hooks/queries/workspace-files'
102102
import { usePermissionConfig } from '@/hooks/use-permission-config'

apps/sim/blocks/blocks/cloudwatch.ts

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ export const CloudWatchBlock: BlockConfig<
2727
description: 'Query and monitor AWS CloudWatch logs, metrics, and alarms',
2828
longDescription:
2929
'Integrate AWS CloudWatch into workflows. Run Log Insights queries, list log groups, retrieve log events, list and get metrics, and monitor alarms. Requires AWS access key and secret access key.',
30+
docsLink: 'https://docs.sim.ai/tools/cloudwatch',
3031
category: 'tools',
3132
integrationType: IntegrationType.Analytics,
32-
docsLink: 'https://docs.sim.ai/tools/cloudwatch',
3333
tags: ['cloud', 'monitoring'],
3434
bgColor: 'linear-gradient(45deg, #B0084D 0%, #FF4F8B 100%)',
3535
icon: CloudWatchIcon,
@@ -73,6 +73,7 @@ export const CloudWatchBlock: BlockConfig<
7373
password: true,
7474
required: true,
7575
},
76+
// Query Logs fields
7677
{
7778
id: 'logGroupSelector',
7879
title: 'Log Group',
@@ -129,10 +130,9 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
129130
required: { field: 'operation', value: ['query_logs', 'get_metric_statistics'] },
130131
wandConfig: {
131132
enabled: true,
132-
prompt: `Generate a Unix epoch timestamp (in seconds) based on the user's description of a point in time.
133-
134-
Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
135-
placeholder: 'Describe the start time (e.g., "1 hour ago", "beginning of today")...',
133+
prompt:
134+
'Generate a Unix epoch timestamp in seconds for the described start time. Return ONLY the numeric timestamp - no explanations, no extra text.',
135+
placeholder: 'Describe the start time (e.g., "1 hour ago", "start of today")...',
136136
generationType: 'timestamp',
137137
},
138138
},
@@ -148,20 +148,21 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
148148
required: { field: 'operation', value: ['query_logs', 'get_metric_statistics'] },
149149
wandConfig: {
150150
enabled: true,
151-
prompt: `Generate a Unix epoch timestamp (in seconds) based on the user's description of a point in time.
152-
153-
Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
154-
placeholder: 'Describe the end time (e.g., "now", "end of yesterday")...',
151+
prompt:
152+
'Generate a Unix epoch timestamp in seconds for the described end time. Return ONLY the numeric timestamp - no explanations, no extra text.',
153+
placeholder: 'Describe the end time (e.g., "now", "end of today")...',
155154
generationType: 'timestamp',
156155
},
157156
},
157+
// Describe Log Groups fields
158158
{
159159
id: 'prefix',
160160
title: 'Log Group Name Prefix',
161161
type: 'short-input',
162162
placeholder: '/aws/lambda/',
163163
condition: { field: 'operation', value: 'describe_log_groups' },
164164
},
165+
// Get Log Events / Describe Log Streams — shared log group selector
165166
{
166167
id: 'logGroupNameSelector',
167168
title: 'Log Group',
@@ -184,13 +185,15 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
184185
required: { field: 'operation', value: ['get_log_events', 'describe_log_streams'] },
185186
mode: 'advanced',
186187
},
188+
// Describe Log Streams — stream prefix filter
187189
{
188190
id: 'streamPrefix',
189191
title: 'Stream Name Prefix',
190192
type: 'short-input',
191193
placeholder: '2024/03/31/',
192194
condition: { field: 'operation', value: 'describe_log_streams' },
193195
},
196+
// Get Log Events — log stream selector (cascading: depends on log group)
194197
{
195198
id: 'logStreamNameSelector',
196199
title: 'Log Stream',
@@ -213,6 +216,7 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
213216
required: { field: 'operation', value: 'get_log_events' },
214217
mode: 'advanced',
215218
},
219+
// List Metrics fields
216220
{
217221
id: 'metricNamespace',
218222
title: 'Namespace',
@@ -248,6 +252,7 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
248252
condition: { field: 'operation', value: 'list_metrics' },
249253
mode: 'advanced',
250254
},
255+
// Publish Metric fields
251256
{
252257
id: 'metricValue',
253258
title: 'Value',
@@ -271,22 +276,8 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
271276
{ label: 'Kilobytes', id: 'Kilobytes' },
272277
{ label: 'Megabytes', id: 'Megabytes' },
273278
{ label: 'Gigabytes', id: 'Gigabytes' },
274-
{ label: 'Terabytes', id: 'Terabytes' },
275279
{ label: 'Bits', id: 'Bits' },
276-
{ label: 'Kilobits', id: 'Kilobits' },
277-
{ label: 'Megabits', id: 'Megabits' },
278-
{ label: 'Gigabits', id: 'Gigabits' },
279-
{ label: 'Terabits', id: 'Terabits' },
280280
{ label: 'Bytes/Second', id: 'Bytes/Second' },
281-
{ label: 'Kilobytes/Second', id: 'Kilobytes/Second' },
282-
{ label: 'Megabytes/Second', id: 'Megabytes/Second' },
283-
{ label: 'Gigabytes/Second', id: 'Gigabytes/Second' },
284-
{ label: 'Terabytes/Second', id: 'Terabytes/Second' },
285-
{ label: 'Bits/Second', id: 'Bits/Second' },
286-
{ label: 'Kilobits/Second', id: 'Kilobits/Second' },
287-
{ label: 'Megabits/Second', id: 'Megabits/Second' },
288-
{ label: 'Gigabits/Second', id: 'Gigabits/Second' },
289-
{ label: 'Terabits/Second', id: 'Terabits/Second' },
290281
{ label: 'Count/Second', id: 'Count/Second' },
291282
],
292283
value: () => 'None',
@@ -299,6 +290,7 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
299290
columns: ['name', 'value'],
300291
condition: { field: 'operation', value: 'put_metric_data' },
301292
},
293+
// Get Metric Statistics fields
302294
{
303295
id: 'metricPeriod',
304296
title: 'Period (seconds)',
@@ -328,6 +320,7 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
328320
columns: ['name', 'value'],
329321
condition: { field: 'operation', value: 'get_metric_statistics' },
330322
},
323+
// Describe Alarms fields
331324
{
332325
id: 'alarmNamePrefix',
333326
title: 'Alarm Name Prefix',
@@ -360,6 +353,7 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
360353
value: () => '',
361354
condition: { field: 'operation', value: 'describe_alarms' },
362355
},
356+
// Shared limit field
363357
{
364358
id: 'limit',
365359
title: 'Limit',
@@ -570,18 +564,14 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
570564
if (rest.metricValue === undefined || rest.metricValue === '') {
571565
throw new Error('Metric value is required')
572566
}
573-
const numericValue = Number(rest.metricValue)
574-
if (!Number.isFinite(numericValue)) {
575-
throw new Error('Metric value must be a finite number')
576-
}
577567

578568
return {
579569
awsRegion,
580570
awsAccessKeyId,
581571
awsSecretAccessKey,
582572
namespace: rest.metricNamespace,
583573
metricName: rest.metricName,
584-
value: numericValue,
574+
value: Number(rest.metricValue),
585575
...(rest.metricUnit && rest.metricUnit !== 'None' && { unit: rest.metricUnit }),
586576
...(rest.publishDimensions && {
587577
dimensions: (() => {
@@ -696,26 +686,6 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
696686
type: 'array',
697687
description: 'CloudWatch alarms with state and configuration',
698688
},
699-
success: {
700-
type: 'boolean',
701-
description: 'Whether the published metric was successful',
702-
},
703-
namespace: {
704-
type: 'string',
705-
description: 'Metric namespace',
706-
},
707-
metricName: {
708-
type: 'string',
709-
description: 'Metric name',
710-
},
711-
value: {
712-
type: 'number',
713-
description: 'Published metric value',
714-
},
715-
unit: {
716-
type: 'string',
717-
description: 'Metric unit',
718-
},
719689
timestamp: {
720690
type: 'string',
721691
description: 'Timestamp when metric was published',

apps/sim/tools/cloudformation/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { getTemplateTool } from '@/tools/cloudformation/get_template'
88
import { listStackResourcesTool } from '@/tools/cloudformation/list_stack_resources'
99
import { validateTemplateTool } from '@/tools/cloudformation/validate_template'
1010

11+
export * from './types'
12+
1113
export const cloudformationDescribeStacksTool = describeStacksTool
1214
export const cloudformationListStackResourcesTool = listStackResourcesTool
1315
export const cloudformationDetectStackDriftTool = detectStackDriftTool

apps/sim/tools/cloudwatch/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ export const cloudwatchGetMetricStatisticsTool = getMetricStatisticsTool
1717
export const cloudwatchListMetricsTool = listMetricsTool
1818
export const cloudwatchPutMetricDataTool = putMetricDataTool
1919
export const cloudwatchQueryLogsTool = queryLogsTool
20+
21+
export * from './types'

0 commit comments

Comments
 (0)