From a97d933cffd150af7684436c7a573c7089467988 Mon Sep 17 00:00:00 2001 From: how2ice Date: Thu, 28 May 2026 16:11:33 +0900 Subject: [PATCH] chore: test deploy snapshot --- .../styles/MainChatPanel.conversation.css | 48 +++- src/app/main/pages/ChatSharePage.tsx | 243 +++++++++--------- 2 files changed, 163 insertions(+), 128 deletions(-) diff --git a/src/app/main/mainChatPanel/styles/MainChatPanel.conversation.css b/src/app/main/mainChatPanel/styles/MainChatPanel.conversation.css index 241a320..8f97499 100644 --- a/src/app/main/mainChatPanel/styles/MainChatPanel.conversation.css +++ b/src/app/main/mainChatPanel/styles/MainChatPanel.conversation.css @@ -2463,11 +2463,57 @@ .app-chat-preview-card--prompt .app-chat-preview-card__actions { flex: 0 0 auto; - min-width: fit-content; + min-width: 0; + max-width: 100%; flex-wrap: nowrap; margin-left: auto; } +@media (max-width: 720px) { + .app-chat-preview-card--prompt .app-chat-preview-card__header { + align-items: flex-start; + flex-wrap: wrap; + } + + .app-chat-preview-card--prompt .app-chat-preview-card__actions { + width: 100%; + flex: 1 1 100%; + justify-content: flex-start; + flex-wrap: wrap; + gap: 6px; + margin-left: 0; + } + + .app-chat-prompt-card__submitted { + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; + } + + .app-chat-prompt-card__selection-pill { + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; + } + + .app-chat-prompt-card__step-header { + flex-wrap: wrap; + } + + .app-chat-prompt-card__preview-toolbar { + flex-wrap: wrap; + align-items: flex-start; + justify-content: flex-start; + min-height: 0; + } + + .app-chat-prompt-card__preview-title.ant-typography { + flex: 1 1 100%; + } +} + .app-chat-prompt-card__preview-modal.ant-modal { background: linear-gradient(180deg, rgba(248, 250, 252, 0.98), rgba(226, 232, 240, 0.98)), diff --git a/src/app/main/pages/ChatSharePage.tsx b/src/app/main/pages/ChatSharePage.tsx index 635c732..139305a 100644 --- a/src/app/main/pages/ChatSharePage.tsx +++ b/src/app/main/pages/ChatSharePage.tsx @@ -173,6 +173,9 @@ type ShareSearchResult = { value: string; }; }; +type ShareSearchIndexedResult = ShareSearchResult & { + searchText: string; +}; type ShareSearchPanelMode = 'all' | 'apps'; type ShareWorkServerVersionStatus = 'latest' | 'unknown' | 'update-available' | 'build-required'; type ClientNotificationPermissionState = 'unsupported' | 'default' | 'granted' | 'denied'; @@ -1923,6 +1926,10 @@ function matchesSearchKeyword(keyword: string, ...values: Array normalizeSearchKeyword(value ?? '').includes(keyword)); } +function buildSearchKeywordText(...values: Array) { + return normalizeSearchKeyword(values.filter(Boolean).join(' ')); +} + function buildSharePromptSelectionKey(parentRequestId: string, sourceMessageId: number, promptIndex: number, promptTitle: string, promptSignature: string) { return [parentRequestId.trim(), sourceMessageId, promptIndex, promptTitle.trim(), promptSignature.trim()].join('::'); } @@ -8379,110 +8386,26 @@ export function ChatSharePage() { ? renderEmbeddedSharePlayApp(programTarget.appId, closeProgramTarget, normalizedToken) : null; const isServerCommandDrawerOpen = programTarget?.appId === 'server-command'; - const searchResults = useMemo(() => { - const keyword = normalizeSearchKeyword(searchKeyword); - const results: ShareSearchResult[] = []; - - if (searchPanelMode === 'apps') { - const photoprismLauncher = buildPhotoPrismProgramTarget(); - - if ( - matchesSearchKeyword( - keyword, - currentShareChatTarget.label, - currentShareChatTarget.appId, - '공유채팅', - '현재 토큰', - '현재 공유토큰 열기', - ...APPS_LAUNCHER_SEARCH_TERMS, - ) - ) { - results.push({ - key: `management-app:${SHARE_CURRENT_CHAT_APP_ID}`, - title: currentShareChatTarget.label, - description: `현재 공유토큰을 ${selectedAppEnvironment} 환경에서 다시 엽니다.`, - category: 'resource', - icon: , - usageBadge: resolveShareAppUsageBadge(appLaunchUsage[SHARE_CURRENT_CHAT_APP_ID]), - resource: currentShareChatTarget, - }); - } - - sortedAllowedManagementApps.forEach((item) => { - if (!matchesSearchKeyword(keyword, item.value, item.label, item.description, ...APPS_LAUNCHER_SEARCH_TERMS)) { - return; - } - - results.push({ - key: `management-app:${item.value}`, - title: item.label, - description: item.description, - category: 'resource', - icon: item.icon, - usageBadge: resolveShareAppUsageBadge(appLaunchUsage[item.value]), - resource: buildShareManagementProgramTarget(item.value, item.label), - }); - }); - - sortedAllowedPlayAppEntries.forEach((entry) => { - if ( - !matchesSearchKeyword( - keyword, - entry.id, - entry.name, - entry.searchDescription, - ...APPS_LAUNCHER_SEARCH_TERMS, - ...(entry.searchKeywords ?? []), - ) - ) { - return; - } - - results.push({ - key: `app:${entry.id}`, - title: entry.name, - description: resolveSupportedEnvironmentSummary(entry), - category: 'resource', - icon: entry.icon, - usageBadge: resolveShareAppUsageBadge(appLaunchUsage[entry.id]), - appEntry: entry, - resource: - entry.id === 'photoprism' - ? photoprismLauncher - : buildPlayAppProgramTarget(entry.id, entry.name), - }); - }); - - return results; - } - - if (!keyword) { - return results; - } + const indexedContentSearchResults = useMemo(() => { + const results: ShareSearchIndexedResult[] = []; sortedRequests.forEach((request) => { const requestText = buildShareVisibleText(request.userText); - if (matchesSearchKeyword(keyword, requestText, request.statusMessage, request.requestId)) { - results.push({ - key: `request:${request.requestId}`, - title: requestText || '질문', - description: `질문 · ${formatTimeLabel(request.createdAt)}`, - category: 'request', - requestId: request.requestId, - scrollTarget: { - type: 'request', - value: request.requestId, - }, - }); - } + results.push({ + key: `request:${request.requestId}`, + title: requestText || '질문', + description: `질문 · ${formatTimeLabel(request.createdAt)}`, + category: 'request', + requestId: request.requestId, + scrollTarget: { + type: 'request', + value: request.requestId, + }, + searchText: buildSearchKeywordText(requestText, request.statusMessage, request.requestId), + }); buildSharePreviewItemsFromText(request.userText, normalizedToken).forEach((item) => { - if (!matchesSearchKeyword(keyword, item.label, item.url, item.kind)) { - return; - } - - const scopedUrl = resolveShareScopedResourceUrl(item.url, normalizedToken); results.push({ key: `request-resource:${request.requestId}:${item.id}`, title: item.label, @@ -8492,7 +8415,7 @@ export function ChatSharePage() { resource: { key: `request-resource:${request.requestId}:${item.id}`, label: item.label, - url: scopedUrl, + url: item.url, kind: item.kind, meta: `${item.kind} resource`, }, @@ -8500,6 +8423,7 @@ export function ChatSharePage() { type: 'request', value: request.requestId, }, + searchText: buildSearchKeywordText(item.label, item.url, item.kind), }); }); }); @@ -8509,25 +8433,20 @@ export function ChatSharePage() { const visibleText = buildVisibleMessageText(entry, payload); const requestId = entry.clientRequestId?.trim() || snapshot?.rootRequestId?.trim() || ''; - if (matchesSearchKeyword(keyword, visibleText, entry.author, requestId)) { - results.push({ - key: `response:${entry.id}`, - title: visibleText || '응답', - description: `${entry.author === 'user' ? '질문 메시지' : '응답'} · ${formatTimeLabel(entry.timestamp)}`, - category: 'response', - requestId: requestId || undefined, - scrollTarget: { - type: 'response', - value: String(entry.id), - }, - }); - } + results.push({ + key: `response:${entry.id}`, + title: visibleText || '응답', + description: `${entry.author === 'user' ? '질문 메시지' : '응답'} · ${formatTimeLabel(entry.timestamp)}`, + category: 'response', + requestId: requestId || undefined, + scrollTarget: { + type: 'response', + value: String(entry.id), + }, + searchText: buildSearchKeywordText(visibleText, entry.author, requestId), + }); (payload?.promptParts ?? []).forEach((prompt, promptIndex) => { - if (!matchesSearchKeyword(keyword, buildSharePromptSearchText(prompt), requestId, entry.id)) { - return; - } - results.push({ key: `prompt:${entry.id}:${promptIndex}`, title: prompt.title || 'prompt', @@ -8538,15 +8457,15 @@ export function ChatSharePage() { type: 'prompt', value: buildSharePromptAnchorKey(entry.id, promptIndex), }, + searchText: buildSearchKeywordText(buildSharePromptSearchText(prompt), requestId, String(entry.id)), }); }); (payload?.previewItems ?? []).forEach((item) => { - if (!requestId || !matchesSearchKeyword(keyword, item.label, item.url, item.kind)) { + if (!requestId) { return; } - const scopedUrl = resolveShareScopedResourceUrl(item.url, normalizedToken); results.push({ key: `response-resource:${entry.id}:${item.id}`, title: item.label, @@ -8556,7 +8475,7 @@ export function ChatSharePage() { resource: { key: `response-resource:${entry.id}:${item.id}`, label: item.label, - url: scopedUrl, + url: resolveShareScopedResourceUrl(item.url, normalizedToken), kind: item.kind, meta: `${item.kind} resource`, }, @@ -8564,6 +8483,7 @@ export function ChatSharePage() { type: 'response', value: String(entry.id), }, + searchText: buildSearchKeywordText(item.label, item.url, item.kind), }); }); }); @@ -8571,10 +8491,6 @@ export function ChatSharePage() { (snapshot?.activityLogs ?? []).forEach((activity, index) => { const summary = summarizeActivityLogLines(activity.lines ?? []).join(' '); - if (!matchesSearchKeyword(keyword, activity.requestId, summary)) { - return; - } - results.push({ key: `activity:${activity.requestId}:${index}`, title: summary || `활동 로그 ${index + 1}`, @@ -8585,13 +8501,86 @@ export function ChatSharePage() { type: 'activity', value: 'chat-share-activity-panel', }, + searchText: buildSearchKeywordText(activity.requestId, summary), }); }); - return results - .filter((item) => !item.scrollTarget || item.scrollTarget.value.trim()) - .slice(0, 40); - }, [appLaunchUsage, currentShareChatTarget, messageRenderPayloadById, normalizedToken, searchKeyword, searchPanelMode, selectedAppEnvironment, snapshot?.activityLogs, snapshot?.rootRequestId, sortedAllowedManagementApps, sortedAllowedPlayAppEntries, sortedMessages, sortedRequests]); + return results.filter((item) => !item.scrollTarget || item.scrollTarget.value.trim()); + }, [messageRenderPayloadById, normalizedToken, snapshot?.activityLogs, snapshot?.rootRequestId, sortedMessages, sortedRequests]); + const indexedAppSearchResults = useMemo(() => { + const results: ShareSearchIndexedResult[] = []; + const photoprismLauncher = buildPhotoPrismProgramTarget(); + + results.push({ + key: `management-app:${SHARE_CURRENT_CHAT_APP_ID}`, + title: currentShareChatTarget.label, + description: `현재 공유토큰을 ${selectedAppEnvironment} 환경에서 다시 엽니다.`, + category: 'resource', + icon: , + usageBadge: resolveShareAppUsageBadge(appLaunchUsage[SHARE_CURRENT_CHAT_APP_ID]), + resource: currentShareChatTarget, + searchText: buildSearchKeywordText( + currentShareChatTarget.label, + currentShareChatTarget.appId, + '공유채팅', + '현재 토큰', + '현재 공유토큰 열기', + ...APPS_LAUNCHER_SEARCH_TERMS, + ), + }); + + sortedAllowedManagementApps.forEach((item) => { + results.push({ + key: `management-app:${item.value}`, + title: item.label, + description: item.description, + category: 'resource', + icon: item.icon, + usageBadge: resolveShareAppUsageBadge(appLaunchUsage[item.value]), + resource: buildShareManagementProgramTarget(item.value, item.label), + searchText: buildSearchKeywordText(item.value, item.label, item.description, ...APPS_LAUNCHER_SEARCH_TERMS), + }); + }); + + sortedAllowedPlayAppEntries.forEach((entry) => { + results.push({ + key: `app:${entry.id}`, + title: entry.name, + description: resolveSupportedEnvironmentSummary(entry), + category: 'resource', + icon: entry.icon, + usageBadge: resolveShareAppUsageBadge(appLaunchUsage[entry.id]), + appEntry: entry, + resource: + entry.id === 'photoprism' + ? photoprismLauncher + : buildPlayAppProgramTarget(entry.id, entry.name), + searchText: buildSearchKeywordText( + entry.id, + entry.name, + entry.searchDescription, + ...APPS_LAUNCHER_SEARCH_TERMS, + ...(entry.searchKeywords ?? []), + ), + }); + }); + + return results; + }, [appLaunchUsage, currentShareChatTarget, selectedAppEnvironment, sortedAllowedManagementApps, sortedAllowedPlayAppEntries]); + const searchResults = useMemo(() => { + const keyword = normalizeSearchKeyword(searchKeyword); + const source = searchPanelMode === 'apps' ? indexedAppSearchResults : indexedContentSearchResults; + + if (searchPanelMode !== 'apps' && !keyword) { + return []; + } + + const filtered = keyword + ? source.filter((item) => item.searchText.includes(keyword)) + : source; + + return filtered.slice(0, 40).map(({ searchText: _searchText, ...result }) => result); + }, [indexedAppSearchResults, indexedContentSearchResults, searchKeyword, searchPanelMode]); const selectedTokenUsageSetting = shareTokenSetting; const tokenUsageSummaryByPeriod = useMemo( () =>