Compare commits

...

33 Commits

Author SHA1 Message Date
Waleed
dff1c9d083 v0.5.64: unsubscribe, search improvements, metrics, additional SSO configuration 2026-01-20 00:34:11 -08:00
Waleed
e4ad31bb6b fix(kb): align bulk chunk operation with API response (#2899)
* fix(kb): align bulk chunk operation with API response

* fix(kb): skip local state update for failed chunks

* fix(kb): correct errors type and refresh on partial failure
2026-01-20 00:24:50 -08:00
Waleed
84691fc873 improvement(modal): fixed popover issue in custom tools modal, removed the ability to update if no changes made (#2897)
* improvement(modal): fixed popover issue in custom tools modal, removed the ability to update if no changes made

* improvement(modal): fixed popover issue in custom tools modal, removed the ability to update if no changes made

* popover fixes, color picker keyboard nav, code simplification

* color standardization

* fix color picker

* set discard alert state when closing modal
2026-01-19 23:52:07 -08:00
Vikhyath Mondreti
b09f683072 v0.5.63: ui and performance improvements, more google tools 2026-01-18 15:22:42 -08:00
Vikhyath Mondreti
a8bb0db660 v0.5.62: webhook bug fixes, seeding default subblock values, block selection fixes 2026-01-16 20:27:06 -08:00
Waleed
af82820a28 v0.5.61: webhook improvements, workflow controls, react query for deployment status, chat fixes, reducto and pulse OCR, linear fixes 2026-01-16 18:06:23 -08:00
Waleed
4372841797 v0.5.60: invitation flow improvements, chat fixes, a2a improvements, additional copilot actions 2026-01-15 00:02:18 -08:00
Waleed
5e8c843241 v0.5.59: a2a support, documentation 2026-01-13 13:21:21 -08:00
Waleed
7bf3d73ee6 v0.5.58: export folders, new tools, permissions groups enhancements 2026-01-13 00:56:59 -08:00
Vikhyath Mondreti
7ffc11a738 v0.5.57: subagents, context menu improvements, bug fixes 2026-01-11 11:38:40 -08:00
Waleed
be578e2ed7 v0.5.56: batch operations, access control and permission groups, billing fixes 2026-01-10 00:31:34 -08:00
Waleed
f415e5edc4 v0.5.55: polling groups, bedrock provider, devcontainer fixes, workflow preview enhancements 2026-01-08 23:36:56 -08:00
Waleed
13a6e6c3fa v0.5.54: seo, model blacklist, helm chart updates, fireflies integration, autoconnect improvements, billing fixes 2026-01-07 16:09:45 -08:00
Waleed
f5ab7f21ae v0.5.53: hotkey improvements, added redis fallback, fixes for workflow tool 2026-01-06 23:34:52 -08:00
Waleed
bfb6fffe38 v0.5.52: new port-based router block, combobox expression and variable support 2026-01-06 16:14:10 -08:00
Waleed
4fbec0a43f v0.5.51: triggers, kb, condition block improvements, supabase and grain integration updates 2026-01-06 14:26:46 -08:00
Waleed
585f5e365b v0.5.50: import improvements, ui upgrades, kb styling and performance improvements 2026-01-05 00:35:55 -08:00
Waleed
3792bdd252 v0.5.49: hitl improvements, new email styles, imap trigger, logs context menu (#2672)
* feat(logs-context-menu): consolidated logs utils and types, added logs record context menu (#2659)

* feat(email): welcome email; improvement(emails): ui/ux (#2658)

* feat(email): welcome email; improvement(emails): ui/ux

* improvement(emails): links, accounts, preview

* refactor(emails): file structure and wrapper components

* added envvar for personal emails sent, added isHosted gate

* fixed failing tests, added env mock

* fix: removed comment

---------

Co-authored-by: waleed <walif6@gmail.com>

* fix(logging): hitl + trigger dev crash protection (#2664)

* hitl gaps

* deal with trigger worker crashes

* cleanup import strcuture

* feat(imap): added support for imap trigger (#2663)

* feat(tools): added support for imap trigger

* feat(imap): added parity, tested

* ack PR comments

* final cleanup

* feat(i18n): update translations (#2665)

Co-authored-by: waleedlatif1 <waleedlatif1@users.noreply.github.com>

* fix(grain): updated grain trigger to auto-establish trigger (#2666)

Co-authored-by: aadamgough <adam@sim.ai>

* feat(admin): routes to manage deployments (#2667)

* feat(admin): routes to manage deployments

* fix naming fo deployed by

* feat(time-picker): added timepicker emcn component, added to playground, added searchable prop for dropdown, added more timezones for schedule, updated license and notice date (#2668)

* feat(time-picker): added timepicker emcn component, added to playground, added searchable prop for dropdown, added more timezones for schedule, updated license and notice date

* removed unused params, cleaned up redundant utils

* improvement(invite): aligned styling (#2669)

* improvement(invite): aligned with rest of app

* fix(invite): error handling

* fix: addressed comments

---------

Co-authored-by: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: waleedlatif1 <waleedlatif1@users.noreply.github.com>
Co-authored-by: Adam Gough <77861281+aadamgough@users.noreply.github.com>
Co-authored-by: aadamgough <adam@sim.ai>
2026-01-03 13:19:18 -08:00
Waleed
eb5d1f3e5b v0.5.48: copy-paste workflow blocks, docs updates, mcp tool fixes 2025-12-31 18:00:04 -08:00
Waleed
54ab82c8dd v0.5.47: deploy workflow as mcp, kb chunks tokenizer, UI improvements, jira service management tools 2025-12-30 23:18:58 -08:00
Waleed
f895bf469b v0.5.46: build improvements, greptile, light mode improvements 2025-12-29 02:17:52 -08:00
Waleed
dd3209af06 v0.5.45: light mode fixes, realtime usage indicator, docker build improvements 2025-12-27 19:57:42 -08:00
Waleed
b6ba3b50a7 v0.5.44: keyboard shortcuts, autolayout, light mode, byok, testing improvements 2025-12-26 21:25:19 -08:00
Waleed
b304233062 v0.5.43: export logs, circleback, grain, vertex, code hygiene, schedule improvements 2025-12-23 19:19:18 -08:00
Vikhyath Mondreti
57e4b49bd6 v0.5.42: fix memory migration 2025-12-23 01:24:54 -08:00
Vikhyath Mondreti
e12dd204ed v0.5.41: memory fixes, copilot improvements, knowledgebase improvements, LLM providers standardization 2025-12-23 00:15:18 -08:00
Vikhyath Mondreti
3d9d9cbc54 v0.5.40: supabase ops to allow non-public schemas, jira uuid 2025-12-21 22:28:05 -08:00
Waleed
0f4ec962ad v0.5.39: notion, workflow variables fixes 2025-12-20 20:44:00 -08:00
Waleed
4827866f9a v0.5.38: snap to grid, copilot ux improvements, billing line items 2025-12-20 17:24:38 -08:00
Waleed
3e697d9ed9 v0.5.37: redaction utils consolidation, logs updates, autoconnect improvements, additional kb tag types 2025-12-19 22:31:55 -08:00
Martin Yankov
4431a1a484 fix(helm): add custom egress rules to realtime network policy (#2481)
The realtime service network policy was missing the custom egress rules section
that allows configuration of additional egress rules via values.yaml. This caused
the realtime pods to be unable to connect to external databases (e.g., PostgreSQL
on port 5432) when using external database configurations.

The app network policy already had this section, but the realtime network policy
was missing it, creating an inconsistency and preventing the realtime service
from accessing external databases configured via networkPolicy.egress values.

This fix adds the same custom egress rules template section to the realtime
network policy, matching the app network policy behavior and allowing users to
configure database connectivity via values.yaml.
2025-12-19 18:59:08 -08:00
Waleed
4d1a9a3f22 v0.5.36: hitl improvements, opengraph, slack fixes, one-click unsubscribe, auth checks, new db indexes 2025-12-19 01:27:49 -08:00
Vikhyath Mondreti
eb07a080fb v0.5.35: helm updates, copilot improvements, 404 for docs, salesforce fixes, subflow resize clamping 2025-12-18 16:23:19 -08:00
17 changed files with 149 additions and 165 deletions

View File

@@ -538,15 +538,11 @@ export function Document({
},
{
onSuccess: (result) => {
if (operation === 'delete') {
if (operation === 'delete' || result.errorCount > 0) {
refreshChunks()
} else {
result.results.forEach((opResult) => {
if (opResult.operation === operation) {
opResult.chunkIds.forEach((chunkId: string) => {
updateChunk(chunkId, { enabled: operation === 'enable' })
})
}
chunks.forEach((chunk) => {
updateChunk(chunk.id, { enabled: operation === 'enable' })
})
}
logger.info(`Successfully ${operation}d ${result.successCount} chunks`)

View File

@@ -462,7 +462,7 @@ export function BaseTagsModal({ open, onOpenChange, knowledgeBaseId }: BaseTagsM
<ModalHeader>Documents using "{selectedTag?.displayName}"</ModalHeader>
<ModalBody>
<div className='space-y-[8px]'>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
{selectedTagUsage?.documentCount || 0} document
{selectedTagUsage?.documentCount !== 1 ? 's are' : ' is'} currently using this tag
definition.
@@ -470,7 +470,7 @@ export function BaseTagsModal({ open, onOpenChange, knowledgeBaseId }: BaseTagsM
{selectedTagUsage?.documentCount === 0 ? (
<div className='rounded-[6px] border p-[16px] text-center'>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
This tag definition is not being used by any documents. You can safely delete it
to free up the tag slot.
</p>

View File

@@ -283,7 +283,7 @@ export function GeneralDeploy({
<ModalContent size='sm'>
<ModalHeader>Promote to live</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
Are you sure you want to promote{' '}
<span className='font-medium text-[var(--text-primary)]'>
{versionToPromoteInfo?.name || `v${versionToPromote}`}

View File

@@ -591,12 +591,11 @@ export function DeployModal({
)}
{activeTab === 'api' && (
<ModalFooter className='items-center justify-between'>
<div>
<div />
<div className='flex items-center gap-2'>
<Button variant='default' onClick={() => setIsApiInfoModalOpen(true)}>
Edit API Info
</Button>
</div>
<div className='flex items-center gap-2'>
<Button
variant='tertiary'
onClick={() => setIsCreateKeyModalOpen(true)}

View File

@@ -42,7 +42,7 @@ export function CodeEditor({
placeholder = '',
className = '',
gutterClassName = '',
minHeight = '360px',
minHeight,
highlightVariables = true,
onKeyDown,
disabled = false,
@@ -186,7 +186,7 @@ export function CodeEditor({
}
return (
<Code.Container className={className} style={{ minHeight }}>
<Code.Container className={className} style={minHeight ? { minHeight } : undefined}>
{showWandButton && onWandClick && (
<Button
variant='ghost'
@@ -220,7 +220,7 @@ export function CodeEditor({
disabled={disabled}
{...getCodeEditorProps({ disabled })}
className={cn(getCodeEditorProps({ disabled }).className, 'h-full')}
style={{ minHeight }}
style={minHeight ? { minHeight } : undefined}
textareaClassName={cn(
getCodeEditorProps({ disabled }).textareaClassName,
'!block !h-full !min-h-full'

View File

@@ -87,15 +87,16 @@ export function CustomToolModal({
const [codeError, setCodeError] = useState<string | null>(null)
const [isEditing, setIsEditing] = useState(false)
const [toolId, setToolId] = useState<string | undefined>(undefined)
const [initialJsonSchema, setInitialJsonSchema] = useState('')
const [initialFunctionCode, setInitialFunctionCode] = useState('')
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
const [showDiscardAlert, setShowDiscardAlert] = useState(false)
const [isSchemaPromptActive, setIsSchemaPromptActive] = useState(false)
const [schemaPromptInput, setSchemaPromptInput] = useState('')
const [schemaPromptSummary, setSchemaPromptSummary] = useState<string | null>(null)
const schemaPromptInputRef = useRef<HTMLInputElement | null>(null)
const [isCodePromptActive, setIsCodePromptActive] = useState(false)
const [codePromptInput, setCodePromptInput] = useState('')
const [codePromptSummary, setCodePromptSummary] = useState<string | null>(null)
const codePromptInputRef = useRef<HTMLInputElement | null>(null)
const schemaGeneration = useWand({
@@ -174,6 +175,9 @@ Example 2:
generationType: 'custom-tool-schema',
},
currentValue: jsonSchema,
onStreamStart: () => {
setJsonSchema('')
},
onGeneratedContent: (content) => {
setJsonSchema(content)
setSchemaError(null)
@@ -237,6 +241,9 @@ try {
generationType: 'javascript-function-body',
},
currentValue: functionCode,
onStreamStart: () => {
setFunctionCode('')
},
onGeneratedContent: (content) => {
handleFunctionCodeChange(content)
setCodeError(null)
@@ -272,12 +279,15 @@ try {
if (initialValues) {
try {
setJsonSchema(
const schemaValue =
typeof initialValues.schema === 'string'
? initialValues.schema
: JSON.stringify(initialValues.schema, null, 2)
)
setFunctionCode(initialValues.code || '')
const codeValue = initialValues.code || ''
setJsonSchema(schemaValue)
setFunctionCode(codeValue)
setInitialJsonSchema(schemaValue)
setInitialFunctionCode(codeValue)
setIsEditing(true)
setToolId(initialValues.id)
} catch (error) {
@@ -304,17 +314,18 @@ try {
const resetForm = () => {
setJsonSchema('')
setFunctionCode('')
setInitialJsonSchema('')
setInitialFunctionCode('')
setSchemaError(null)
setCodeError(null)
setActiveSection('schema')
setIsEditing(false)
setToolId(undefined)
setSchemaPromptSummary(null)
setCodePromptSummary(null)
setIsSchemaPromptActive(false)
setIsCodePromptActive(false)
setSchemaPromptInput('')
setCodePromptInput('')
setShowDiscardAlert(false)
schemaGeneration.closePrompt()
schemaGeneration.hidePromptInline()
codeGeneration.closePrompt()
@@ -328,31 +339,37 @@ try {
onOpenChange(false)
}
const validateJsonSchema = (schema: string): boolean => {
if (!schema) return false
const validateSchema = (schema: string): { isValid: boolean; error: string | null } => {
if (!schema) return { isValid: false, error: null }
try {
const parsed = JSON.parse(schema)
if (!parsed.type || parsed.type !== 'function') {
return false
return { isValid: false, error: 'Missing "type": "function"' }
}
if (!parsed.function || !parsed.function.name) {
return false
return { isValid: false, error: 'Missing function.name field' }
}
if (!parsed.function.parameters) {
return false
return { isValid: false, error: 'Missing function.parameters object' }
}
if (!parsed.function.parameters.type) {
return { isValid: false, error: 'Missing parameters.type field' }
}
if (parsed.function.parameters.properties === undefined) {
return { isValid: false, error: 'Missing parameters.properties field' }
}
if (
typeof parsed.function.parameters.properties !== 'object' ||
parsed.function.parameters.properties === null
) {
return { isValid: false, error: 'parameters.properties must be an object' }
}
if (!parsed.function.parameters.type || parsed.function.parameters.properties === undefined) {
return false
}
return true
} catch (_error) {
return false
return { isValid: true, error: null }
} catch {
return { isValid: false, error: 'Invalid JSON format' }
}
}
@@ -374,7 +391,32 @@ try {
}
}, [jsonSchema])
const isSchemaValid = useMemo(() => validateJsonSchema(jsonSchema), [jsonSchema])
const isSchemaValid = useMemo(() => validateSchema(jsonSchema).isValid, [jsonSchema])
const hasChanges = useMemo(() => {
if (!isEditing) return true
return jsonSchema !== initialJsonSchema || functionCode !== initialFunctionCode
}, [isEditing, jsonSchema, initialJsonSchema, functionCode, initialFunctionCode])
const hasUnsavedChanges = useMemo(() => {
if (isEditing) {
return jsonSchema !== initialJsonSchema || functionCode !== initialFunctionCode
}
return jsonSchema.trim().length > 0 || functionCode.trim().length > 0
}, [isEditing, jsonSchema, initialJsonSchema, functionCode, initialFunctionCode])
const handleCloseAttempt = () => {
if (hasUnsavedChanges && !schemaGeneration.isStreaming && !codeGeneration.isStreaming) {
setShowDiscardAlert(true)
} else {
handleClose()
}
}
const handleConfirmDiscard = () => {
setShowDiscardAlert(false)
handleClose()
}
const handleSave = async () => {
try {
@@ -384,43 +426,9 @@ try {
return
}
const parsed = JSON.parse(jsonSchema)
if (!parsed.type || parsed.type !== 'function') {
setSchemaError('Schema must have a "type" field set to "function"')
setActiveSection('schema')
return
}
if (!parsed.function || !parsed.function.name) {
setSchemaError('Schema must have a "function" object with a "name" field')
setActiveSection('schema')
return
}
if (!parsed.function.parameters) {
setSchemaError('Missing function.parameters object')
setActiveSection('schema')
return
}
if (!parsed.function.parameters.type) {
setSchemaError('Missing parameters.type field')
setActiveSection('schema')
return
}
if (parsed.function.parameters.properties === undefined) {
setSchemaError('Missing parameters.properties field')
setActiveSection('schema')
return
}
if (
typeof parsed.function.parameters.properties !== 'object' ||
parsed.function.parameters.properties === null
) {
setSchemaError('parameters.properties must be an object')
const { isValid, error } = validateSchema(jsonSchema)
if (!isValid) {
setSchemaError(error)
setActiveSection('schema')
return
}
@@ -483,17 +491,9 @@ try {
}
onSave(customTool)
setSchemaPromptSummary(null)
setCodePromptSummary(null)
handleClose()
} catch (error) {
logger.error('Error saving custom tool:', { error })
setSchemaPromptSummary(null)
setCodePromptSummary(null)
const errorMessage = error instanceof Error ? error.message : 'Failed to save custom tool'
if (errorMessage.includes('Cannot change function name')) {
@@ -512,46 +512,8 @@ try {
setJsonSchema(value)
if (value.trim()) {
try {
const parsed = JSON.parse(value)
if (!parsed.type || parsed.type !== 'function') {
setSchemaError('Missing "type": "function"')
return
}
if (!parsed.function || !parsed.function.name) {
setSchemaError('Missing function.name field')
return
}
if (!parsed.function.parameters) {
setSchemaError('Missing function.parameters object')
return
}
if (!parsed.function.parameters.type) {
setSchemaError('Missing parameters.type field')
return
}
if (parsed.function.parameters.properties === undefined) {
setSchemaError('Missing parameters.properties field')
return
}
if (
typeof parsed.function.parameters.properties !== 'object' ||
parsed.function.parameters.properties === null
) {
setSchemaError('parameters.properties must be an object')
return
}
setSchemaError(null)
} catch {
setSchemaError('Invalid JSON format')
}
const { error } = validateSchema(value)
setSchemaError(error)
} else {
setSchemaError(null)
}
@@ -709,12 +671,12 @@ try {
e.preventDefault()
e.stopPropagation()
setSchemaParamSelectedIndex((prev) => Math.min(prev + 1, schemaParameters.length - 1))
break
return
case 'ArrowUp':
e.preventDefault()
e.stopPropagation()
setSchemaParamSelectedIndex((prev) => Math.max(prev - 1, 0))
break
return
case 'Enter':
e.preventDefault()
e.stopPropagation()
@@ -722,14 +684,17 @@ try {
const selectedParam = schemaParameters[schemaParamSelectedIndex]
handleSchemaParamSelect(selectedParam.name)
}
break
return
case 'Escape':
e.preventDefault()
e.stopPropagation()
setShowSchemaParams(false)
break
return
case ' ':
case 'Tab':
setShowSchemaParams(false)
return
}
return
}
if (showEnvVars || showTags) {
@@ -743,7 +708,7 @@ try {
const handleSchemaWandClick = () => {
if (schemaGeneration.isLoading || schemaGeneration.isStreaming) return
setIsSchemaPromptActive(true)
setSchemaPromptInput(schemaPromptSummary ?? '')
setSchemaPromptInput('')
setTimeout(() => {
schemaPromptInputRef.current?.focus()
}, 0)
@@ -762,7 +727,6 @@ try {
const handleSchemaPromptSubmit = () => {
const trimmedPrompt = schemaPromptInput.trim()
if (!trimmedPrompt || schemaGeneration.isLoading || schemaGeneration.isStreaming) return
setSchemaPromptSummary(trimmedPrompt)
schemaGeneration.generateStream({ prompt: trimmedPrompt })
setSchemaPromptInput('')
setIsSchemaPromptActive(false)
@@ -782,7 +746,7 @@ try {
const handleCodeWandClick = () => {
if (codeGeneration.isLoading || codeGeneration.isStreaming) return
setIsCodePromptActive(true)
setCodePromptInput(codePromptSummary ?? '')
setCodePromptInput('')
setTimeout(() => {
codePromptInputRef.current?.focus()
}, 0)
@@ -801,7 +765,6 @@ try {
const handleCodePromptSubmit = () => {
const trimmedPrompt = codePromptInput.trim()
if (!trimmedPrompt || codeGeneration.isLoading || codeGeneration.isStreaming) return
setCodePromptSummary(trimmedPrompt)
codeGeneration.generateStream({ prompt: trimmedPrompt })
setCodePromptInput('')
setIsCodePromptActive(false)
@@ -846,19 +809,8 @@ try {
return (
<>
<Modal open={open} onOpenChange={handleClose}>
<ModalContent
size='xl'
onKeyDown={(e) => {
if (e.key === 'Escape' && (showEnvVars || showTags || showSchemaParams)) {
e.preventDefault()
e.stopPropagation()
setShowEnvVars(false)
setShowTags(false)
setShowSchemaParams(false)
}
}}
>
<Modal open={open} onOpenChange={handleCloseAttempt}>
<ModalContent size='xl'>
<ModalHeader>{isEditing ? 'Edit Agent Tool' : 'Create Agent Tool'}</ModalHeader>
<ModalTabs
@@ -1211,7 +1163,7 @@ try {
<Button
variant='tertiary'
onClick={handleSave}
disabled={!isSchemaValid || !!schemaError}
disabled={!isSchemaValid || !!schemaError || !hasChanges}
>
{isEditing ? 'Update Tool' : 'Save Tool'}
</Button>
@@ -1248,6 +1200,26 @@ try {
</ModalFooter>
</ModalContent>
</Modal>
<Modal open={showDiscardAlert} onOpenChange={setShowDiscardAlert}>
<ModalContent size='sm'>
<ModalHeader>Unsaved Changes</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-secondary)]'>
You have unsaved changes to this tool. Are you sure you want to discard your changes
and close the editor?
</p>
</ModalBody>
<ModalFooter>
<Button variant='default' onClick={() => setShowDiscardAlert(false)}>
Keep Editing
</Button>
<Button variant='destructive' onClick={handleConfirmDiscard}>
Discard Changes
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
)
}

View File

@@ -1072,7 +1072,7 @@ export function AccessControl() {
<ModalContent size='sm'>
<ModalHeader>Unsaved Changes</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
You have unsaved changes. Do you want to save them before closing?
</p>
</ModalBody>

View File

@@ -115,7 +115,7 @@ export function CreateApiKeyModal({
<ModalContent size='sm'>
<ModalHeader>Create new API key</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
{keyType === 'workspace'
? "This key will have access to all workflows in this workspace. Make sure to copy it after creation as you won't be able to see it again."
: "This key will have access to your personal workflows. Make sure to copy it after creation as you won't be able to see it again."}
@@ -218,7 +218,7 @@ export function CreateApiKeyModal({
<ModalContent size='sm'>
<ModalHeader>Your API key has been created</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
This is the only time you will see your API key.{' '}
<span className='font-semibold text-[var(--text-primary)]'>
Copy it now and store it securely.

View File

@@ -222,7 +222,7 @@ export function BYOK() {
)}
</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
This key will be used for all {PROVIDERS.find((p) => p.id === editingProvider)?.name}{' '}
requests in this workspace. Your key is encrypted and stored securely.
</p>
@@ -308,7 +308,7 @@ export function BYOK() {
<ModalContent size='sm'>
<ModalHeader>Delete API Key</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
Are you sure you want to delete the{' '}
<span className='font-medium text-[var(--text-primary)]'>
{PROVIDERS.find((p) => p.id === deleteConfirmProvider)?.name}

View File

@@ -214,7 +214,7 @@ export function Copilot() {
<ModalContent size='sm'>
<ModalHeader>Create new API key</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
This key will allow access to Copilot features. Make sure to copy it after creation as
you won't be able to see it again.
</p>
@@ -276,7 +276,7 @@ export function Copilot() {
<ModalContent size='sm'>
<ModalHeader>Your API key has been created</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
This is the only time you will see your API key.{' '}
<span className='font-semibold text-[var(--text-primary)]'>
Copy it now and store it securely.

View File

@@ -824,7 +824,7 @@ export function EnvironmentVariables({ registerBeforeLeaveHandler }: Environment
<ModalContent size='sm'>
<ModalHeader>Unsaved Changes</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
{hasConflicts || hasInvalidKeys
? `You have unsaved changes, but ${hasConflicts ? 'conflicts must be resolved' : 'invalid variable names must be fixed'} before saving. You can discard your changes to close the modal.`
: 'You have unsaved changes. Do you want to save them before closing?'}

View File

@@ -603,7 +603,7 @@ export function General({ onOpenChange }: GeneralProps) {
<ModalContent size='sm'>
<ModalHeader>Reset Password</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-tertiary)]'>
<p className='text-[12px] text-[var(--text-secondary)]'>
A password reset link will be sent to{' '}
<span className='font-medium text-[var(--text-primary)]'>{profile?.email}</span>.
Click the link in the email to create a new password.

View File

@@ -64,7 +64,7 @@ export function TeamSeats({
<ModalContent size='sm'>
<ModalHeader>{title}</ModalHeader>
<ModalBody>
<p className='text-[12px] text-[var(--text-muted)]'>{description}</p>
<p className='text-[12px] text-[var(--text-secondary)]'>{description}</p>
<div className='mt-[16px] flex flex-col gap-[4px]'>
<Label htmlFor='seats' className='text-[12px]'>

View File

@@ -25,9 +25,11 @@ const GRID_COLUMNS = 6
function ColorGrid({
hexInput,
setHexInput,
onColorChange,
}: {
hexInput: string
setHexInput: (color: string) => void
onColorChange?: (color: string) => void
}) {
const { isInFolder } = usePopoverContext()
const [focusedIndex, setFocusedIndex] = useState(-1)
@@ -72,7 +74,9 @@ function ColorGrid({
case 'Enter':
case ' ':
e.preventDefault()
e.stopPropagation()
setHexInput(WORKFLOW_COLORS[index].color)
onColorChange?.(WORKFLOW_COLORS[index].color)
return
default:
return
@@ -83,7 +87,7 @@ function ColorGrid({
buttonRefs.current[newIndex]?.focus()
}
},
[setHexInput]
[setHexInput, onColorChange]
)
return (
@@ -105,8 +109,10 @@ function ColorGrid({
onKeyDown={(e) => handleKeyDown(e, index)}
onFocus={() => setFocusedIndex(index)}
className={cn(
'h-[20px] w-[20px] rounded-[4px] focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-1 focus:ring-offset-[#1b1b1b]',
hexInput.toLowerCase() === color.toLowerCase() && 'ring-1 ring-white'
'h-[20px] w-[20px] rounded-[4px] outline-none ring-white ring-offset-0',
(focusedIndex === index ||
(focusedIndex === -1 && hexInput.toLowerCase() === color.toLowerCase())) &&
'ring-[1.5px]'
)}
style={{ backgroundColor: color }}
/>
@@ -450,7 +456,11 @@ export function ContextMenu({
>
<div className='flex w-[140px] flex-col gap-[8px] p-[2px]'>
{/* Preset colors with keyboard navigation */}
<ColorGrid hexInput={hexInput} setHexInput={setHexInput} />
<ColorGrid
hexInput={hexInput}
setHexInput={setHexInput}
onColorChange={onColorChange}
/>
{/* Hex input */}
<div className='flex items-center gap-[4px]'>

View File

@@ -459,6 +459,7 @@ export function WorkspaceHeader({
value={editingName}
onChange={(e) => setEditingName(e.target.value)}
onKeyDown={async (e) => {
e.stopPropagation()
if (e.key === 'Enter') {
e.preventDefault()
setIsListRenaming(true)

View File

@@ -460,6 +460,13 @@ const PopoverContent = React.forwardRef<
const content = contentRef.current
if (!content) return
const activeElement = document.activeElement
const isInputFocused =
activeElement instanceof HTMLInputElement ||
activeElement instanceof HTMLTextAreaElement ||
activeElement?.getAttribute('contenteditable') === 'true'
if (isInputFocused) return
const items = content.querySelectorAll<HTMLElement>(
'[role="menuitem"]:not([aria-disabled="true"])'
)

View File

@@ -755,12 +755,11 @@ export interface BulkChunkOperationParams {
}
export interface BulkChunkOperationResult {
operation: string
successCount: number
failedCount: number
results: Array<{
operation: string
chunkIds: string[]
}>
errorCount: number
processed: number
errors: string[]
}
export async function bulkChunkOperation({