Skip to content

Commit 54e14f4

Browse files
waleedlatif1claude
andauthored
fix(notifications): polish modal styling, credential display, and trigger filters (#3571)
* fix(notifications): polish modal styling, credential display, and trigger filters - Show credential display name instead of raw account ID in Slack account selector - Fix label styling to use default Label component (text-primary) for consistency - Fix modal body spacing with proper top padding after tab bar - Replace list-card skeleton with form-field skeleton matching actual layout - Replace custom "Select a Slack account first" box with disabled Combobox (dependsOn pattern) - Use proper Label component in WorkflowSelector with consistent gap spacing - Add overflow badge pattern (slice + +N) to level and trigger filter badges - Use dynamic trigger options from getTriggerOptions() instead of hardcoded CORE_TRIGGER_TYPES - Relax API validation to accept integration trigger types (z.string instead of z.enum) - Deduplicate account rows from credential leftJoin in accounts API - Extract getTriggerOptions() to module-level constants to avoid per-render calls Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(notifications): address PR review feedback - Restore accountId in displayName fallback chain (credentialDisplayName || accountId || providerId) - Add .default([]) to triggerFilter in create schema to preserve backward compatibility - Treat empty triggerFilter as "match all" in notification matching logic - Remove unreachable overflow badge for levelFilter (only 2 possible values) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cbe8fe3 commit 54e14f4

File tree

7 files changed

+73
-70
lines changed

7 files changed

+73
-70
lines changed

apps/sim/app/api/auth/accounts/route.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { db } from '@sim/db'
2-
import { account } from '@sim/db/schema'
2+
import { account, credential } from '@sim/db/schema'
33
import { createLogger } from '@sim/logger'
44
import { and, desc, eq } from 'drizzle-orm'
55
import { type NextRequest, NextResponse } from 'next/server'
@@ -28,16 +28,25 @@ export async function GET(request: NextRequest) {
2828
id: account.id,
2929
accountId: account.accountId,
3030
providerId: account.providerId,
31+
credentialDisplayName: credential.displayName,
3132
})
3233
.from(account)
34+
.leftJoin(credential, eq(credential.accountId, account.id))
3335
.where(and(...whereConditions))
3436
.orderBy(desc(account.updatedAt))
3537

36-
const accountsWithDisplayName = accounts.map((acc) => ({
38+
const seen = new Map<string, (typeof accounts)[number]>()
39+
for (const acc of accounts) {
40+
if (!seen.has(acc.id)) {
41+
seen.set(acc.id, acc)
42+
}
43+
}
44+
45+
const accountsWithDisplayName = Array.from(seen.values()).map((acc) => ({
3746
id: acc.id,
3847
accountId: acc.accountId,
3948
providerId: acc.providerId,
40-
displayName: acc.accountId || acc.providerId,
49+
displayName: acc.credentialDisplayName || acc.accountId || acc.providerId,
4150
}))
4251

4352
return NextResponse.json({ accounts: accountsWithDisplayName })

apps/sim/app/api/workspaces/[id]/notifications/[notificationId]/route.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
88
import { getSession } from '@/lib/auth'
99
import { encryptSecret } from '@/lib/core/security/encryption'
1010
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
11-
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
1211
import { MAX_EMAIL_RECIPIENTS, MAX_WORKFLOW_IDS } from '../constants'
1312

1413
const logger = createLogger('WorkspaceNotificationAPI')
1514

1615
const levelFilterSchema = z.array(z.enum(['info', 'error']))
17-
const triggerFilterSchema = z.array(z.enum(CORE_TRIGGER_TYPES))
16+
const triggerFilterSchema = z.array(z.string().min(1))
1817

1918
const alertRuleSchema = z.enum([
2019
'consecutive_failures',

apps/sim/app/api/workspaces/[id]/notifications/route.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
99
import { getSession } from '@/lib/auth'
1010
import { encryptSecret } from '@/lib/core/security/encryption'
1111
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
12-
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
1312
import { MAX_EMAIL_RECIPIENTS, MAX_NOTIFICATIONS_PER_TYPE, MAX_WORKFLOW_IDS } from './constants'
1413

1514
const logger = createLogger('WorkspaceNotificationsAPI')
1615

1716
const notificationTypeSchema = z.enum(['webhook', 'email', 'slack'])
1817
const levelFilterSchema = z.array(z.enum(['info', 'error']))
19-
const triggerFilterSchema = z.array(z.enum(CORE_TRIGGER_TYPES))
18+
const triggerFilterSchema = z.array(z.string().min(1))
2019

2120
const alertRuleSchema = z.enum([
2221
'consecutive_failures',
@@ -82,7 +81,7 @@ const createNotificationSchema = z
8281
workflowIds: z.array(z.string()).max(MAX_WORKFLOW_IDS).default([]),
8382
allWorkflows: z.boolean().default(false),
8483
levelFilter: levelFilterSchema.default(['info', 'error']),
85-
triggerFilter: triggerFilterSchema.default([...CORE_TRIGGER_TYPES]),
84+
triggerFilter: triggerFilterSchema.default([]),
8685
includeFinalOutput: z.boolean().default(false),
8786
includeTraceSpans: z.boolean().default(false),
8887
includeRateLimits: z.boolean().default(false),

apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/notifications/components/slack-channel-selector/slack-channel-selector.tsx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,6 @@ export function SlackChannelSelector({
7979

8080
const selectedChannel = channels.find((c) => c.id === value)
8181

82-
if (!accountId) {
83-
return (
84-
<div className='rounded-[6px] border bg-[var(--surface-3)] p-[10px] text-center'>
85-
<p className='text-[12px] text-[var(--text-muted)]'>Select a Slack account first</p>
86-
</div>
87-
)
88-
}
89-
9082
const handleChange = (channelId: string) => {
9183
const channel = channels.find((c) => c.id === channelId)
9284
onChange(channelId, channel?.name || '')
@@ -99,9 +91,13 @@ export function SlackChannelSelector({
9991
value={value}
10092
onChange={handleChange}
10193
placeholder={
102-
channels.length === 0 && !isLoading ? 'No channels available' : 'Select channel...'
94+
!accountId
95+
? 'Select an account first...'
96+
: channels.length === 0 && !isLoading
97+
? 'No channels available'
98+
: 'Select channel...'
10399
}
104-
disabled={disabled || channels.length === 0}
100+
disabled={disabled || !accountId || channels.length === 0}
105101
isLoading={isLoading}
106102
error={fetchError}
107103
searchable

apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/notifications/components/workflow-selector/workflow-selector.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useMemo } from 'react'
44
import { X } from 'lucide-react'
5-
import { Badge, Combobox, type ComboboxOption } from '@/components/emcn'
5+
import { Badge, Combobox, type ComboboxOption, Label } from '@/components/emcn'
66
import { Skeleton } from '@/components/ui'
77
import { useWorkflows } from '@/hooks/queries/workflows'
88

@@ -103,16 +103,16 @@ export function WorkflowSelector({
103103

104104
if (isLoading) {
105105
return (
106-
<div className='flex flex-col gap-[4px]'>
107-
<span className='font-medium text-[13px] text-[var(--text-secondary)]'>Workflows</span>
106+
<div className='flex flex-col gap-[8px]'>
107+
<Label>Workflows</Label>
108108
<Skeleton className='h-[34px] w-full rounded-[6px]' />
109109
</div>
110110
)
111111
}
112112

113113
return (
114-
<div className='flex flex-col gap-[4px]'>
115-
<span className='font-medium text-[13px] text-[var(--text-secondary)]'>Workflows</span>
114+
<div className='flex flex-col gap-[8px]'>
115+
<Label>Workflows</Label>
116116
<Combobox
117117
options={options}
118118
multiSelect

0 commit comments

Comments
 (0)