@comergehq/studio 0.1.35 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +823 -386
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +832 -387
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
- package/src/components/chat/ChatMessageAttachments.tsx +243 -0
- package/src/components/chat/ChatMessageBubble.tsx +74 -24
- package/src/components/chat/ChatMessageList.tsx +4 -1
- package/src/components/chat/ChatPage.tsx +3 -0
- package/src/components/draw/DrawModeOverlay.tsx +7 -1
- package/src/components/models/types.ts +11 -0
- package/src/components/overlays/EdgeGlowFrame.tsx +7 -2
- package/src/core/services/supabase/client.ts +2 -0
- package/src/data/attachment/types.ts +2 -0
- package/src/studio/ComergeStudio.tsx +3 -0
- package/src/studio/hooks/useAttachmentUpload.ts +37 -6
- package/src/studio/hooks/useOptimisticChatMessages.ts +47 -3
- package/src/studio/hooks/useThreadMessages.ts +79 -5
- package/src/studio/ui/ChatPanel.tsx +3 -0
- package/src/studio/ui/StudioOverlay.tsx +3 -0
- package/src/studio/ui/preview-panel/PreviewRelatedAppsSection.tsx +28 -19
package/dist/index.mjs
CHANGED
|
@@ -486,8 +486,8 @@ var require_remix_x_loop_lottie = __commonJS({
|
|
|
486
486
|
});
|
|
487
487
|
|
|
488
488
|
// src/studio/ComergeStudio.tsx
|
|
489
|
-
import * as
|
|
490
|
-
import { Platform as RNPlatform, View as
|
|
489
|
+
import * as React52 from "react";
|
|
490
|
+
import { Platform as RNPlatform, View as View50 } from "react-native";
|
|
491
491
|
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
|
492
492
|
import { isSystemEventEnvelope } from "@comergehq/runtime";
|
|
493
493
|
|
|
@@ -700,6 +700,7 @@ publicApi.interceptors.request.use((config) => {
|
|
|
700
700
|
|
|
701
701
|
// src/core/services/supabase/client.ts
|
|
702
702
|
import { createClient } from "@supabase/supabase-js";
|
|
703
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
703
704
|
var clientSingleton = null;
|
|
704
705
|
var injectedClient = null;
|
|
705
706
|
var hasInjectedClient = false;
|
|
@@ -726,6 +727,7 @@ function getSupabaseClient() {
|
|
|
726
727
|
}
|
|
727
728
|
clientSingleton = createClient(runtimeConfig.url, runtimeConfig.anonKey, {
|
|
728
729
|
auth: {
|
|
730
|
+
storage: AsyncStorage,
|
|
729
731
|
autoRefreshToken: true,
|
|
730
732
|
persistSession: true,
|
|
731
733
|
detectSessionInUrl: false
|
|
@@ -1605,6 +1607,34 @@ function compareMessages(a, b) {
|
|
|
1605
1607
|
if (aMs !== bMs) return aMs - bMs;
|
|
1606
1608
|
return String(a.createdAt).localeCompare(String(b.createdAt));
|
|
1607
1609
|
}
|
|
1610
|
+
function parseAttachments(payload) {
|
|
1611
|
+
const raw = payload == null ? void 0 : payload.attachments;
|
|
1612
|
+
if (!Array.isArray(raw)) return [];
|
|
1613
|
+
const out = [];
|
|
1614
|
+
for (const item of raw) {
|
|
1615
|
+
if (!item || typeof item !== "object") continue;
|
|
1616
|
+
const id = typeof item.id === "string" ? String(item.id) : "";
|
|
1617
|
+
const name = typeof item.name === "string" ? String(item.name) : "";
|
|
1618
|
+
const mimeType = typeof item.mimeType === "string" ? String(item.mimeType) : "";
|
|
1619
|
+
const size = typeof item.size === "number" ? Number(item.size) : 0;
|
|
1620
|
+
if (!id || !name || !mimeType || !Number.isFinite(size) || size <= 0) continue;
|
|
1621
|
+
out.push({
|
|
1622
|
+
id,
|
|
1623
|
+
name,
|
|
1624
|
+
mimeType,
|
|
1625
|
+
size,
|
|
1626
|
+
uri: typeof item.downloadUrl === "string" ? String(item.downloadUrl) : void 0,
|
|
1627
|
+
width: typeof item.width === "number" ? Number(item.width) : void 0,
|
|
1628
|
+
height: typeof item.height === "number" ? Number(item.height) : void 0
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
return out;
|
|
1632
|
+
}
|
|
1633
|
+
function hasAttachmentWithoutUrl(payload) {
|
|
1634
|
+
const attachments = parseAttachments(payload);
|
|
1635
|
+
if (attachments.length === 0) return false;
|
|
1636
|
+
return attachments.some((att) => !att.uri);
|
|
1637
|
+
}
|
|
1608
1638
|
function mapMessageToChatMessage(m) {
|
|
1609
1639
|
var _a, _b;
|
|
1610
1640
|
const kind = typeof ((_a = m.payload) == null ? void 0 : _a.type) === "string" ? String(m.payload.type) : null;
|
|
@@ -1614,7 +1644,8 @@ function mapMessageToChatMessage(m) {
|
|
|
1614
1644
|
content: typeof ((_b = m.payload) == null ? void 0 : _b.content) === "string" ? m.payload.content : "",
|
|
1615
1645
|
createdAt: m.createdAt,
|
|
1616
1646
|
kind,
|
|
1617
|
-
meta: extractMeta(m.payload)
|
|
1647
|
+
meta: extractMeta(m.payload),
|
|
1648
|
+
attachments: parseAttachments(m.payload)
|
|
1618
1649
|
};
|
|
1619
1650
|
}
|
|
1620
1651
|
function useThreadMessages(threadId) {
|
|
@@ -1625,9 +1656,19 @@ function useThreadMessages(threadId) {
|
|
|
1625
1656
|
const activeRequestIdRef = React4.useRef(0);
|
|
1626
1657
|
const foregroundSignal = useForegroundSignal(Boolean(threadId));
|
|
1627
1658
|
const hasLoadedOnceRef = React4.useRef(false);
|
|
1659
|
+
const attachmentRecoveryTimerRef = React4.useRef(null);
|
|
1660
|
+
const lastAttachmentRecoveryAtRef = React4.useRef(0);
|
|
1628
1661
|
React4.useEffect(() => {
|
|
1629
1662
|
hasLoadedOnceRef.current = false;
|
|
1630
1663
|
}, [threadId]);
|
|
1664
|
+
React4.useEffect(() => {
|
|
1665
|
+
return () => {
|
|
1666
|
+
if (attachmentRecoveryTimerRef.current) {
|
|
1667
|
+
clearTimeout(attachmentRecoveryTimerRef.current);
|
|
1668
|
+
attachmentRecoveryTimerRef.current = null;
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
}, []);
|
|
1631
1672
|
const upsertSorted = React4.useCallback((prev, m) => {
|
|
1632
1673
|
const next = prev.filter((x) => x.id !== m.id);
|
|
1633
1674
|
next.push(m);
|
|
@@ -1668,29 +1709,56 @@ function useThreadMessages(threadId) {
|
|
|
1668
1709
|
}
|
|
1669
1710
|
}
|
|
1670
1711
|
}, [threadId]);
|
|
1712
|
+
const recoverAttachmentUrls = React4.useCallback(() => {
|
|
1713
|
+
if (!threadId) return;
|
|
1714
|
+
if (attachmentRecoveryTimerRef.current) return;
|
|
1715
|
+
const now = Date.now();
|
|
1716
|
+
if (now - lastAttachmentRecoveryAtRef.current < 2e3) return;
|
|
1717
|
+
attachmentRecoveryTimerRef.current = setTimeout(() => {
|
|
1718
|
+
attachmentRecoveryTimerRef.current = null;
|
|
1719
|
+
lastAttachmentRecoveryAtRef.current = Date.now();
|
|
1720
|
+
void refetch({ background: true });
|
|
1721
|
+
}, 250);
|
|
1722
|
+
}, [refetch, threadId]);
|
|
1671
1723
|
React4.useEffect(() => {
|
|
1672
1724
|
void refetch();
|
|
1673
1725
|
}, [refetch]);
|
|
1674
1726
|
React4.useEffect(() => {
|
|
1675
1727
|
if (!threadId) return;
|
|
1676
1728
|
const unsubscribe = messagesRepository.subscribeThread(threadId, {
|
|
1677
|
-
onInsert: (m) =>
|
|
1678
|
-
|
|
1729
|
+
onInsert: (m) => {
|
|
1730
|
+
setRaw((prev) => upsertSorted(prev, m));
|
|
1731
|
+
if (hasAttachmentWithoutUrl(m.payload)) {
|
|
1732
|
+
recoverAttachmentUrls();
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1735
|
+
onUpdate: (m) => {
|
|
1736
|
+
setRaw((prev) => upsertSorted(prev, m));
|
|
1737
|
+
if (hasAttachmentWithoutUrl(m.payload)) {
|
|
1738
|
+
recoverAttachmentUrls();
|
|
1739
|
+
}
|
|
1740
|
+
},
|
|
1679
1741
|
onDelete: (m) => setRaw((prev) => prev.filter((x) => x.id !== m.id))
|
|
1680
1742
|
});
|
|
1681
1743
|
return unsubscribe;
|
|
1682
|
-
}, [threadId, upsertSorted, foregroundSignal]);
|
|
1744
|
+
}, [threadId, upsertSorted, foregroundSignal, recoverAttachmentUrls]);
|
|
1683
1745
|
React4.useEffect(() => {
|
|
1684
1746
|
if (!threadId) return;
|
|
1685
1747
|
if (foregroundSignal <= 0) return;
|
|
1686
1748
|
void refetch({ background: true });
|
|
1687
1749
|
}, [foregroundSignal, refetch, threadId]);
|
|
1750
|
+
React4.useEffect(() => {
|
|
1751
|
+
if (!threadId) return;
|
|
1752
|
+
if (raw.length === 0) return;
|
|
1753
|
+
if (!raw.some((m) => hasAttachmentWithoutUrl(m.payload))) return;
|
|
1754
|
+
recoverAttachmentUrls();
|
|
1755
|
+
}, [raw, recoverAttachmentUrls, threadId]);
|
|
1688
1756
|
const messages = React4.useMemo(() => {
|
|
1689
1757
|
const visible = raw.filter((m) => !isQueuedHiddenMessage(m));
|
|
1690
1758
|
const resolved = visible.length > 0 ? visible : raw;
|
|
1691
1759
|
return resolved.map(mapMessageToChatMessage);
|
|
1692
1760
|
}, [raw]);
|
|
1693
|
-
return { raw, messages, loading, refreshing, error, refetch };
|
|
1761
|
+
return { raw, messages, loading, refreshing, error, refetch, recoverAttachmentUrls };
|
|
1694
1762
|
}
|
|
1695
1763
|
|
|
1696
1764
|
// src/studio/hooks/useBundleManager.ts
|
|
@@ -2857,7 +2925,7 @@ function useMergeRequests(params) {
|
|
|
2857
2925
|
|
|
2858
2926
|
// src/studio/hooks/useAttachmentUpload.ts
|
|
2859
2927
|
import * as React7 from "react";
|
|
2860
|
-
import { Platform as Platform2 } from "react-native";
|
|
2928
|
+
import { Image, Platform as Platform2 } from "react-native";
|
|
2861
2929
|
import * as FileSystem2 from "expo-file-system/legacy";
|
|
2862
2930
|
|
|
2863
2931
|
// src/data/attachment/remote.ts
|
|
@@ -2953,6 +3021,23 @@ function getMimeTypeFromDataUrl(dataUrl) {
|
|
|
2953
3021
|
const mimeMatch = header.match(/data:(.*?);base64/i);
|
|
2954
3022
|
return (mimeMatch == null ? void 0 : mimeMatch[1]) ?? "image/png";
|
|
2955
3023
|
}
|
|
3024
|
+
async function getImageDimensionsFromDataUrl(dataUrl) {
|
|
3025
|
+
try {
|
|
3026
|
+
const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
|
|
3027
|
+
const dims = await new Promise((resolve, reject) => {
|
|
3028
|
+
Image.getSize(
|
|
3029
|
+
normalized,
|
|
3030
|
+
(width, height) => resolve({ width, height }),
|
|
3031
|
+
(err) => reject(err)
|
|
3032
|
+
);
|
|
3033
|
+
});
|
|
3034
|
+
if (dims.width > 0 && dims.height > 0) {
|
|
3035
|
+
return { width: Math.round(dims.width), height: Math.round(dims.height) };
|
|
3036
|
+
}
|
|
3037
|
+
} catch {
|
|
3038
|
+
}
|
|
3039
|
+
return {};
|
|
3040
|
+
}
|
|
2956
3041
|
function useAttachmentUpload() {
|
|
2957
3042
|
const [uploading, setUploading] = React7.useState(false);
|
|
2958
3043
|
const [error, setError] = React7.useState(null);
|
|
@@ -2967,17 +3052,24 @@ function useAttachmentUpload() {
|
|
|
2967
3052
|
const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
|
|
2968
3053
|
const blob = Platform2.OS === "android" ? await dataUrlToBlobAndroid(normalized) : await (await fetch(normalized)).blob();
|
|
2969
3054
|
const mimeType = getMimeTypeFromDataUrl(normalized);
|
|
2970
|
-
|
|
3055
|
+
const dimensions = mimeType.startsWith("image/") ? await getImageDimensionsFromDataUrl(normalized) : {};
|
|
3056
|
+
return { blob, idx, mimeType, ...dimensions };
|
|
2971
3057
|
})
|
|
2972
3058
|
);
|
|
2973
|
-
const files = blobs.map(({ blob, mimeType }, idx) => ({
|
|
3059
|
+
const files = blobs.map(({ blob, mimeType, width, height }, idx) => ({
|
|
2974
3060
|
name: `attachment-${Date.now()}-${idx}.png`,
|
|
2975
3061
|
size: blob.size,
|
|
2976
|
-
mimeType
|
|
3062
|
+
mimeType,
|
|
3063
|
+
width,
|
|
3064
|
+
height
|
|
2977
3065
|
}));
|
|
2978
3066
|
const presign = await attachmentRepository.presign({ threadId, appId, files });
|
|
2979
3067
|
await Promise.all(presign.uploads.map((u, index) => attachmentRepository.upload(u, blobs[index].blob)));
|
|
2980
|
-
return presign.uploads.map((u) =>
|
|
3068
|
+
return presign.uploads.map((u, index) => ({
|
|
3069
|
+
...u.attachment,
|
|
3070
|
+
width: blobs[index].width,
|
|
3071
|
+
height: blobs[index].height
|
|
3072
|
+
}));
|
|
2981
3073
|
} catch (e) {
|
|
2982
3074
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
2983
3075
|
setError(err);
|
|
@@ -2996,13 +3088,16 @@ function useAttachmentUpload() {
|
|
|
2996
3088
|
const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
|
|
2997
3089
|
const blob = Platform2.OS === "android" ? await dataUrlToBlobAndroid(normalized) : await (await fetch(normalized)).blob();
|
|
2998
3090
|
const mimeType = getMimeTypeFromDataUrl(normalized);
|
|
2999
|
-
|
|
3091
|
+
const dimensions = mimeType.startsWith("image/") ? await getImageDimensionsFromDataUrl(normalized) : {};
|
|
3092
|
+
return { blob, mimeType, ...dimensions };
|
|
3000
3093
|
})
|
|
3001
3094
|
);
|
|
3002
|
-
const files = blobs.map(({ blob, mimeType }, idx) => ({
|
|
3095
|
+
const files = blobs.map(({ blob, mimeType, width, height }, idx) => ({
|
|
3003
3096
|
name: `attachment-${Date.now()}-${idx}.png`,
|
|
3004
3097
|
size: blob.size,
|
|
3005
|
-
mimeType
|
|
3098
|
+
mimeType,
|
|
3099
|
+
width,
|
|
3100
|
+
height
|
|
3006
3101
|
}));
|
|
3007
3102
|
const presign = await attachmentRepository.stagePresign({ files });
|
|
3008
3103
|
await Promise.all(presign.uploads.map((u, index) => attachmentRepository.uploadStaged(u, blobs[index].blob)));
|
|
@@ -3285,8 +3380,8 @@ function RuntimeRenderer({
|
|
|
3285
3380
|
}
|
|
3286
3381
|
|
|
3287
3382
|
// src/studio/ui/StudioOverlay.tsx
|
|
3288
|
-
import * as
|
|
3289
|
-
import { InteractionManager, Keyboard as Keyboard5, Platform as Platform11, View as
|
|
3383
|
+
import * as React47 from "react";
|
|
3384
|
+
import { InteractionManager, Keyboard as Keyboard5, Platform as Platform11, View as View49, useWindowDimensions as useWindowDimensions5 } from "react-native";
|
|
3290
3385
|
|
|
3291
3386
|
// src/components/studio-sheet/StudioBottomSheet.tsx
|
|
3292
3387
|
import * as React12 from "react";
|
|
@@ -3845,6 +3940,7 @@ function EdgeGlowFrame({
|
|
|
3845
3940
|
role = "accent",
|
|
3846
3941
|
thickness = 40,
|
|
3847
3942
|
intensity = 1,
|
|
3943
|
+
animationDurationMs = 300,
|
|
3848
3944
|
style
|
|
3849
3945
|
}) {
|
|
3850
3946
|
const theme = useTheme();
|
|
@@ -3853,10 +3949,10 @@ function EdgeGlowFrame({
|
|
|
3853
3949
|
React14.useEffect(() => {
|
|
3854
3950
|
Animated3.timing(anim, {
|
|
3855
3951
|
toValue: visible ? 1 : 0,
|
|
3856
|
-
duration:
|
|
3952
|
+
duration: animationDurationMs,
|
|
3857
3953
|
useNativeDriver: true
|
|
3858
3954
|
}).start();
|
|
3859
|
-
}, [anim, visible]);
|
|
3955
|
+
}, [anim, visible, animationDurationMs]);
|
|
3860
3956
|
const c = baseColor(role, theme);
|
|
3861
3957
|
const strong = withAlpha(c, 0.6 * alpha);
|
|
3862
3958
|
const soft = withAlpha(c, 0.22 * alpha);
|
|
@@ -4382,7 +4478,16 @@ function DrawModeOverlay({
|
|
|
4382
4478
|
}, [captureTargetRef, capturing, onCapture]);
|
|
4383
4479
|
if (!visible) return null;
|
|
4384
4480
|
return /* @__PURE__ */ jsxs7(View10, { style: [StyleSheet3.absoluteFill, styles3.root, style], pointerEvents: "box-none", children: [
|
|
4385
|
-
/* @__PURE__ */ jsx14(
|
|
4481
|
+
/* @__PURE__ */ jsx14(
|
|
4482
|
+
EdgeGlowFrame,
|
|
4483
|
+
{
|
|
4484
|
+
visible: !hideUi,
|
|
4485
|
+
role: "danger",
|
|
4486
|
+
thickness: 50,
|
|
4487
|
+
intensity: 1,
|
|
4488
|
+
animationDurationMs: hideUi ? 0 : 300
|
|
4489
|
+
}
|
|
4490
|
+
),
|
|
4386
4491
|
/* @__PURE__ */ jsx14(
|
|
4387
4492
|
DrawSurface,
|
|
4388
4493
|
{
|
|
@@ -4436,7 +4541,7 @@ import {
|
|
|
4436
4541
|
ActivityIndicator as ActivityIndicator2,
|
|
4437
4542
|
Animated as Animated5,
|
|
4438
4543
|
Dimensions,
|
|
4439
|
-
Image,
|
|
4544
|
+
Image as Image2,
|
|
4440
4545
|
Pressable as Pressable4,
|
|
4441
4546
|
ScrollView,
|
|
4442
4547
|
View as View11
|
|
@@ -4538,7 +4643,7 @@ function AspectRatioThumbnail({
|
|
|
4538
4643
|
const [aspectRatio, setAspectRatio] = React19.useState(1);
|
|
4539
4644
|
return /* @__PURE__ */ jsxs8(View11, { style: { height: THUMBNAIL_HEIGHT, aspectRatio, position: "relative" }, children: [
|
|
4540
4645
|
/* @__PURE__ */ jsx17(View11, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ jsx17(
|
|
4541
|
-
|
|
4646
|
+
Image2,
|
|
4542
4647
|
{
|
|
4543
4648
|
source: { uri },
|
|
4544
4649
|
style: { width: "100%", height: "100%" },
|
|
@@ -4747,7 +4852,7 @@ import * as React20 from "react";
|
|
|
4747
4852
|
import { View as View13 } from "react-native";
|
|
4748
4853
|
|
|
4749
4854
|
// src/components/primitives/Avatar.tsx
|
|
4750
|
-
import { Image as
|
|
4855
|
+
import { Image as Image3, View as View12 } from "react-native";
|
|
4751
4856
|
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
4752
4857
|
function initialsFrom(name) {
|
|
4753
4858
|
var _a, _b;
|
|
@@ -4782,7 +4887,7 @@ function Avatar({
|
|
|
4782
4887
|
style
|
|
4783
4888
|
],
|
|
4784
4889
|
children: uri ? /* @__PURE__ */ jsx18(
|
|
4785
|
-
|
|
4890
|
+
Image3,
|
|
4786
4891
|
{
|
|
4787
4892
|
source: { uri },
|
|
4788
4893
|
style: [{ width: size, height: size }, imageStyle],
|
|
@@ -5587,12 +5692,12 @@ function PreviewPlaceholder({ visible, style }) {
|
|
|
5587
5692
|
}
|
|
5588
5693
|
|
|
5589
5694
|
// src/components/preview/PreviewImage.tsx
|
|
5590
|
-
import { Image as
|
|
5695
|
+
import { Image as Image4 } from "react-native";
|
|
5591
5696
|
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
5592
5697
|
function PreviewImage({ uri, onLoad, style }) {
|
|
5593
5698
|
if (!uri) return null;
|
|
5594
5699
|
return /* @__PURE__ */ jsx29(
|
|
5595
|
-
|
|
5700
|
+
Image4,
|
|
5596
5701
|
{
|
|
5597
5702
|
source: { uri },
|
|
5598
5703
|
resizeMode: "cover",
|
|
@@ -5819,7 +5924,7 @@ function PreviewHeroSection({
|
|
|
5819
5924
|
|
|
5820
5925
|
// src/studio/ui/preview-panel/PreviewRelatedAppsSection.tsx
|
|
5821
5926
|
import * as React27 from "react";
|
|
5822
|
-
import { ActivityIndicator as ActivityIndicator4, Pressable as Pressable9, ScrollView as ScrollView2, View as View24 } from "react-native";
|
|
5927
|
+
import { ActivityIndicator as ActivityIndicator4, Pressable as Pressable9, ScrollView as ScrollView2, View as View24, useWindowDimensions as useWindowDimensions3 } from "react-native";
|
|
5823
5928
|
|
|
5824
5929
|
// src/components/primitives/Modal.tsx
|
|
5825
5930
|
import {
|
|
@@ -5907,7 +6012,10 @@ function PreviewRelatedAppsSection({
|
|
|
5907
6012
|
}) {
|
|
5908
6013
|
var _a;
|
|
5909
6014
|
const theme = useTheme();
|
|
6015
|
+
const { height: windowHeight } = useWindowDimensions3();
|
|
5910
6016
|
const [relatedAppsOpen, setRelatedAppsOpen] = React27.useState(false);
|
|
6017
|
+
const modalMaxHeight = Math.max(240, windowHeight * 0.5);
|
|
6018
|
+
const modalScrollMaxHeight = Math.max(140, modalMaxHeight - 96);
|
|
5911
6019
|
const relatedAppItems = React27.useMemo(() => {
|
|
5912
6020
|
if (!relatedApps) return [];
|
|
5913
6021
|
const items = [];
|
|
@@ -6040,10 +6148,7 @@ function PreviewRelatedAppsSection({
|
|
|
6040
6148
|
}
|
|
6041
6149
|
)
|
|
6042
6150
|
] }),
|
|
6043
|
-
/* @__PURE__ */
|
|
6044
|
-
/* @__PURE__ */ jsx36(View24, { style: { minHeight: 20, justifyContent: "center" }, children: item.app.status !== "ready" ? /* @__PURE__ */ jsx36(PreviewStatusBadge, { status: item.app.status }) : null }),
|
|
6045
|
-
isSwitching ? /* @__PURE__ */ jsx36(ActivityIndicator4, { size: "small", color: theme.colors.primary }) : null
|
|
6046
|
-
] })
|
|
6151
|
+
/* @__PURE__ */ jsx36(View24, { style: { alignItems: "flex-end", gap: 6 }, children: isSwitching ? /* @__PURE__ */ jsx36(ActivityIndicator4, { size: "small", color: theme.colors.primary }) : null })
|
|
6047
6152
|
] })
|
|
6048
6153
|
},
|
|
6049
6154
|
item.app.id
|
|
@@ -6086,17 +6191,35 @@ function PreviewRelatedAppsSection({
|
|
|
6086
6191
|
children: inlineItems.map((item) => renderRelatedCard(item))
|
|
6087
6192
|
}
|
|
6088
6193
|
),
|
|
6089
|
-
/* @__PURE__ */ jsx36(
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6194
|
+
/* @__PURE__ */ jsx36(
|
|
6195
|
+
Modal,
|
|
6196
|
+
{
|
|
6197
|
+
visible: relatedAppsOpen,
|
|
6198
|
+
onRequestClose: closeRelatedApps,
|
|
6199
|
+
contentStyle: { maxHeight: modalMaxHeight, overflow: "hidden" },
|
|
6200
|
+
children: /* @__PURE__ */ jsxs19(View24, { style: { gap: theme.spacing.sm, minHeight: 0 }, children: [
|
|
6201
|
+
/* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.text, fontSize: 18, fontWeight: theme.typography.fontWeight.semibold }, children: "Related apps" }),
|
|
6202
|
+
/* @__PURE__ */ jsxs19(
|
|
6203
|
+
ScrollView2,
|
|
6204
|
+
{
|
|
6205
|
+
style: { maxHeight: modalScrollMaxHeight },
|
|
6206
|
+
contentContainerStyle: { paddingBottom: theme.spacing.xs, gap: theme.spacing.sm },
|
|
6207
|
+
showsVerticalScrollIndicator: true,
|
|
6208
|
+
children: [
|
|
6209
|
+
sectionedRelatedApps.original.length > 0 ? /* @__PURE__ */ jsxs19(View24, { children: [
|
|
6210
|
+
/* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.textMuted, marginBottom: theme.spacing.xs }, children: "Original" }),
|
|
6211
|
+
sectionedRelatedApps.original.map((item) => renderRelatedCard(item, { fullWidth: true }))
|
|
6212
|
+
] }) : null,
|
|
6213
|
+
sectionedRelatedApps.remixes.length > 0 ? /* @__PURE__ */ jsxs19(View24, { children: [
|
|
6214
|
+
/* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.textMuted, marginBottom: theme.spacing.xs }, children: "Remixes" }),
|
|
6215
|
+
sectionedRelatedApps.remixes.map((item) => renderRelatedCard(item, { fullWidth: true }))
|
|
6216
|
+
] }) : null
|
|
6217
|
+
]
|
|
6218
|
+
}
|
|
6219
|
+
)
|
|
6220
|
+
] })
|
|
6221
|
+
}
|
|
6222
|
+
)
|
|
6100
6223
|
] });
|
|
6101
6224
|
}
|
|
6102
6225
|
|
|
@@ -6713,7 +6836,7 @@ function MergeRequestStatusCard({
|
|
|
6713
6836
|
|
|
6714
6837
|
// src/components/merge-requests/ReviewMergeRequestCarousel.tsx
|
|
6715
6838
|
import * as React32 from "react";
|
|
6716
|
-
import { Animated as Animated9, FlatList, View as View33, useWindowDimensions as
|
|
6839
|
+
import { Animated as Animated9, FlatList, View as View33, useWindowDimensions as useWindowDimensions4 } from "react-native";
|
|
6717
6840
|
|
|
6718
6841
|
// src/components/merge-requests/ReviewMergeRequestCard.tsx
|
|
6719
6842
|
import * as React31 from "react";
|
|
@@ -6928,7 +7051,7 @@ function ReviewMergeRequestCarousel({
|
|
|
6928
7051
|
style
|
|
6929
7052
|
}) {
|
|
6930
7053
|
const theme = useTheme();
|
|
6931
|
-
const { width } =
|
|
7054
|
+
const { width } = useWindowDimensions4();
|
|
6932
7055
|
const [expanded, setExpanded] = React32.useState({});
|
|
6933
7056
|
const carouselScrollX = React32.useRef(new Animated9.Value(0)).current;
|
|
6934
7057
|
const peekAmount = 24;
|
|
@@ -7669,22 +7792,22 @@ ${shareUrl}`;
|
|
|
7669
7792
|
}
|
|
7670
7793
|
|
|
7671
7794
|
// src/studio/ui/ChatPanel.tsx
|
|
7672
|
-
import * as
|
|
7673
|
-
import { ActivityIndicator as ActivityIndicator10, View as
|
|
7795
|
+
import * as React44 from "react";
|
|
7796
|
+
import { ActivityIndicator as ActivityIndicator10, View as View47 } from "react-native";
|
|
7674
7797
|
|
|
7675
7798
|
// src/components/chat/ChatPage.tsx
|
|
7676
|
-
import * as
|
|
7677
|
-
import { Platform as Platform10, View as
|
|
7799
|
+
import * as React41 from "react";
|
|
7800
|
+
import { Platform as Platform10, View as View40 } from "react-native";
|
|
7678
7801
|
import { useSafeAreaInsets as useSafeAreaInsets4 } from "react-native-safe-area-context";
|
|
7679
7802
|
|
|
7680
7803
|
// src/components/chat/ChatMessageList.tsx
|
|
7681
|
-
import * as
|
|
7682
|
-
import { View as
|
|
7804
|
+
import * as React40 from "react";
|
|
7805
|
+
import { View as View39 } from "react-native";
|
|
7683
7806
|
import { BottomSheetFlatList } from "@gorhom/bottom-sheet";
|
|
7684
7807
|
|
|
7685
7808
|
// src/components/chat/ChatMessageBubble.tsx
|
|
7686
|
-
import * as
|
|
7687
|
-
import { View as
|
|
7809
|
+
import * as React38 from "react";
|
|
7810
|
+
import { View as View37 } from "react-native";
|
|
7688
7811
|
import { CheckCheck as CheckCheck2, GitMerge as GitMerge2, RotateCcw } from "lucide-react-native";
|
|
7689
7812
|
|
|
7690
7813
|
// src/components/primitives/Button.tsx
|
|
@@ -7752,19 +7875,269 @@ function Button({
|
|
|
7752
7875
|
);
|
|
7753
7876
|
}
|
|
7754
7877
|
|
|
7878
|
+
// src/components/chat/ChatMessageAttachments.tsx
|
|
7879
|
+
import * as React37 from "react";
|
|
7880
|
+
import {
|
|
7881
|
+
Animated as Animated10,
|
|
7882
|
+
Dimensions as Dimensions3,
|
|
7883
|
+
FlatList as FlatList2,
|
|
7884
|
+
Modal as Modal3,
|
|
7885
|
+
Pressable as Pressable16,
|
|
7886
|
+
StyleSheet as StyleSheet4,
|
|
7887
|
+
View as View36
|
|
7888
|
+
} from "react-native";
|
|
7889
|
+
import { Image as ExpoImage } from "expo-image";
|
|
7890
|
+
import { Fragment as Fragment7, jsx as jsx49, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
7891
|
+
function ChatMessageAttachments({
|
|
7892
|
+
messageId,
|
|
7893
|
+
attachments,
|
|
7894
|
+
align = "left",
|
|
7895
|
+
onAttachmentLoadError
|
|
7896
|
+
}) {
|
|
7897
|
+
const theme = useTheme();
|
|
7898
|
+
const [viewerVisible, setViewerVisible] = React37.useState(false);
|
|
7899
|
+
const [viewerIndex, setViewerIndex] = React37.useState(0);
|
|
7900
|
+
const failedKeysRef = React37.useRef(/* @__PURE__ */ new Set());
|
|
7901
|
+
const [loadingById, setLoadingById] = React37.useState({});
|
|
7902
|
+
const [modalLoadingById, setModalLoadingById] = React37.useState({});
|
|
7903
|
+
const pulse = React37.useRef(new Animated10.Value(0.45)).current;
|
|
7904
|
+
const imageAttachments = React37.useMemo(
|
|
7905
|
+
() => attachments.filter(
|
|
7906
|
+
(att) => att.mimeType.startsWith("image/") && typeof att.uri === "string" && att.uri.length > 0
|
|
7907
|
+
),
|
|
7908
|
+
[attachments]
|
|
7909
|
+
);
|
|
7910
|
+
const itemHeight = imageAttachments.length === 1 ? 180 : 124;
|
|
7911
|
+
const maxItemWidth = imageAttachments.length === 1 ? 280 : 180;
|
|
7912
|
+
const getAspectRatio = (att) => {
|
|
7913
|
+
const width = typeof att.width === "number" ? att.width : 0;
|
|
7914
|
+
const height = typeof att.height === "number" ? att.height : 0;
|
|
7915
|
+
if (width > 0 && height > 0) {
|
|
7916
|
+
return Math.max(0.35, Math.min(2.4, width / height));
|
|
7917
|
+
}
|
|
7918
|
+
return 0.8;
|
|
7919
|
+
};
|
|
7920
|
+
React37.useEffect(() => {
|
|
7921
|
+
Animated10.loop(
|
|
7922
|
+
Animated10.sequence([
|
|
7923
|
+
Animated10.timing(pulse, { toValue: 0.85, duration: 650, useNativeDriver: true }),
|
|
7924
|
+
Animated10.timing(pulse, { toValue: 0.45, duration: 650, useNativeDriver: true })
|
|
7925
|
+
])
|
|
7926
|
+
).start();
|
|
7927
|
+
}, [pulse]);
|
|
7928
|
+
React37.useEffect(() => {
|
|
7929
|
+
if (imageAttachments.length === 0) {
|
|
7930
|
+
setLoadingById({});
|
|
7931
|
+
setModalLoadingById({});
|
|
7932
|
+
return;
|
|
7933
|
+
}
|
|
7934
|
+
setLoadingById((prev) => {
|
|
7935
|
+
const next = {};
|
|
7936
|
+
for (const att of imageAttachments) {
|
|
7937
|
+
next[att.id] = prev[att.id] ?? true;
|
|
7938
|
+
}
|
|
7939
|
+
return next;
|
|
7940
|
+
});
|
|
7941
|
+
}, [imageAttachments]);
|
|
7942
|
+
React37.useEffect(() => {
|
|
7943
|
+
if (!viewerVisible) return;
|
|
7944
|
+
if (imageAttachments.length === 0) {
|
|
7945
|
+
setModalLoadingById({});
|
|
7946
|
+
return;
|
|
7947
|
+
}
|
|
7948
|
+
setModalLoadingById(() => {
|
|
7949
|
+
const next = {};
|
|
7950
|
+
for (const att of imageAttachments) {
|
|
7951
|
+
next[att.id] = true;
|
|
7952
|
+
}
|
|
7953
|
+
return next;
|
|
7954
|
+
});
|
|
7955
|
+
}, [viewerVisible, imageAttachments]);
|
|
7956
|
+
if (imageAttachments.length === 0) return null;
|
|
7957
|
+
const handleError = (attachmentId) => {
|
|
7958
|
+
const key = `${messageId}:${attachmentId}`;
|
|
7959
|
+
if (failedKeysRef.current.has(key)) return;
|
|
7960
|
+
failedKeysRef.current.add(key);
|
|
7961
|
+
onAttachmentLoadError == null ? void 0 : onAttachmentLoadError(messageId, attachmentId);
|
|
7962
|
+
};
|
|
7963
|
+
return /* @__PURE__ */ jsxs30(Fragment7, { children: [
|
|
7964
|
+
/* @__PURE__ */ jsx49(
|
|
7965
|
+
View36,
|
|
7966
|
+
{
|
|
7967
|
+
style: {
|
|
7968
|
+
flexDirection: "row",
|
|
7969
|
+
flexWrap: "wrap",
|
|
7970
|
+
justifyContent: align === "right" ? "flex-end" : "flex-start",
|
|
7971
|
+
alignSelf: align === "right" ? "flex-end" : "flex-start",
|
|
7972
|
+
gap: theme.spacing.sm,
|
|
7973
|
+
marginBottom: theme.spacing.sm
|
|
7974
|
+
},
|
|
7975
|
+
children: imageAttachments.map((att, index) => /* @__PURE__ */ jsxs30(
|
|
7976
|
+
Pressable16,
|
|
7977
|
+
{
|
|
7978
|
+
onPress: () => {
|
|
7979
|
+
setViewerIndex(index);
|
|
7980
|
+
setViewerVisible(true);
|
|
7981
|
+
},
|
|
7982
|
+
accessibilityRole: "button",
|
|
7983
|
+
accessibilityLabel: `Attachment ${index + 1} of ${imageAttachments.length}`,
|
|
7984
|
+
style: {
|
|
7985
|
+
height: itemHeight,
|
|
7986
|
+
aspectRatio: getAspectRatio(att),
|
|
7987
|
+
maxWidth: maxItemWidth,
|
|
7988
|
+
borderRadius: theme.radii.lg,
|
|
7989
|
+
overflow: "hidden"
|
|
7990
|
+
},
|
|
7991
|
+
children: [
|
|
7992
|
+
loadingById[att.id] ? /* @__PURE__ */ jsx49(
|
|
7993
|
+
Animated10.View,
|
|
7994
|
+
{
|
|
7995
|
+
style: {
|
|
7996
|
+
...StyleSheet4.absoluteFillObject,
|
|
7997
|
+
opacity: pulse,
|
|
7998
|
+
backgroundColor: theme.colors.border
|
|
7999
|
+
}
|
|
8000
|
+
}
|
|
8001
|
+
) : null,
|
|
8002
|
+
/* @__PURE__ */ jsx49(
|
|
8003
|
+
ExpoImage,
|
|
8004
|
+
{
|
|
8005
|
+
source: { uri: att.uri },
|
|
8006
|
+
style: { width: "100%", height: "100%" },
|
|
8007
|
+
contentFit: "contain",
|
|
8008
|
+
transition: 140,
|
|
8009
|
+
cachePolicy: "memory-disk",
|
|
8010
|
+
onLoadStart: () => {
|
|
8011
|
+
setLoadingById((prev) => ({ ...prev, [att.id]: true }));
|
|
8012
|
+
},
|
|
8013
|
+
onLoadEnd: () => {
|
|
8014
|
+
setLoadingById((prev) => ({ ...prev, [att.id]: false }));
|
|
8015
|
+
},
|
|
8016
|
+
onError: () => handleError(att.id)
|
|
8017
|
+
}
|
|
8018
|
+
)
|
|
8019
|
+
]
|
|
8020
|
+
},
|
|
8021
|
+
att.id
|
|
8022
|
+
))
|
|
8023
|
+
}
|
|
8024
|
+
),
|
|
8025
|
+
/* @__PURE__ */ jsx49(Modal3, { visible: viewerVisible, transparent: true, animationType: "fade", onRequestClose: () => setViewerVisible(false), children: /* @__PURE__ */ jsxs30(View36, { style: { flex: 1, backgroundColor: "rgba(0,0,0,0.95)" }, children: [
|
|
8026
|
+
/* @__PURE__ */ jsx49(
|
|
8027
|
+
View36,
|
|
8028
|
+
{
|
|
8029
|
+
style: {
|
|
8030
|
+
position: "absolute",
|
|
8031
|
+
top: 56,
|
|
8032
|
+
right: 16,
|
|
8033
|
+
zIndex: 2
|
|
8034
|
+
},
|
|
8035
|
+
children: /* @__PURE__ */ jsx49(
|
|
8036
|
+
Pressable16,
|
|
8037
|
+
{
|
|
8038
|
+
accessibilityRole: "button",
|
|
8039
|
+
accessibilityLabel: "Close attachment viewer",
|
|
8040
|
+
onPress: () => setViewerVisible(false),
|
|
8041
|
+
style: {
|
|
8042
|
+
width: 44,
|
|
8043
|
+
height: 44,
|
|
8044
|
+
borderRadius: 22,
|
|
8045
|
+
alignItems: "center",
|
|
8046
|
+
justifyContent: "center",
|
|
8047
|
+
backgroundColor: "rgba(255,255,255,0.15)"
|
|
8048
|
+
},
|
|
8049
|
+
children: /* @__PURE__ */ jsx49(IconClose, { size: 18, colorToken: "onPrimary" })
|
|
8050
|
+
}
|
|
8051
|
+
)
|
|
8052
|
+
}
|
|
8053
|
+
),
|
|
8054
|
+
/* @__PURE__ */ jsx49(
|
|
8055
|
+
FlatList2,
|
|
8056
|
+
{
|
|
8057
|
+
data: imageAttachments,
|
|
8058
|
+
horizontal: true,
|
|
8059
|
+
pagingEnabled: true,
|
|
8060
|
+
initialScrollIndex: viewerIndex,
|
|
8061
|
+
keyExtractor: (item) => item.id,
|
|
8062
|
+
showsHorizontalScrollIndicator: false,
|
|
8063
|
+
getItemLayout: (_, index) => {
|
|
8064
|
+
const width = Dimensions3.get("window").width;
|
|
8065
|
+
return { length: width, offset: width * index, index };
|
|
8066
|
+
},
|
|
8067
|
+
renderItem: ({ item, index }) => /* @__PURE__ */ jsxs30(View36, { style: { width: Dimensions3.get("window").width, height: "100%", justifyContent: "center" }, children: [
|
|
8068
|
+
modalLoadingById[item.id] ? /* @__PURE__ */ jsx49(
|
|
8069
|
+
Animated10.View,
|
|
8070
|
+
{
|
|
8071
|
+
style: {
|
|
8072
|
+
...StyleSheet4.absoluteFillObject,
|
|
8073
|
+
opacity: pulse,
|
|
8074
|
+
backgroundColor: theme.colors.border
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
) : null,
|
|
8078
|
+
/* @__PURE__ */ jsx49(
|
|
8079
|
+
ExpoImage,
|
|
8080
|
+
{
|
|
8081
|
+
source: { uri: item.uri },
|
|
8082
|
+
style: { width: "100%", height: "78%" },
|
|
8083
|
+
contentFit: "contain",
|
|
8084
|
+
transition: 140,
|
|
8085
|
+
cachePolicy: "memory-disk",
|
|
8086
|
+
onLoadStart: () => {
|
|
8087
|
+
setModalLoadingById((prev) => ({ ...prev, [item.id]: true }));
|
|
8088
|
+
},
|
|
8089
|
+
onLoadEnd: () => {
|
|
8090
|
+
setModalLoadingById((prev) => ({ ...prev, [item.id]: false }));
|
|
8091
|
+
},
|
|
8092
|
+
onError: () => handleError(item.id)
|
|
8093
|
+
}
|
|
8094
|
+
),
|
|
8095
|
+
/* @__PURE__ */ jsxs30(
|
|
8096
|
+
Text,
|
|
8097
|
+
{
|
|
8098
|
+
variant: "caption",
|
|
8099
|
+
color: "#FFFFFF",
|
|
8100
|
+
style: { textAlign: "center", marginTop: theme.spacing.sm },
|
|
8101
|
+
children: [
|
|
8102
|
+
index + 1,
|
|
8103
|
+
" / ",
|
|
8104
|
+
imageAttachments.length
|
|
8105
|
+
]
|
|
8106
|
+
}
|
|
8107
|
+
)
|
|
8108
|
+
] })
|
|
8109
|
+
}
|
|
8110
|
+
)
|
|
8111
|
+
] }) })
|
|
8112
|
+
] });
|
|
8113
|
+
}
|
|
8114
|
+
|
|
7755
8115
|
// src/components/chat/ChatMessageBubble.tsx
|
|
7756
|
-
import { jsx as
|
|
8116
|
+
import { jsx as jsx50, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
7757
8117
|
function areMessageMetaEqual(a, b) {
|
|
7758
8118
|
if (a === b) return true;
|
|
7759
8119
|
if (!a || !b) return a === b;
|
|
7760
8120
|
return a.kind === b.kind && a.event === b.event && a.status === b.status && a.mergeRequestId === b.mergeRequestId && a.sourceAppId === b.sourceAppId && a.targetAppId === b.targetAppId && a.appId === b.appId && a.threadId === b.threadId;
|
|
7761
8121
|
}
|
|
8122
|
+
function areMessageAttachmentsEqual(a, b) {
|
|
8123
|
+
if (a === b) return true;
|
|
8124
|
+
const left = a ?? [];
|
|
8125
|
+
const right = b ?? [];
|
|
8126
|
+
if (left.length !== right.length) return false;
|
|
8127
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
8128
|
+
if (left[i].id !== right[i].id || left[i].name !== right[i].name || left[i].mimeType !== right[i].mimeType || left[i].size !== right[i].size || left[i].uri !== right[i].uri || left[i].width !== right[i].width || left[i].height !== right[i].height) {
|
|
8129
|
+
return false;
|
|
8130
|
+
}
|
|
8131
|
+
}
|
|
8132
|
+
return true;
|
|
8133
|
+
}
|
|
7762
8134
|
function ChatMessageBubbleInner({
|
|
7763
8135
|
message,
|
|
7764
8136
|
renderContent,
|
|
7765
8137
|
isLast,
|
|
7766
8138
|
retrying,
|
|
7767
8139
|
onRetryMessage,
|
|
8140
|
+
onAttachmentLoadError,
|
|
7768
8141
|
style
|
|
7769
8142
|
}) {
|
|
7770
8143
|
var _a, _b;
|
|
@@ -7783,11 +8156,36 @@ function ChatMessageBubbleInner({
|
|
|
7783
8156
|
const bodyColor = metaStatus === "success" ? theme.colors.success : metaStatus === "error" ? theme.colors.danger : void 0;
|
|
7784
8157
|
const showRetry = Boolean(onRetryMessage) && isLast && metaStatus === "error" && message.author === "human";
|
|
7785
8158
|
const retryLabel = retrying ? "Retrying..." : "Retry";
|
|
7786
|
-
const
|
|
8159
|
+
const hasText = message.content.trim().length > 0;
|
|
8160
|
+
const attachments = message.attachments ?? [];
|
|
8161
|
+
const hasAttachments = attachments.length > 0;
|
|
8162
|
+
const hasStatusIcon = isMergeCompleted || isSyncCompleted || isMergeApproved || isSyncStarted;
|
|
8163
|
+
const shouldRenderBubble = hasText || hasStatusIcon;
|
|
8164
|
+
const handleRetryPress = React38.useCallback(() => {
|
|
7787
8165
|
onRetryMessage == null ? void 0 : onRetryMessage(message.id);
|
|
7788
8166
|
}, [message.id, onRetryMessage]);
|
|
7789
|
-
return /* @__PURE__ */
|
|
7790
|
-
/* @__PURE__ */
|
|
8167
|
+
return /* @__PURE__ */ jsxs31(View37, { style: [align, style], children: [
|
|
8168
|
+
hasAttachments ? /* @__PURE__ */ jsx50(
|
|
8169
|
+
View37,
|
|
8170
|
+
{
|
|
8171
|
+
style: {
|
|
8172
|
+
maxWidth: "85%",
|
|
8173
|
+
marginBottom: shouldRenderBubble ? theme.spacing.xs : 0,
|
|
8174
|
+
alignSelf: isHuman ? "flex-end" : "flex-start",
|
|
8175
|
+
alignItems: isHuman ? "flex-end" : "flex-start"
|
|
8176
|
+
},
|
|
8177
|
+
children: /* @__PURE__ */ jsx50(
|
|
8178
|
+
ChatMessageAttachments,
|
|
8179
|
+
{
|
|
8180
|
+
messageId: message.id,
|
|
8181
|
+
attachments,
|
|
8182
|
+
align: isHuman ? "right" : "left",
|
|
8183
|
+
onAttachmentLoadError
|
|
8184
|
+
}
|
|
8185
|
+
)
|
|
8186
|
+
}
|
|
8187
|
+
) : null,
|
|
8188
|
+
shouldRenderBubble ? /* @__PURE__ */ jsx50(
|
|
7791
8189
|
Surface,
|
|
7792
8190
|
{
|
|
7793
8191
|
variant: bubbleVariant,
|
|
@@ -7802,14 +8200,14 @@ function ChatMessageBubbleInner({
|
|
|
7802
8200
|
},
|
|
7803
8201
|
cornerStyle
|
|
7804
8202
|
],
|
|
7805
|
-
children: /* @__PURE__ */
|
|
7806
|
-
isMergeCompleted || isSyncCompleted ? /* @__PURE__ */
|
|
7807
|
-
isMergeApproved || isSyncStarted ? /* @__PURE__ */
|
|
7808
|
-
/* @__PURE__ */
|
|
8203
|
+
children: /* @__PURE__ */ jsxs31(View37, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8204
|
+
isMergeCompleted || isSyncCompleted ? /* @__PURE__ */ jsx50(CheckCheck2, { size: 16, color: theme.colors.success, style: { marginRight: theme.spacing.sm } }) : null,
|
|
8205
|
+
isMergeApproved || isSyncStarted ? /* @__PURE__ */ jsx50(GitMerge2, { size: 16, color: theme.colors.text, style: { marginRight: theme.spacing.sm } }) : null,
|
|
8206
|
+
/* @__PURE__ */ jsx50(View37, { style: { flexShrink: 1, minWidth: 0 }, children: renderContent ? renderContent(message) : /* @__PURE__ */ jsx50(MarkdownText, { markdown: message.content, variant: "chat", bodyColor }) })
|
|
7809
8207
|
] })
|
|
7810
8208
|
}
|
|
7811
|
-
),
|
|
7812
|
-
showRetry ? /* @__PURE__ */
|
|
8209
|
+
) : null,
|
|
8210
|
+
showRetry ? /* @__PURE__ */ jsx50(View37, { style: { marginTop: theme.spacing.xs, alignSelf: align.alignSelf }, children: /* @__PURE__ */ jsx50(
|
|
7813
8211
|
Button,
|
|
7814
8212
|
{
|
|
7815
8213
|
variant: "ghost",
|
|
@@ -7818,9 +8216,9 @@ function ChatMessageBubbleInner({
|
|
|
7818
8216
|
disabled: retrying,
|
|
7819
8217
|
style: { borderColor: theme.colors.danger },
|
|
7820
8218
|
accessibilityLabel: "Retry send",
|
|
7821
|
-
children: /* @__PURE__ */
|
|
7822
|
-
!retrying ? /* @__PURE__ */
|
|
7823
|
-
/* @__PURE__ */
|
|
8219
|
+
children: /* @__PURE__ */ jsxs31(View37, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8220
|
+
!retrying ? /* @__PURE__ */ jsx50(RotateCcw, { size: 14, color: theme.colors.danger }) : null,
|
|
8221
|
+
/* @__PURE__ */ jsx50(
|
|
7824
8222
|
Text,
|
|
7825
8223
|
{
|
|
7826
8224
|
variant: "caption",
|
|
@@ -7836,30 +8234,30 @@ function ChatMessageBubbleInner({
|
|
|
7836
8234
|
] });
|
|
7837
8235
|
}
|
|
7838
8236
|
function areEqual(prev, next) {
|
|
7839
|
-
return prev.message.id === next.message.id && prev.message.author === next.message.author && prev.message.content === next.message.content && prev.message.kind === next.message.kind && String(prev.message.createdAt) === String(next.message.createdAt) && areMessageMetaEqual(prev.message.meta, next.message.meta) && prev.renderContent === next.renderContent && prev.isLast === next.isLast && prev.retrying === next.retrying && prev.onRetryMessage === next.onRetryMessage && prev.style === next.style;
|
|
8237
|
+
return prev.message.id === next.message.id && prev.message.author === next.message.author && prev.message.content === next.message.content && areMessageAttachmentsEqual(prev.message.attachments, next.message.attachments) && prev.message.kind === next.message.kind && String(prev.message.createdAt) === String(next.message.createdAt) && areMessageMetaEqual(prev.message.meta, next.message.meta) && prev.renderContent === next.renderContent && prev.isLast === next.isLast && prev.retrying === next.retrying && prev.onRetryMessage === next.onRetryMessage && prev.onAttachmentLoadError === next.onAttachmentLoadError && prev.style === next.style;
|
|
7840
8238
|
}
|
|
7841
|
-
var ChatMessageBubble =
|
|
8239
|
+
var ChatMessageBubble = React38.memo(ChatMessageBubbleInner, areEqual);
|
|
7842
8240
|
ChatMessageBubble.displayName = "ChatMessageBubble";
|
|
7843
8241
|
|
|
7844
8242
|
// src/components/chat/TypingIndicator.tsx
|
|
7845
|
-
import * as
|
|
7846
|
-
import { Animated as
|
|
7847
|
-
import { jsx as
|
|
8243
|
+
import * as React39 from "react";
|
|
8244
|
+
import { Animated as Animated11, View as View38 } from "react-native";
|
|
8245
|
+
import { jsx as jsx51 } from "react/jsx-runtime";
|
|
7848
8246
|
function TypingIndicator({ style }) {
|
|
7849
8247
|
const theme = useTheme();
|
|
7850
8248
|
const dotColor = theme.colors.textSubtle;
|
|
7851
|
-
const anims =
|
|
7852
|
-
() => [new
|
|
8249
|
+
const anims = React39.useMemo(
|
|
8250
|
+
() => [new Animated11.Value(0.3), new Animated11.Value(0.3), new Animated11.Value(0.3)],
|
|
7853
8251
|
[]
|
|
7854
8252
|
);
|
|
7855
|
-
|
|
8253
|
+
React39.useEffect(() => {
|
|
7856
8254
|
const loops = [];
|
|
7857
8255
|
anims.forEach((a, idx) => {
|
|
7858
|
-
const seq =
|
|
7859
|
-
|
|
7860
|
-
|
|
8256
|
+
const seq = Animated11.sequence([
|
|
8257
|
+
Animated11.timing(a, { toValue: 1, duration: 420, useNativeDriver: true, delay: idx * 140 }),
|
|
8258
|
+
Animated11.timing(a, { toValue: 0.3, duration: 420, useNativeDriver: true })
|
|
7861
8259
|
]);
|
|
7862
|
-
const loop =
|
|
8260
|
+
const loop = Animated11.loop(seq);
|
|
7863
8261
|
loops.push(loop);
|
|
7864
8262
|
loop.start();
|
|
7865
8263
|
});
|
|
@@ -7867,8 +8265,8 @@ function TypingIndicator({ style }) {
|
|
|
7867
8265
|
loops.forEach((l) => l.stop());
|
|
7868
8266
|
};
|
|
7869
8267
|
}, [anims]);
|
|
7870
|
-
return /* @__PURE__ */
|
|
7871
|
-
|
|
8268
|
+
return /* @__PURE__ */ jsx51(View38, { style: [{ flexDirection: "row", alignItems: "center" }, style], children: anims.map((a, i) => /* @__PURE__ */ jsx51(
|
|
8269
|
+
Animated11.View,
|
|
7872
8270
|
{
|
|
7873
8271
|
style: {
|
|
7874
8272
|
width: 8,
|
|
@@ -7877,7 +8275,7 @@ function TypingIndicator({ style }) {
|
|
|
7877
8275
|
marginHorizontal: 3,
|
|
7878
8276
|
backgroundColor: dotColor,
|
|
7879
8277
|
opacity: a,
|
|
7880
|
-
transform: [{ translateY:
|
|
8278
|
+
transform: [{ translateY: Animated11.multiply(Animated11.subtract(a, 0.3), 2) }]
|
|
7881
8279
|
}
|
|
7882
8280
|
},
|
|
7883
8281
|
i
|
|
@@ -7885,36 +8283,37 @@ function TypingIndicator({ style }) {
|
|
|
7885
8283
|
}
|
|
7886
8284
|
|
|
7887
8285
|
// src/components/chat/ChatMessageList.tsx
|
|
7888
|
-
import { jsx as
|
|
7889
|
-
var ChatMessageList =
|
|
8286
|
+
import { jsx as jsx52, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
8287
|
+
var ChatMessageList = React40.forwardRef(
|
|
7890
8288
|
({
|
|
7891
8289
|
messages,
|
|
7892
8290
|
showTypingIndicator = false,
|
|
7893
8291
|
renderMessageContent,
|
|
7894
8292
|
onRetryMessage,
|
|
7895
8293
|
isRetryingMessage,
|
|
8294
|
+
onAttachmentLoadError,
|
|
7896
8295
|
contentStyle,
|
|
7897
8296
|
bottomInset = 0,
|
|
7898
8297
|
onNearBottomChange,
|
|
7899
8298
|
nearBottomThreshold = 200
|
|
7900
8299
|
}, ref) => {
|
|
7901
8300
|
const theme = useTheme();
|
|
7902
|
-
const listRef =
|
|
7903
|
-
const nearBottomRef =
|
|
7904
|
-
const initialScrollDoneRef =
|
|
7905
|
-
const lastMessageIdRef =
|
|
7906
|
-
const data =
|
|
8301
|
+
const listRef = React40.useRef(null);
|
|
8302
|
+
const nearBottomRef = React40.useRef(true);
|
|
8303
|
+
const initialScrollDoneRef = React40.useRef(false);
|
|
8304
|
+
const lastMessageIdRef = React40.useRef(null);
|
|
8305
|
+
const data = React40.useMemo(() => {
|
|
7907
8306
|
return [...messages].reverse();
|
|
7908
8307
|
}, [messages]);
|
|
7909
8308
|
const lastMessageId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
7910
|
-
const keyExtractor =
|
|
7911
|
-
const scrollToBottom =
|
|
8309
|
+
const keyExtractor = React40.useCallback((m) => m.id, []);
|
|
8310
|
+
const scrollToBottom = React40.useCallback((options) => {
|
|
7912
8311
|
var _a;
|
|
7913
8312
|
const animated = (options == null ? void 0 : options.animated) ?? true;
|
|
7914
8313
|
(_a = listRef.current) == null ? void 0 : _a.scrollToOffset({ offset: 0, animated });
|
|
7915
8314
|
}, []);
|
|
7916
|
-
|
|
7917
|
-
const handleScroll =
|
|
8315
|
+
React40.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
|
|
8316
|
+
const handleScroll = React40.useCallback(
|
|
7918
8317
|
(e) => {
|
|
7919
8318
|
const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
|
|
7920
8319
|
const distanceFromBottom = Math.max(contentOffset.y - Math.max(bottomInset, 0), 0);
|
|
@@ -7926,7 +8325,7 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7926
8325
|
},
|
|
7927
8326
|
[bottomInset, nearBottomThreshold, onNearBottomChange]
|
|
7928
8327
|
);
|
|
7929
|
-
|
|
8328
|
+
React40.useEffect(() => {
|
|
7930
8329
|
if (!initialScrollDoneRef.current) return;
|
|
7931
8330
|
const lastId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
7932
8331
|
const prevLastId = lastMessageIdRef.current;
|
|
@@ -7936,14 +8335,14 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7936
8335
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
7937
8336
|
return () => cancelAnimationFrame(id);
|
|
7938
8337
|
}, [messages, scrollToBottom]);
|
|
7939
|
-
|
|
8338
|
+
React40.useEffect(() => {
|
|
7940
8339
|
if (showTypingIndicator && nearBottomRef.current) {
|
|
7941
8340
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
7942
8341
|
return () => cancelAnimationFrame(id);
|
|
7943
8342
|
}
|
|
7944
8343
|
return void 0;
|
|
7945
8344
|
}, [showTypingIndicator, scrollToBottom]);
|
|
7946
|
-
const handleContentSizeChange =
|
|
8345
|
+
const handleContentSizeChange = React40.useCallback(() => {
|
|
7947
8346
|
if (initialScrollDoneRef.current) return;
|
|
7948
8347
|
initialScrollDoneRef.current = true;
|
|
7949
8348
|
lastMessageIdRef.current = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
@@ -7951,7 +8350,7 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7951
8350
|
onNearBottomChange == null ? void 0 : onNearBottomChange(true);
|
|
7952
8351
|
requestAnimationFrame(() => scrollToBottom({ animated: false }));
|
|
7953
8352
|
}, [messages, onNearBottomChange, scrollToBottom]);
|
|
7954
|
-
const contentContainerStyle =
|
|
8353
|
+
const contentContainerStyle = React40.useMemo(
|
|
7955
8354
|
() => [
|
|
7956
8355
|
{
|
|
7957
8356
|
paddingHorizontal: theme.spacing.lg,
|
|
@@ -7961,28 +8360,29 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7961
8360
|
],
|
|
7962
8361
|
[contentStyle, theme.spacing.lg, theme.spacing.sm]
|
|
7963
8362
|
);
|
|
7964
|
-
const renderSeparator =
|
|
7965
|
-
const listHeader =
|
|
7966
|
-
() => /* @__PURE__ */
|
|
7967
|
-
showTypingIndicator ? /* @__PURE__ */
|
|
7968
|
-
bottomInset > 0 ? /* @__PURE__ */
|
|
8363
|
+
const renderSeparator = React40.useCallback(() => /* @__PURE__ */ jsx52(View39, { style: { height: theme.spacing.sm } }), [theme.spacing.sm]);
|
|
8364
|
+
const listHeader = React40.useMemo(
|
|
8365
|
+
() => /* @__PURE__ */ jsxs32(View39, { children: [
|
|
8366
|
+
showTypingIndicator ? /* @__PURE__ */ jsx52(View39, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ jsx52(TypingIndicator, {}) }) : null,
|
|
8367
|
+
bottomInset > 0 ? /* @__PURE__ */ jsx52(View39, { style: { height: bottomInset } }) : null
|
|
7969
8368
|
] }),
|
|
7970
8369
|
[bottomInset, showTypingIndicator, theme.spacing.lg, theme.spacing.sm]
|
|
7971
8370
|
);
|
|
7972
|
-
const renderItem =
|
|
7973
|
-
({ item }) => /* @__PURE__ */
|
|
8371
|
+
const renderItem = React40.useCallback(
|
|
8372
|
+
({ item }) => /* @__PURE__ */ jsx52(
|
|
7974
8373
|
ChatMessageBubble,
|
|
7975
8374
|
{
|
|
7976
8375
|
message: item,
|
|
7977
8376
|
renderContent: renderMessageContent,
|
|
7978
8377
|
isLast: Boolean(lastMessageId && item.id === lastMessageId),
|
|
7979
8378
|
retrying: (isRetryingMessage == null ? void 0 : isRetryingMessage(item.id)) ?? false,
|
|
7980
|
-
onRetryMessage
|
|
8379
|
+
onRetryMessage,
|
|
8380
|
+
onAttachmentLoadError
|
|
7981
8381
|
}
|
|
7982
8382
|
),
|
|
7983
|
-
[isRetryingMessage, lastMessageId, onRetryMessage, renderMessageContent]
|
|
8383
|
+
[isRetryingMessage, lastMessageId, onAttachmentLoadError, onRetryMessage, renderMessageContent]
|
|
7984
8384
|
);
|
|
7985
|
-
return /* @__PURE__ */
|
|
8385
|
+
return /* @__PURE__ */ jsx52(
|
|
7986
8386
|
BottomSheetFlatList,
|
|
7987
8387
|
{
|
|
7988
8388
|
ref: listRef,
|
|
@@ -8005,7 +8405,7 @@ var ChatMessageList = React39.forwardRef(
|
|
|
8005
8405
|
ChatMessageList.displayName = "ChatMessageList";
|
|
8006
8406
|
|
|
8007
8407
|
// src/components/chat/ChatPage.tsx
|
|
8008
|
-
import { jsx as
|
|
8408
|
+
import { jsx as jsx53, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
8009
8409
|
function ChatPage({
|
|
8010
8410
|
header,
|
|
8011
8411
|
messages,
|
|
@@ -8013,6 +8413,7 @@ function ChatPage({
|
|
|
8013
8413
|
renderMessageContent,
|
|
8014
8414
|
onRetryMessage,
|
|
8015
8415
|
isRetryingMessage,
|
|
8416
|
+
onAttachmentLoadError,
|
|
8016
8417
|
topBanner,
|
|
8017
8418
|
composerTop,
|
|
8018
8419
|
composer,
|
|
@@ -8024,35 +8425,35 @@ function ChatPage({
|
|
|
8024
8425
|
}) {
|
|
8025
8426
|
const theme = useTheme();
|
|
8026
8427
|
const insets = useSafeAreaInsets4();
|
|
8027
|
-
const [composerHeight, setComposerHeight] =
|
|
8028
|
-
const [composerTopHeight, setComposerTopHeight] =
|
|
8428
|
+
const [composerHeight, setComposerHeight] = React41.useState(0);
|
|
8429
|
+
const [composerTopHeight, setComposerTopHeight] = React41.useState(0);
|
|
8029
8430
|
const footerBottomPadding = Platform10.OS === "ios" ? insets.bottom - 24 : insets.bottom + 10;
|
|
8030
8431
|
const totalComposerHeight = composerHeight + composerTopHeight;
|
|
8031
8432
|
const overlayBottom = totalComposerHeight + footerBottomPadding + theme.spacing.lg;
|
|
8032
8433
|
const bottomInset = totalComposerHeight + footerBottomPadding + theme.spacing.xl;
|
|
8033
|
-
const resolvedOverlay =
|
|
8434
|
+
const resolvedOverlay = React41.useMemo(() => {
|
|
8034
8435
|
var _a;
|
|
8035
8436
|
if (!overlay) return null;
|
|
8036
|
-
if (!
|
|
8437
|
+
if (!React41.isValidElement(overlay)) return overlay;
|
|
8037
8438
|
const prevStyle = (_a = overlay.props) == null ? void 0 : _a.style;
|
|
8038
|
-
return
|
|
8439
|
+
return React41.cloneElement(overlay, {
|
|
8039
8440
|
style: [prevStyle, { bottom: overlayBottom }]
|
|
8040
8441
|
});
|
|
8041
8442
|
}, [overlay, overlayBottom]);
|
|
8042
|
-
|
|
8443
|
+
React41.useEffect(() => {
|
|
8043
8444
|
if (composerTop) return;
|
|
8044
8445
|
setComposerTopHeight(0);
|
|
8045
8446
|
}, [composerTop]);
|
|
8046
|
-
return /* @__PURE__ */
|
|
8047
|
-
header ? /* @__PURE__ */
|
|
8048
|
-
topBanner ? /* @__PURE__ */
|
|
8049
|
-
/* @__PURE__ */
|
|
8050
|
-
/* @__PURE__ */
|
|
8051
|
-
|
|
8447
|
+
return /* @__PURE__ */ jsxs33(View40, { style: [{ flex: 1 }, style], children: [
|
|
8448
|
+
header ? /* @__PURE__ */ jsx53(View40, { children: header }) : null,
|
|
8449
|
+
topBanner ? /* @__PURE__ */ jsx53(View40, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
|
|
8450
|
+
/* @__PURE__ */ jsxs33(View40, { style: { flex: 1 }, children: [
|
|
8451
|
+
/* @__PURE__ */ jsxs33(
|
|
8452
|
+
View40,
|
|
8052
8453
|
{
|
|
8053
8454
|
style: { flex: 1 },
|
|
8054
8455
|
children: [
|
|
8055
|
-
/* @__PURE__ */
|
|
8456
|
+
/* @__PURE__ */ jsx53(
|
|
8056
8457
|
ChatMessageList,
|
|
8057
8458
|
{
|
|
8058
8459
|
ref: listRef,
|
|
@@ -8061,6 +8462,7 @@ function ChatPage({
|
|
|
8061
8462
|
renderMessageContent,
|
|
8062
8463
|
onRetryMessage,
|
|
8063
8464
|
isRetryingMessage,
|
|
8465
|
+
onAttachmentLoadError,
|
|
8064
8466
|
onNearBottomChange,
|
|
8065
8467
|
bottomInset
|
|
8066
8468
|
}
|
|
@@ -8069,8 +8471,8 @@ function ChatPage({
|
|
|
8069
8471
|
]
|
|
8070
8472
|
}
|
|
8071
8473
|
),
|
|
8072
|
-
/* @__PURE__ */
|
|
8073
|
-
|
|
8474
|
+
/* @__PURE__ */ jsxs33(
|
|
8475
|
+
View40,
|
|
8074
8476
|
{
|
|
8075
8477
|
style: {
|
|
8076
8478
|
position: "absolute",
|
|
@@ -8082,15 +8484,15 @@ function ChatPage({
|
|
|
8082
8484
|
paddingBottom: footerBottomPadding
|
|
8083
8485
|
},
|
|
8084
8486
|
children: [
|
|
8085
|
-
composerTop ? /* @__PURE__ */
|
|
8086
|
-
|
|
8487
|
+
composerTop ? /* @__PURE__ */ jsx53(
|
|
8488
|
+
View40,
|
|
8087
8489
|
{
|
|
8088
8490
|
style: { marginBottom: theme.spacing.sm },
|
|
8089
8491
|
onLayout: (e) => setComposerTopHeight(e.nativeEvent.layout.height),
|
|
8090
8492
|
children: composerTop
|
|
8091
8493
|
}
|
|
8092
8494
|
) : null,
|
|
8093
|
-
/* @__PURE__ */
|
|
8495
|
+
/* @__PURE__ */ jsx53(
|
|
8094
8496
|
ChatComposer,
|
|
8095
8497
|
{
|
|
8096
8498
|
...composer,
|
|
@@ -8106,15 +8508,15 @@ function ChatPage({
|
|
|
8106
8508
|
}
|
|
8107
8509
|
|
|
8108
8510
|
// src/components/chat/ScrollToBottomButton.tsx
|
|
8109
|
-
import * as
|
|
8110
|
-
import { Pressable as
|
|
8111
|
-
import
|
|
8112
|
-
import { jsx as
|
|
8511
|
+
import * as React42 from "react";
|
|
8512
|
+
import { Pressable as Pressable17, View as View41 } from "react-native";
|
|
8513
|
+
import Animated12, { Easing as Easing2, useAnimatedStyle as useAnimatedStyle2, useSharedValue as useSharedValue2, withTiming as withTiming2 } from "react-native-reanimated";
|
|
8514
|
+
import { jsx as jsx54 } from "react/jsx-runtime";
|
|
8113
8515
|
function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
8114
8516
|
const theme = useTheme();
|
|
8115
8517
|
const progress = useSharedValue2(visible ? 1 : 0);
|
|
8116
|
-
const [pressed, setPressed] =
|
|
8117
|
-
|
|
8518
|
+
const [pressed, setPressed] = React42.useState(false);
|
|
8519
|
+
React42.useEffect(() => {
|
|
8118
8520
|
progress.value = withTiming2(visible ? 1 : 0, { duration: 200, easing: Easing2.out(Easing2.ease) });
|
|
8119
8521
|
}, [progress, visible]);
|
|
8120
8522
|
const animStyle = useAnimatedStyle2(() => ({
|
|
@@ -8123,8 +8525,8 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8123
8525
|
}));
|
|
8124
8526
|
const bg = theme.scheme === "dark" ? "rgba(39,39,42,0.9)" : "rgba(244,244,245,0.95)";
|
|
8125
8527
|
const border = theme.scheme === "dark" ? withAlpha("#FFFFFF", 0.12) : withAlpha("#000000", 0.08);
|
|
8126
|
-
return /* @__PURE__ */
|
|
8127
|
-
|
|
8528
|
+
return /* @__PURE__ */ jsx54(
|
|
8529
|
+
Animated12.View,
|
|
8128
8530
|
{
|
|
8129
8531
|
pointerEvents: visible ? "auto" : "none",
|
|
8130
8532
|
style: [
|
|
@@ -8137,8 +8539,8 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8137
8539
|
style,
|
|
8138
8540
|
animStyle
|
|
8139
8541
|
],
|
|
8140
|
-
children: /* @__PURE__ */
|
|
8141
|
-
|
|
8542
|
+
children: /* @__PURE__ */ jsx54(
|
|
8543
|
+
View41,
|
|
8142
8544
|
{
|
|
8143
8545
|
style: {
|
|
8144
8546
|
width: 44,
|
|
@@ -8156,8 +8558,8 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8156
8558
|
elevation: 5,
|
|
8157
8559
|
opacity: pressed ? 0.85 : 1
|
|
8158
8560
|
},
|
|
8159
|
-
children: /* @__PURE__ */
|
|
8160
|
-
|
|
8561
|
+
children: /* @__PURE__ */ jsx54(
|
|
8562
|
+
Pressable17,
|
|
8161
8563
|
{
|
|
8162
8564
|
onPress,
|
|
8163
8565
|
onPressIn: () => setPressed(true),
|
|
@@ -8174,16 +8576,16 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8174
8576
|
}
|
|
8175
8577
|
|
|
8176
8578
|
// src/components/chat/ChatHeader.tsx
|
|
8177
|
-
import { StyleSheet as
|
|
8178
|
-
import { jsx as
|
|
8579
|
+
import { StyleSheet as StyleSheet5 } from "react-native";
|
|
8580
|
+
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
8179
8581
|
function ChatHeader({ left, right, center, style }) {
|
|
8180
|
-
const flattenedStyle =
|
|
8582
|
+
const flattenedStyle = StyleSheet5.flatten([
|
|
8181
8583
|
{
|
|
8182
8584
|
paddingTop: 0
|
|
8183
8585
|
},
|
|
8184
8586
|
style
|
|
8185
8587
|
]);
|
|
8186
|
-
return /* @__PURE__ */
|
|
8588
|
+
return /* @__PURE__ */ jsx55(
|
|
8187
8589
|
StudioSheetHeader,
|
|
8188
8590
|
{
|
|
8189
8591
|
left,
|
|
@@ -8195,13 +8597,13 @@ function ChatHeader({ left, right, center, style }) {
|
|
|
8195
8597
|
}
|
|
8196
8598
|
|
|
8197
8599
|
// src/components/chat/ForkNoticeBanner.tsx
|
|
8198
|
-
import { View as
|
|
8199
|
-
import { jsx as
|
|
8600
|
+
import { View as View43 } from "react-native";
|
|
8601
|
+
import { jsx as jsx56, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
8200
8602
|
function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
8201
8603
|
const theme = useTheme();
|
|
8202
8604
|
const resolvedTitle = title ?? (isOwner ? "Remixed app" : "Remix app");
|
|
8203
8605
|
const resolvedDescription = description ?? (isOwner ? "Any changes you make will be a remix of the original app. You can view the edited version in the Remix tab in your apps page." : "Once you make edits, this remixed version will appear on your Remixed apps page.");
|
|
8204
|
-
return /* @__PURE__ */
|
|
8606
|
+
return /* @__PURE__ */ jsx56(
|
|
8205
8607
|
Card,
|
|
8206
8608
|
{
|
|
8207
8609
|
variant: "surfaceRaised",
|
|
@@ -8216,8 +8618,8 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
8216
8618
|
},
|
|
8217
8619
|
style
|
|
8218
8620
|
],
|
|
8219
|
-
children: /* @__PURE__ */
|
|
8220
|
-
/* @__PURE__ */
|
|
8621
|
+
children: /* @__PURE__ */ jsxs34(View43, { style: { minWidth: 0 }, children: [
|
|
8622
|
+
/* @__PURE__ */ jsx56(
|
|
8221
8623
|
Text,
|
|
8222
8624
|
{
|
|
8223
8625
|
style: {
|
|
@@ -8231,7 +8633,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
8231
8633
|
children: resolvedTitle
|
|
8232
8634
|
}
|
|
8233
8635
|
),
|
|
8234
|
-
/* @__PURE__ */
|
|
8636
|
+
/* @__PURE__ */ jsx56(
|
|
8235
8637
|
Text,
|
|
8236
8638
|
{
|
|
8237
8639
|
style: {
|
|
@@ -8249,16 +8651,16 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
8249
8651
|
}
|
|
8250
8652
|
|
|
8251
8653
|
// src/components/chat/ChatQueue.tsx
|
|
8252
|
-
import * as
|
|
8253
|
-
import { ActivityIndicator as ActivityIndicator9, Pressable as
|
|
8254
|
-
import { jsx as
|
|
8654
|
+
import * as React43 from "react";
|
|
8655
|
+
import { ActivityIndicator as ActivityIndicator9, Pressable as Pressable18, View as View44 } from "react-native";
|
|
8656
|
+
import { jsx as jsx57, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
8255
8657
|
function ChatQueue({ items, onRemove }) {
|
|
8256
8658
|
const theme = useTheme();
|
|
8257
|
-
const [expanded, setExpanded] =
|
|
8258
|
-
const [canExpand, setCanExpand] =
|
|
8259
|
-
const [collapsedText, setCollapsedText] =
|
|
8260
|
-
const [removing, setRemoving] =
|
|
8261
|
-
const buildCollapsedText =
|
|
8659
|
+
const [expanded, setExpanded] = React43.useState({});
|
|
8660
|
+
const [canExpand, setCanExpand] = React43.useState({});
|
|
8661
|
+
const [collapsedText, setCollapsedText] = React43.useState({});
|
|
8662
|
+
const [removing, setRemoving] = React43.useState({});
|
|
8663
|
+
const buildCollapsedText = React43.useCallback((lines) => {
|
|
8262
8664
|
var _a, _b;
|
|
8263
8665
|
const line1 = ((_a = lines[0]) == null ? void 0 : _a.text) ?? "";
|
|
8264
8666
|
const line2 = ((_b = lines[1]) == null ? void 0 : _b.text) ?? "";
|
|
@@ -8274,7 +8676,7 @@ function ChatQueue({ items, onRemove }) {
|
|
|
8274
8676
|
return `${line1}
|
|
8275
8677
|
${trimmedLine2}\u2026 `;
|
|
8276
8678
|
}, []);
|
|
8277
|
-
|
|
8679
|
+
React43.useEffect(() => {
|
|
8278
8680
|
if (items.length === 0) return;
|
|
8279
8681
|
const ids = new Set(items.map((item) => item.id));
|
|
8280
8682
|
setExpanded((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
|
|
@@ -8283,8 +8685,8 @@ ${trimmedLine2}\u2026 `;
|
|
|
8283
8685
|
setRemoving((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
|
|
8284
8686
|
}, [items]);
|
|
8285
8687
|
if (items.length === 0) return null;
|
|
8286
|
-
return /* @__PURE__ */
|
|
8287
|
-
|
|
8688
|
+
return /* @__PURE__ */ jsxs35(
|
|
8689
|
+
View44,
|
|
8288
8690
|
{
|
|
8289
8691
|
style: {
|
|
8290
8692
|
borderWidth: 1,
|
|
@@ -8295,16 +8697,16 @@ ${trimmedLine2}\u2026 `;
|
|
|
8295
8697
|
backgroundColor: "transparent"
|
|
8296
8698
|
},
|
|
8297
8699
|
children: [
|
|
8298
|
-
/* @__PURE__ */
|
|
8299
|
-
/* @__PURE__ */
|
|
8700
|
+
/* @__PURE__ */ jsx57(Text, { variant: "caption", style: { marginBottom: theme.spacing.sm }, children: "Queue" }),
|
|
8701
|
+
/* @__PURE__ */ jsx57(View44, { style: { gap: theme.spacing.sm }, children: items.map((item) => {
|
|
8300
8702
|
const isExpanded = Boolean(expanded[item.id]);
|
|
8301
8703
|
const showToggle = Boolean(canExpand[item.id]);
|
|
8302
8704
|
const prompt = item.prompt ?? "";
|
|
8303
8705
|
const moreLabel = "more";
|
|
8304
8706
|
const displayPrompt = !isExpanded && showToggle && collapsedText[item.id] ? collapsedText[item.id] : prompt;
|
|
8305
8707
|
const isRemoving = Boolean(removing[item.id]);
|
|
8306
|
-
return /* @__PURE__ */
|
|
8307
|
-
|
|
8708
|
+
return /* @__PURE__ */ jsxs35(
|
|
8709
|
+
View44,
|
|
8308
8710
|
{
|
|
8309
8711
|
style: {
|
|
8310
8712
|
flexDirection: "row",
|
|
@@ -8316,8 +8718,8 @@ ${trimmedLine2}\u2026 `;
|
|
|
8316
8718
|
backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.8 : 0.9)
|
|
8317
8719
|
},
|
|
8318
8720
|
children: [
|
|
8319
|
-
/* @__PURE__ */
|
|
8320
|
-
!canExpand[item.id] ? /* @__PURE__ */
|
|
8721
|
+
/* @__PURE__ */ jsxs35(View44, { style: { flex: 1 }, children: [
|
|
8722
|
+
!canExpand[item.id] ? /* @__PURE__ */ jsx57(
|
|
8321
8723
|
Text,
|
|
8322
8724
|
{
|
|
8323
8725
|
style: { position: "absolute", opacity: 0, zIndex: -1, width: "100%" },
|
|
@@ -8336,14 +8738,14 @@ ${trimmedLine2}\u2026 `;
|
|
|
8336
8738
|
children: prompt
|
|
8337
8739
|
}
|
|
8338
8740
|
) : null,
|
|
8339
|
-
/* @__PURE__ */
|
|
8741
|
+
/* @__PURE__ */ jsxs35(
|
|
8340
8742
|
Text,
|
|
8341
8743
|
{
|
|
8342
8744
|
variant: "bodyMuted",
|
|
8343
8745
|
numberOfLines: isExpanded ? void 0 : 2,
|
|
8344
8746
|
children: [
|
|
8345
8747
|
displayPrompt,
|
|
8346
|
-
!isExpanded && showToggle ? /* @__PURE__ */
|
|
8748
|
+
!isExpanded && showToggle ? /* @__PURE__ */ jsx57(
|
|
8347
8749
|
Text,
|
|
8348
8750
|
{
|
|
8349
8751
|
color: theme.colors.text,
|
|
@@ -8355,18 +8757,18 @@ ${trimmedLine2}\u2026 `;
|
|
|
8355
8757
|
]
|
|
8356
8758
|
}
|
|
8357
8759
|
),
|
|
8358
|
-
showToggle && isExpanded ? /* @__PURE__ */
|
|
8359
|
-
|
|
8760
|
+
showToggle && isExpanded ? /* @__PURE__ */ jsx57(
|
|
8761
|
+
Pressable18,
|
|
8360
8762
|
{
|
|
8361
8763
|
onPress: () => setExpanded((prev) => ({ ...prev, [item.id]: false })),
|
|
8362
8764
|
hitSlop: 6,
|
|
8363
8765
|
style: { alignSelf: "flex-start", marginTop: 4 },
|
|
8364
|
-
children: /* @__PURE__ */
|
|
8766
|
+
children: /* @__PURE__ */ jsx57(Text, { variant: "captionMuted", color: theme.colors.text, children: "less" })
|
|
8365
8767
|
}
|
|
8366
8768
|
) : null
|
|
8367
8769
|
] }),
|
|
8368
|
-
/* @__PURE__ */
|
|
8369
|
-
|
|
8770
|
+
/* @__PURE__ */ jsx57(
|
|
8771
|
+
Pressable18,
|
|
8370
8772
|
{
|
|
8371
8773
|
onPress: () => {
|
|
8372
8774
|
if (!onRemove || isRemoving) return;
|
|
@@ -8381,7 +8783,7 @@ ${trimmedLine2}\u2026 `;
|
|
|
8381
8783
|
},
|
|
8382
8784
|
hitSlop: 8,
|
|
8383
8785
|
style: { alignSelf: "center" },
|
|
8384
|
-
children: isRemoving ? /* @__PURE__ */
|
|
8786
|
+
children: isRemoving ? /* @__PURE__ */ jsx57(ActivityIndicator9, { size: "small", color: theme.colors.text }) : /* @__PURE__ */ jsx57(IconClose, { size: 14, colorToken: "text" })
|
|
8385
8787
|
}
|
|
8386
8788
|
)
|
|
8387
8789
|
]
|
|
@@ -8395,15 +8797,15 @@ ${trimmedLine2}\u2026 `;
|
|
|
8395
8797
|
}
|
|
8396
8798
|
|
|
8397
8799
|
// src/components/chat/AgentProgressCard.tsx
|
|
8398
|
-
import { View as
|
|
8800
|
+
import { View as View45 } from "react-native";
|
|
8399
8801
|
|
|
8400
8802
|
// src/components/icons/RemixXLoopLottie.tsx
|
|
8401
8803
|
import LottieView from "lottie-react-native";
|
|
8402
|
-
import { jsx as
|
|
8804
|
+
import { jsx as jsx58 } from "react/jsx-runtime";
|
|
8403
8805
|
var remixXLoopSource = require_remix_x_loop_lottie();
|
|
8404
8806
|
var Lottie = LottieView;
|
|
8405
8807
|
function RemixXLoopLottie({ size = 24, style }) {
|
|
8406
|
-
return /* @__PURE__ */
|
|
8808
|
+
return /* @__PURE__ */ jsx58(
|
|
8407
8809
|
Lottie,
|
|
8408
8810
|
{
|
|
8409
8811
|
source: remixXLoopSource,
|
|
@@ -8415,7 +8817,7 @@ function RemixXLoopLottie({ size = 24, style }) {
|
|
|
8415
8817
|
}
|
|
8416
8818
|
|
|
8417
8819
|
// src/components/chat/AgentProgressCard.tsx
|
|
8418
|
-
import { jsx as
|
|
8820
|
+
import { jsx as jsx59, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
8419
8821
|
function titleForPhase(phase) {
|
|
8420
8822
|
if (phase === "planning") return "Planning";
|
|
8421
8823
|
if (phase === "reasoning") return "Reasoning";
|
|
@@ -8440,8 +8842,8 @@ function AgentProgressCard({ progress }) {
|
|
|
8440
8842
|
const showAnimatedStatusIcon = progress.status === "running";
|
|
8441
8843
|
const subtitle = progress.latestMessage || `Agent is ${phaseLabel.toLowerCase()}...`;
|
|
8442
8844
|
const todo = progress.todoSummary;
|
|
8443
|
-
return /* @__PURE__ */
|
|
8444
|
-
|
|
8845
|
+
return /* @__PURE__ */ jsxs36(
|
|
8846
|
+
View45,
|
|
8445
8847
|
{
|
|
8446
8848
|
style: {
|
|
8447
8849
|
borderWidth: 1,
|
|
@@ -8452,23 +8854,23 @@ function AgentProgressCard({ progress }) {
|
|
|
8452
8854
|
backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.84 : 0.94)
|
|
8453
8855
|
},
|
|
8454
8856
|
children: [
|
|
8455
|
-
/* @__PURE__ */
|
|
8456
|
-
/* @__PURE__ */
|
|
8457
|
-
/* @__PURE__ */
|
|
8458
|
-
/* @__PURE__ */
|
|
8459
|
-
showAnimatedStatusIcon ? /* @__PURE__ */
|
|
8857
|
+
/* @__PURE__ */ jsxs36(View45, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }, children: [
|
|
8858
|
+
/* @__PURE__ */ jsx59(Text, { variant: "caption", children: statusLabel }),
|
|
8859
|
+
/* @__PURE__ */ jsxs36(View45, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8860
|
+
/* @__PURE__ */ jsx59(Text, { variant: "captionMuted", children: phaseLabel }),
|
|
8861
|
+
showAnimatedStatusIcon ? /* @__PURE__ */ jsx59(RemixXLoopLottie, { size: 20, style: { marginLeft: 8 } }) : null
|
|
8460
8862
|
] })
|
|
8461
8863
|
] }),
|
|
8462
|
-
/* @__PURE__ */
|
|
8463
|
-
progress.changedFilesCount > 0 ? /* @__PURE__ */
|
|
8864
|
+
/* @__PURE__ */ jsx59(Text, { variant: "bodyMuted", children: subtitle }),
|
|
8865
|
+
progress.changedFilesCount > 0 ? /* @__PURE__ */ jsxs36(Text, { variant: "captionMuted", style: { marginTop: 8 }, children: [
|
|
8464
8866
|
"Updated files: ",
|
|
8465
8867
|
progress.changedFilesCount
|
|
8466
8868
|
] }) : null,
|
|
8467
|
-
progress.recentFiles.length > 0 ? /* @__PURE__ */
|
|
8869
|
+
progress.recentFiles.length > 0 ? /* @__PURE__ */ jsx59(View45, { style: { marginTop: 6 }, children: progress.recentFiles.map((path) => /* @__PURE__ */ jsxs36(Text, { variant: "captionMuted", numberOfLines: 1, children: [
|
|
8468
8870
|
"\u2022 ",
|
|
8469
8871
|
path
|
|
8470
8872
|
] }, path)) }) : null,
|
|
8471
|
-
todo ? /* @__PURE__ */
|
|
8873
|
+
todo ? /* @__PURE__ */ jsxs36(Text, { variant: "captionMuted", style: { marginTop: 8 }, children: [
|
|
8472
8874
|
"Todos: ",
|
|
8473
8875
|
todo.completed,
|
|
8474
8876
|
"/",
|
|
@@ -8482,8 +8884,8 @@ function AgentProgressCard({ progress }) {
|
|
|
8482
8884
|
}
|
|
8483
8885
|
|
|
8484
8886
|
// src/components/chat/BundleProgressCard.tsx
|
|
8485
|
-
import { View as
|
|
8486
|
-
import { jsx as
|
|
8887
|
+
import { View as View46 } from "react-native";
|
|
8888
|
+
import { jsx as jsx60, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
8487
8889
|
function titleForStatus2(status) {
|
|
8488
8890
|
if (status === "succeeded") return "Completed";
|
|
8489
8891
|
if (status === "failed") return "Failed";
|
|
@@ -8495,8 +8897,8 @@ function BundleProgressCard({ progress }) {
|
|
|
8495
8897
|
const percent = Math.round(Math.max(0, Math.min(1, progress.progressValue)) * 100);
|
|
8496
8898
|
const fillColor = progress.status === "failed" ? theme.colors.danger : progress.status === "succeeded" ? theme.colors.success : theme.colors.warning;
|
|
8497
8899
|
const detail = progress.errorMessage || progress.phaseLabel;
|
|
8498
|
-
return /* @__PURE__ */
|
|
8499
|
-
|
|
8900
|
+
return /* @__PURE__ */ jsxs37(
|
|
8901
|
+
View46,
|
|
8500
8902
|
{
|
|
8501
8903
|
accessible: true,
|
|
8502
8904
|
accessibilityRole: "progressbar",
|
|
@@ -8511,15 +8913,15 @@ function BundleProgressCard({ progress }) {
|
|
|
8511
8913
|
backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.84 : 0.94)
|
|
8512
8914
|
},
|
|
8513
8915
|
children: [
|
|
8514
|
-
/* @__PURE__ */
|
|
8515
|
-
/* @__PURE__ */
|
|
8516
|
-
/* @__PURE__ */
|
|
8916
|
+
/* @__PURE__ */ jsxs37(View46, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 8 }, children: [
|
|
8917
|
+
/* @__PURE__ */ jsx60(Text, { variant: "caption", children: statusLabel }),
|
|
8918
|
+
/* @__PURE__ */ jsxs37(Text, { variant: "captionMuted", children: [
|
|
8517
8919
|
percent,
|
|
8518
8920
|
"%"
|
|
8519
8921
|
] })
|
|
8520
8922
|
] }),
|
|
8521
|
-
/* @__PURE__ */
|
|
8522
|
-
|
|
8923
|
+
/* @__PURE__ */ jsx60(
|
|
8924
|
+
View46,
|
|
8523
8925
|
{
|
|
8524
8926
|
style: {
|
|
8525
8927
|
width: "100%",
|
|
@@ -8528,8 +8930,8 @@ function BundleProgressCard({ progress }) {
|
|
|
8528
8930
|
backgroundColor: withAlpha(theme.colors.border, theme.scheme === "dark" ? 0.5 : 0.6),
|
|
8529
8931
|
overflow: "hidden"
|
|
8530
8932
|
},
|
|
8531
|
-
children: /* @__PURE__ */
|
|
8532
|
-
|
|
8933
|
+
children: /* @__PURE__ */ jsx60(
|
|
8934
|
+
View46,
|
|
8533
8935
|
{
|
|
8534
8936
|
style: {
|
|
8535
8937
|
width: `${percent}%`,
|
|
@@ -8540,14 +8942,14 @@ function BundleProgressCard({ progress }) {
|
|
|
8540
8942
|
)
|
|
8541
8943
|
}
|
|
8542
8944
|
),
|
|
8543
|
-
/* @__PURE__ */
|
|
8945
|
+
/* @__PURE__ */ jsx60(Text, { variant: "captionMuted", numberOfLines: 1, style: { marginTop: 8, minHeight: 16 }, children: detail })
|
|
8544
8946
|
]
|
|
8545
8947
|
}
|
|
8546
8948
|
);
|
|
8547
8949
|
}
|
|
8548
8950
|
|
|
8549
8951
|
// src/studio/ui/ChatPanel.tsx
|
|
8550
|
-
import { jsx as
|
|
8952
|
+
import { jsx as jsx61, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
8551
8953
|
function ChatPanel({
|
|
8552
8954
|
title = "Chat",
|
|
8553
8955
|
messages,
|
|
@@ -8567,14 +8969,15 @@ function ChatPanel({
|
|
|
8567
8969
|
onSend,
|
|
8568
8970
|
onRetryMessage,
|
|
8569
8971
|
isRetryingMessage,
|
|
8972
|
+
onAttachmentLoadError,
|
|
8570
8973
|
queueItems = [],
|
|
8571
8974
|
onRemoveQueueItem,
|
|
8572
8975
|
progress = null
|
|
8573
8976
|
}) {
|
|
8574
8977
|
const theme = useTheme();
|
|
8575
|
-
const listRef =
|
|
8576
|
-
const [nearBottom, setNearBottom] =
|
|
8577
|
-
const handleSend =
|
|
8978
|
+
const listRef = React44.useRef(null);
|
|
8979
|
+
const [nearBottom, setNearBottom] = React44.useState(true);
|
|
8980
|
+
const handleSend = React44.useCallback(
|
|
8578
8981
|
async (text, composerAttachments) => {
|
|
8579
8982
|
const all = composerAttachments ?? attachments;
|
|
8580
8983
|
await onSend(text, all.length > 0 ? all : void 0);
|
|
@@ -8588,25 +8991,25 @@ function ChatPanel({
|
|
|
8588
8991
|
},
|
|
8589
8992
|
[attachments, nearBottom, onClearAttachments, onSend]
|
|
8590
8993
|
);
|
|
8591
|
-
const handleScrollToBottom =
|
|
8994
|
+
const handleScrollToBottom = React44.useCallback(() => {
|
|
8592
8995
|
var _a;
|
|
8593
8996
|
(_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
|
|
8594
8997
|
}, []);
|
|
8595
|
-
const header = /* @__PURE__ */
|
|
8998
|
+
const header = /* @__PURE__ */ jsx61(
|
|
8596
8999
|
ChatHeader,
|
|
8597
9000
|
{
|
|
8598
|
-
left: /* @__PURE__ */
|
|
8599
|
-
/* @__PURE__ */
|
|
8600
|
-
onNavigateHome ? /* @__PURE__ */
|
|
9001
|
+
left: /* @__PURE__ */ jsxs38(View47, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
9002
|
+
/* @__PURE__ */ jsx61(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx61(IconBack, { size: 20, colorToken: "floatingContent" }) }),
|
|
9003
|
+
onNavigateHome ? /* @__PURE__ */ jsx61(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ jsx61(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
|
|
8601
9004
|
] }),
|
|
8602
|
-
right: /* @__PURE__ */
|
|
8603
|
-
onStartDraw ? /* @__PURE__ */
|
|
8604
|
-
/* @__PURE__ */
|
|
9005
|
+
right: /* @__PURE__ */ jsxs38(View47, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
9006
|
+
onStartDraw ? /* @__PURE__ */ jsx61(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx61(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
|
|
9007
|
+
/* @__PURE__ */ jsx61(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ jsx61(IconClose, { size: 20, colorToken: "floatingContent" }) })
|
|
8605
9008
|
] }),
|
|
8606
9009
|
center: null
|
|
8607
9010
|
}
|
|
8608
9011
|
);
|
|
8609
|
-
const topBanner = shouldForkOnEdit ? /* @__PURE__ */
|
|
9012
|
+
const topBanner = shouldForkOnEdit ? /* @__PURE__ */ jsx61(
|
|
8610
9013
|
ForkNoticeBanner,
|
|
8611
9014
|
{
|
|
8612
9015
|
isOwner: !shouldForkOnEdit,
|
|
@@ -8615,22 +9018,22 @@ function ChatPanel({
|
|
|
8615
9018
|
) : null;
|
|
8616
9019
|
const showMessagesLoading = Boolean(loading) && messages.length === 0;
|
|
8617
9020
|
if (showMessagesLoading) {
|
|
8618
|
-
return /* @__PURE__ */
|
|
8619
|
-
/* @__PURE__ */
|
|
8620
|
-
topBanner ? /* @__PURE__ */
|
|
8621
|
-
/* @__PURE__ */
|
|
8622
|
-
/* @__PURE__ */
|
|
8623
|
-
/* @__PURE__ */
|
|
8624
|
-
/* @__PURE__ */
|
|
9021
|
+
return /* @__PURE__ */ jsxs38(View47, { style: { flex: 1 }, children: [
|
|
9022
|
+
/* @__PURE__ */ jsx61(View47, { children: header }),
|
|
9023
|
+
topBanner ? /* @__PURE__ */ jsx61(View47, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
|
|
9024
|
+
/* @__PURE__ */ jsxs38(View47, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
|
|
9025
|
+
/* @__PURE__ */ jsx61(ActivityIndicator10, {}),
|
|
9026
|
+
/* @__PURE__ */ jsx61(View47, { style: { height: 12 } }),
|
|
9027
|
+
/* @__PURE__ */ jsx61(Text, { variant: "bodyMuted", children: "Loading messages\u2026" })
|
|
8625
9028
|
] })
|
|
8626
9029
|
] });
|
|
8627
9030
|
}
|
|
8628
9031
|
const bundleProgress = (progress == null ? void 0 : progress.bundle) ?? null;
|
|
8629
|
-
const queueTop = progress || queueItems.length > 0 ? /* @__PURE__ */
|
|
8630
|
-
progress ? bundleProgress ? /* @__PURE__ */
|
|
8631
|
-
!progress && queueItems.length > 0 ? /* @__PURE__ */
|
|
9032
|
+
const queueTop = progress || queueItems.length > 0 ? /* @__PURE__ */ jsxs38(View47, { style: { gap: theme.spacing.sm }, children: [
|
|
9033
|
+
progress ? bundleProgress ? /* @__PURE__ */ jsx61(BundleProgressCard, { progress: bundleProgress }) : /* @__PURE__ */ jsx61(AgentProgressCard, { progress }) : null,
|
|
9034
|
+
!progress && queueItems.length > 0 ? /* @__PURE__ */ jsx61(ChatQueue, { items: queueItems, onRemove: onRemoveQueueItem }) : null
|
|
8632
9035
|
] }) : null;
|
|
8633
|
-
return /* @__PURE__ */
|
|
9036
|
+
return /* @__PURE__ */ jsx61(
|
|
8634
9037
|
ChatPage,
|
|
8635
9038
|
{
|
|
8636
9039
|
header,
|
|
@@ -8638,18 +9041,19 @@ function ChatPanel({
|
|
|
8638
9041
|
showTypingIndicator,
|
|
8639
9042
|
onRetryMessage,
|
|
8640
9043
|
isRetryingMessage,
|
|
9044
|
+
onAttachmentLoadError,
|
|
8641
9045
|
topBanner,
|
|
8642
9046
|
composerTop: queueTop,
|
|
8643
9047
|
composerHorizontalPadding: 0,
|
|
8644
9048
|
listRef,
|
|
8645
9049
|
onNearBottomChange: setNearBottom,
|
|
8646
|
-
overlay: /* @__PURE__ */
|
|
9050
|
+
overlay: /* @__PURE__ */ jsx61(
|
|
8647
9051
|
ScrollToBottomButton,
|
|
8648
9052
|
{
|
|
8649
9053
|
visible: !nearBottom,
|
|
8650
9054
|
onPress: handleScrollToBottom,
|
|
8651
9055
|
style: { bottom: 80 },
|
|
8652
|
-
children: /* @__PURE__ */
|
|
9056
|
+
children: /* @__PURE__ */ jsx61(IconArrowDown, { size: 20, colorToken: "floatingContent" })
|
|
8653
9057
|
}
|
|
8654
9058
|
),
|
|
8655
9059
|
composer: {
|
|
@@ -8669,9 +9073,9 @@ function ChatPanel({
|
|
|
8669
9073
|
}
|
|
8670
9074
|
|
|
8671
9075
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
8672
|
-
import * as
|
|
8673
|
-
import { Pressable as
|
|
8674
|
-
import { jsx as
|
|
9076
|
+
import * as React45 from "react";
|
|
9077
|
+
import { Pressable as Pressable19, View as View48 } from "react-native";
|
|
9078
|
+
import { jsx as jsx62, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
8675
9079
|
function ConfirmMergeRequestDialog({
|
|
8676
9080
|
visible,
|
|
8677
9081
|
onOpenChange,
|
|
@@ -8682,14 +9086,14 @@ function ConfirmMergeRequestDialog({
|
|
|
8682
9086
|
onTestFirst
|
|
8683
9087
|
}) {
|
|
8684
9088
|
const theme = useTheme();
|
|
8685
|
-
const close =
|
|
9089
|
+
const close = React45.useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
8686
9090
|
const canConfirm = Boolean(mergeRequest) && !approveDisabled;
|
|
8687
|
-
const handleConfirm =
|
|
9091
|
+
const handleConfirm = React45.useCallback(() => {
|
|
8688
9092
|
if (!mergeRequest) return;
|
|
8689
9093
|
onOpenChange(false);
|
|
8690
9094
|
void onConfirm();
|
|
8691
9095
|
}, [mergeRequest, onConfirm, onOpenChange]);
|
|
8692
|
-
const handleTestFirst =
|
|
9096
|
+
const handleTestFirst = React45.useCallback(() => {
|
|
8693
9097
|
if (!mergeRequest) return;
|
|
8694
9098
|
onOpenChange(false);
|
|
8695
9099
|
void onTestFirst(mergeRequest);
|
|
@@ -8701,7 +9105,7 @@ function ConfirmMergeRequestDialog({
|
|
|
8701
9105
|
justifyContent: "center",
|
|
8702
9106
|
alignSelf: "stretch"
|
|
8703
9107
|
};
|
|
8704
|
-
return /* @__PURE__ */
|
|
9108
|
+
return /* @__PURE__ */ jsxs39(
|
|
8705
9109
|
Modal,
|
|
8706
9110
|
{
|
|
8707
9111
|
visible,
|
|
@@ -8712,7 +9116,7 @@ function ConfirmMergeRequestDialog({
|
|
|
8712
9116
|
backgroundColor: theme.colors.background
|
|
8713
9117
|
},
|
|
8714
9118
|
children: [
|
|
8715
|
-
/* @__PURE__ */
|
|
9119
|
+
/* @__PURE__ */ jsx62(View48, { children: /* @__PURE__ */ jsx62(
|
|
8716
9120
|
Text,
|
|
8717
9121
|
{
|
|
8718
9122
|
style: {
|
|
@@ -8724,9 +9128,9 @@ function ConfirmMergeRequestDialog({
|
|
|
8724
9128
|
children: "Are you sure you want to approve this merge request?"
|
|
8725
9129
|
}
|
|
8726
9130
|
) }),
|
|
8727
|
-
/* @__PURE__ */
|
|
8728
|
-
/* @__PURE__ */
|
|
8729
|
-
|
|
9131
|
+
/* @__PURE__ */ jsxs39(View48, { style: { marginTop: 16 }, children: [
|
|
9132
|
+
/* @__PURE__ */ jsx62(
|
|
9133
|
+
View48,
|
|
8730
9134
|
{
|
|
8731
9135
|
style: [
|
|
8732
9136
|
fullWidthButtonBase,
|
|
@@ -8735,22 +9139,22 @@ function ConfirmMergeRequestDialog({
|
|
|
8735
9139
|
opacity: canConfirm ? 1 : 0.5
|
|
8736
9140
|
}
|
|
8737
9141
|
],
|
|
8738
|
-
children: /* @__PURE__ */
|
|
8739
|
-
|
|
9142
|
+
children: /* @__PURE__ */ jsx62(
|
|
9143
|
+
Pressable19,
|
|
8740
9144
|
{
|
|
8741
9145
|
accessibilityRole: "button",
|
|
8742
9146
|
accessibilityLabel: "Approve Merge",
|
|
8743
9147
|
disabled: !canConfirm,
|
|
8744
9148
|
onPress: handleConfirm,
|
|
8745
9149
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
8746
|
-
children: /* @__PURE__ */
|
|
9150
|
+
children: /* @__PURE__ */ jsx62(Text, { style: { textAlign: "center", color: theme.colors.onPrimary }, children: "Approve Merge" })
|
|
8747
9151
|
}
|
|
8748
9152
|
)
|
|
8749
9153
|
}
|
|
8750
9154
|
),
|
|
8751
|
-
/* @__PURE__ */
|
|
8752
|
-
/* @__PURE__ */
|
|
8753
|
-
|
|
9155
|
+
/* @__PURE__ */ jsx62(View48, { style: { height: 8 } }),
|
|
9156
|
+
/* @__PURE__ */ jsx62(
|
|
9157
|
+
View48,
|
|
8754
9158
|
{
|
|
8755
9159
|
style: [
|
|
8756
9160
|
fullWidthButtonBase,
|
|
@@ -8761,22 +9165,22 @@ function ConfirmMergeRequestDialog({
|
|
|
8761
9165
|
opacity: isBuilding || !mergeRequest ? 0.5 : 1
|
|
8762
9166
|
}
|
|
8763
9167
|
],
|
|
8764
|
-
children: /* @__PURE__ */
|
|
8765
|
-
|
|
9168
|
+
children: /* @__PURE__ */ jsx62(
|
|
9169
|
+
Pressable19,
|
|
8766
9170
|
{
|
|
8767
9171
|
accessibilityRole: "button",
|
|
8768
9172
|
accessibilityLabel: isBuilding ? "Preparing\u2026" : "Test edits first",
|
|
8769
9173
|
disabled: isBuilding || !mergeRequest,
|
|
8770
9174
|
onPress: handleTestFirst,
|
|
8771
9175
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
8772
|
-
children: /* @__PURE__ */
|
|
9176
|
+
children: /* @__PURE__ */ jsx62(Text, { style: { textAlign: "center", color: theme.colors.text }, children: isBuilding ? "Preparing\u2026" : "Test edits first" })
|
|
8773
9177
|
}
|
|
8774
9178
|
)
|
|
8775
9179
|
}
|
|
8776
9180
|
),
|
|
8777
|
-
/* @__PURE__ */
|
|
8778
|
-
/* @__PURE__ */
|
|
8779
|
-
|
|
9181
|
+
/* @__PURE__ */ jsx62(View48, { style: { height: 8 } }),
|
|
9182
|
+
/* @__PURE__ */ jsx62(
|
|
9183
|
+
View48,
|
|
8780
9184
|
{
|
|
8781
9185
|
style: [
|
|
8782
9186
|
fullWidthButtonBase,
|
|
@@ -8786,14 +9190,14 @@ function ConfirmMergeRequestDialog({
|
|
|
8786
9190
|
borderColor: theme.colors.border
|
|
8787
9191
|
}
|
|
8788
9192
|
],
|
|
8789
|
-
children: /* @__PURE__ */
|
|
8790
|
-
|
|
9193
|
+
children: /* @__PURE__ */ jsx62(
|
|
9194
|
+
Pressable19,
|
|
8791
9195
|
{
|
|
8792
9196
|
accessibilityRole: "button",
|
|
8793
9197
|
accessibilityLabel: "Cancel",
|
|
8794
9198
|
onPress: close,
|
|
8795
9199
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
8796
|
-
children: /* @__PURE__ */
|
|
9200
|
+
children: /* @__PURE__ */ jsx62(Text, { style: { textAlign: "center", color: theme.colors.text }, children: "Cancel" })
|
|
8797
9201
|
}
|
|
8798
9202
|
)
|
|
8799
9203
|
}
|
|
@@ -8805,7 +9209,7 @@ function ConfirmMergeRequestDialog({
|
|
|
8805
9209
|
}
|
|
8806
9210
|
|
|
8807
9211
|
// src/studio/ui/ConfirmMergeFlow.tsx
|
|
8808
|
-
import { jsx as
|
|
9212
|
+
import { jsx as jsx63 } from "react/jsx-runtime";
|
|
8809
9213
|
function ConfirmMergeFlow({
|
|
8810
9214
|
visible,
|
|
8811
9215
|
onOpenChange,
|
|
@@ -8816,7 +9220,7 @@ function ConfirmMergeFlow({
|
|
|
8816
9220
|
onConfirm,
|
|
8817
9221
|
onTestFirst
|
|
8818
9222
|
}) {
|
|
8819
|
-
return /* @__PURE__ */
|
|
9223
|
+
return /* @__PURE__ */ jsx63(
|
|
8820
9224
|
ConfirmMergeRequestDialog,
|
|
8821
9225
|
{
|
|
8822
9226
|
visible,
|
|
@@ -8838,7 +9242,8 @@ function ConfirmMergeFlow({
|
|
|
8838
9242
|
}
|
|
8839
9243
|
|
|
8840
9244
|
// src/studio/hooks/useOptimisticChatMessages.ts
|
|
8841
|
-
import * as
|
|
9245
|
+
import * as React46 from "react";
|
|
9246
|
+
import { Image as Image5 } from "react-native";
|
|
8842
9247
|
function makeOptimisticId() {
|
|
8843
9248
|
return `optimistic:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 10)}`;
|
|
8844
9249
|
}
|
|
@@ -8849,6 +9254,28 @@ function toEpochMs2(createdAt) {
|
|
|
8849
9254
|
const t = Date.parse(String(createdAt));
|
|
8850
9255
|
return Number.isFinite(t) ? t : 0;
|
|
8851
9256
|
}
|
|
9257
|
+
async function resolveAttachmentDimensions(uris) {
|
|
9258
|
+
return Promise.all(
|
|
9259
|
+
uris.map(
|
|
9260
|
+
async (uri) => {
|
|
9261
|
+
try {
|
|
9262
|
+
const { width, height } = await new Promise((resolve, reject) => {
|
|
9263
|
+
Image5.getSize(
|
|
9264
|
+
uri,
|
|
9265
|
+
(w, h) => resolve({ width: w, height: h }),
|
|
9266
|
+
(err) => reject(err)
|
|
9267
|
+
);
|
|
9268
|
+
});
|
|
9269
|
+
if (width > 0 && height > 0) {
|
|
9270
|
+
return { uri, width: Math.round(width), height: Math.round(height) };
|
|
9271
|
+
}
|
|
9272
|
+
} catch {
|
|
9273
|
+
}
|
|
9274
|
+
return { uri };
|
|
9275
|
+
}
|
|
9276
|
+
)
|
|
9277
|
+
);
|
|
9278
|
+
}
|
|
8852
9279
|
function isOptimisticResolvedByServer(chatMessages, o) {
|
|
8853
9280
|
if (o.failed) return false;
|
|
8854
9281
|
const normalize = (s) => s.trim();
|
|
@@ -8877,11 +9304,11 @@ function useOptimisticChatMessages({
|
|
|
8877
9304
|
chatMessages,
|
|
8878
9305
|
onSendChat
|
|
8879
9306
|
}) {
|
|
8880
|
-
const [optimisticChat, setOptimisticChat] =
|
|
8881
|
-
|
|
9307
|
+
const [optimisticChat, setOptimisticChat] = React46.useState([]);
|
|
9308
|
+
React46.useEffect(() => {
|
|
8882
9309
|
setOptimisticChat([]);
|
|
8883
9310
|
}, [threadId]);
|
|
8884
|
-
const messages =
|
|
9311
|
+
const messages = React46.useMemo(() => {
|
|
8885
9312
|
if (!optimisticChat || optimisticChat.length === 0) return chatMessages;
|
|
8886
9313
|
const unresolved = optimisticChat.filter((o) => !isOptimisticResolvedByServer(chatMessages, o));
|
|
8887
9314
|
if (unresolved.length === 0) return chatMessages;
|
|
@@ -8891,13 +9318,22 @@ function useOptimisticChatMessages({
|
|
|
8891
9318
|
content: o.content,
|
|
8892
9319
|
createdAt: o.createdAtIso,
|
|
8893
9320
|
kind: "optimistic",
|
|
9321
|
+
attachments: (o.attachments ?? []).map((attachment, index) => ({
|
|
9322
|
+
id: `${o.id}:attachment:${index}`,
|
|
9323
|
+
name: `attachment-${index + 1}.png`,
|
|
9324
|
+
mimeType: "image/png",
|
|
9325
|
+
size: 1,
|
|
9326
|
+
uri: attachment.uri,
|
|
9327
|
+
width: attachment.width,
|
|
9328
|
+
height: attachment.height
|
|
9329
|
+
})),
|
|
8894
9330
|
meta: o.failed ? { kind: "optimistic", event: "send.failed", status: "error" } : { kind: "optimistic", event: "send.pending", status: "info" }
|
|
8895
9331
|
}));
|
|
8896
9332
|
const merged = [...chatMessages, ...optimisticAsChat];
|
|
8897
9333
|
merged.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
8898
9334
|
return merged;
|
|
8899
9335
|
}, [chatMessages, optimisticChat]);
|
|
8900
|
-
|
|
9336
|
+
React46.useEffect(() => {
|
|
8901
9337
|
if (optimisticChat.length === 0) return;
|
|
8902
9338
|
setOptimisticChat((prev) => {
|
|
8903
9339
|
if (prev.length === 0) return prev;
|
|
@@ -8905,7 +9341,7 @@ function useOptimisticChatMessages({
|
|
|
8905
9341
|
return next.length === prev.length ? prev : next;
|
|
8906
9342
|
});
|
|
8907
9343
|
}, [chatMessages, optimisticChat.length]);
|
|
8908
|
-
const onSend =
|
|
9344
|
+
const onSend = React46.useCallback(
|
|
8909
9345
|
async (text, attachments) => {
|
|
8910
9346
|
if (disableOptimistic) {
|
|
8911
9347
|
await onSendChat(text, attachments);
|
|
@@ -8914,7 +9350,7 @@ function useOptimisticChatMessages({
|
|
|
8914
9350
|
const createdAtIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
8915
9351
|
const baseServerLastId = chatMessages.length > 0 ? chatMessages[chatMessages.length - 1].id : null;
|
|
8916
9352
|
const id = makeOptimisticId();
|
|
8917
|
-
const normalizedAttachments = attachments && attachments.length > 0 ?
|
|
9353
|
+
const normalizedAttachments = attachments && attachments.length > 0 ? await resolveAttachmentDimensions(attachments) : void 0;
|
|
8918
9354
|
setOptimisticChat((prev) => [
|
|
8919
9355
|
...prev,
|
|
8920
9356
|
{
|
|
@@ -8933,8 +9369,9 @@ function useOptimisticChatMessages({
|
|
|
8933
9369
|
},
|
|
8934
9370
|
[chatMessages, disableOptimistic, onSendChat]
|
|
8935
9371
|
);
|
|
8936
|
-
const onRetry =
|
|
9372
|
+
const onRetry = React46.useCallback(
|
|
8937
9373
|
async (messageId) => {
|
|
9374
|
+
var _a;
|
|
8938
9375
|
if (disableOptimistic) return;
|
|
8939
9376
|
const target = optimisticChat.find((m) => m.id === messageId);
|
|
8940
9377
|
if (!target || target.retrying) return;
|
|
@@ -8945,7 +9382,10 @@ function useOptimisticChatMessages({
|
|
|
8945
9382
|
)
|
|
8946
9383
|
);
|
|
8947
9384
|
try {
|
|
8948
|
-
await onSendChat(
|
|
9385
|
+
await onSendChat(
|
|
9386
|
+
target.content,
|
|
9387
|
+
(_a = target.attachments) == null ? void 0 : _a.map((att) => att.uri)
|
|
9388
|
+
);
|
|
8949
9389
|
setOptimisticChat(
|
|
8950
9390
|
(prev) => prev.map((m) => m.id === messageId ? { ...m, retrying: false } : m)
|
|
8951
9391
|
);
|
|
@@ -8957,7 +9397,7 @@ function useOptimisticChatMessages({
|
|
|
8957
9397
|
},
|
|
8958
9398
|
[chatMessages, disableOptimistic, onSendChat, optimisticChat]
|
|
8959
9399
|
);
|
|
8960
|
-
const isRetrying =
|
|
9400
|
+
const isRetrying = React46.useCallback(
|
|
8961
9401
|
(messageId) => {
|
|
8962
9402
|
return optimisticChat.some((m) => m.id === messageId && m.retrying);
|
|
8963
9403
|
},
|
|
@@ -8974,24 +9414,24 @@ import {
|
|
|
8974
9414
|
|
|
8975
9415
|
// src/components/icons/RemixUpIcon.tsx
|
|
8976
9416
|
import Svg3, { Path as Path3 } from "react-native-svg";
|
|
8977
|
-
import { jsx as
|
|
9417
|
+
import { jsx as jsx64, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
8978
9418
|
function RemixUpIcon({ width = 24, height = 24, ...props }) {
|
|
8979
|
-
return /* @__PURE__ */
|
|
8980
|
-
/* @__PURE__ */
|
|
9419
|
+
return /* @__PURE__ */ jsxs40(Svg3, { viewBox: "0 0 70 49", width, height, fill: "none", ...props, children: [
|
|
9420
|
+
/* @__PURE__ */ jsx64(
|
|
8981
9421
|
Path3,
|
|
8982
9422
|
{
|
|
8983
9423
|
d: "M34.706 7.62939e-05L34.7656 2.28882e-05L21.44 13.2661L0 34.8401L13.266 48.1061L34.706 26.5321L21.44 13.2661L34.706 7.62939e-05Z",
|
|
8984
9424
|
fill: "#00CBC0"
|
|
8985
9425
|
}
|
|
8986
9426
|
),
|
|
8987
|
-
/* @__PURE__ */
|
|
9427
|
+
/* @__PURE__ */ jsx64(
|
|
8988
9428
|
Path3,
|
|
8989
9429
|
{
|
|
8990
9430
|
d: "M47.972 13.266L34.7656 2.28882e-05L34.706 7.62939e-05L47.972 13.266L34.706 26.5321L56.28 48.106L69.546 34.84L47.972 13.266Z",
|
|
8991
9431
|
fill: "#FF1820"
|
|
8992
9432
|
}
|
|
8993
9433
|
),
|
|
8994
|
-
/* @__PURE__ */
|
|
9434
|
+
/* @__PURE__ */ jsx64(
|
|
8995
9435
|
Path3,
|
|
8996
9436
|
{
|
|
8997
9437
|
d: "M34.7656 2.28882e-05L21.44 13.2661L34.706 26.5321L47.972 13.266L34.7656 2.28882e-05Z",
|
|
@@ -9002,7 +9442,7 @@ function RemixUpIcon({ width = 24, height = 24, ...props }) {
|
|
|
9002
9442
|
}
|
|
9003
9443
|
|
|
9004
9444
|
// src/studio/ui/StudioOverlay.tsx
|
|
9005
|
-
import { Fragment as
|
|
9445
|
+
import { Fragment as Fragment8, jsx as jsx65, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
9006
9446
|
function StudioOverlay({
|
|
9007
9447
|
captureTargetRef,
|
|
9008
9448
|
app,
|
|
@@ -9033,6 +9473,7 @@ function StudioOverlay({
|
|
|
9033
9473
|
chatSending,
|
|
9034
9474
|
chatShowTypingIndicator,
|
|
9035
9475
|
onSendChat,
|
|
9476
|
+
onChatAttachmentLoadError,
|
|
9036
9477
|
chatQueueItems,
|
|
9037
9478
|
onRemoveQueueItem,
|
|
9038
9479
|
chatProgress,
|
|
@@ -9046,15 +9487,15 @@ function StudioOverlay({
|
|
|
9046
9487
|
onSwitchRelatedApp
|
|
9047
9488
|
}) {
|
|
9048
9489
|
const theme = useTheme();
|
|
9049
|
-
const { width } =
|
|
9050
|
-
const [sheetOpen, setSheetOpen] =
|
|
9051
|
-
const sheetOpenRef =
|
|
9052
|
-
const pendingNavigateHomeRef =
|
|
9053
|
-
const [activePage, setActivePage] =
|
|
9054
|
-
const [drawing, setDrawing] =
|
|
9055
|
-
const [chatAttachments, setChatAttachments] =
|
|
9056
|
-
const [commentsAppId, setCommentsAppId] =
|
|
9057
|
-
const [commentsCount, setCommentsCount] =
|
|
9490
|
+
const { width } = useWindowDimensions5();
|
|
9491
|
+
const [sheetOpen, setSheetOpen] = React47.useState(false);
|
|
9492
|
+
const sheetOpenRef = React47.useRef(sheetOpen);
|
|
9493
|
+
const pendingNavigateHomeRef = React47.useRef(false);
|
|
9494
|
+
const [activePage, setActivePage] = React47.useState("preview");
|
|
9495
|
+
const [drawing, setDrawing] = React47.useState(false);
|
|
9496
|
+
const [chatAttachments, setChatAttachments] = React47.useState([]);
|
|
9497
|
+
const [commentsAppId, setCommentsAppId] = React47.useState(null);
|
|
9498
|
+
const [commentsCount, setCommentsCount] = React47.useState(null);
|
|
9058
9499
|
const threadId = (app == null ? void 0 : app.threadId) ?? null;
|
|
9059
9500
|
const isForking = chatForking || (app == null ? void 0 : app.status) === "forking";
|
|
9060
9501
|
const isBubbleLoading = (app == null ? void 0 : app.status) === "editing" || isBaseBundleDownloading;
|
|
@@ -9067,24 +9508,24 @@ function StudioOverlay({
|
|
|
9067
9508
|
chatMessages,
|
|
9068
9509
|
onSendChat
|
|
9069
9510
|
});
|
|
9070
|
-
const [confirmMrId, setConfirmMrId] =
|
|
9071
|
-
const confirmMr =
|
|
9511
|
+
const [confirmMrId, setConfirmMrId] = React47.useState(null);
|
|
9512
|
+
const confirmMr = React47.useMemo(
|
|
9072
9513
|
() => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
|
|
9073
9514
|
[confirmMrId, incomingMergeRequests]
|
|
9074
9515
|
);
|
|
9075
|
-
const handleSheetOpenChange =
|
|
9516
|
+
const handleSheetOpenChange = React47.useCallback((open) => {
|
|
9076
9517
|
setSheetOpen(open);
|
|
9077
9518
|
if (!open) Keyboard5.dismiss();
|
|
9078
9519
|
}, []);
|
|
9079
|
-
const closeSheet =
|
|
9520
|
+
const closeSheet = React47.useCallback(() => {
|
|
9080
9521
|
handleSheetOpenChange(false);
|
|
9081
9522
|
}, [handleSheetOpenChange]);
|
|
9082
|
-
const openSheet =
|
|
9083
|
-
const goToChat =
|
|
9523
|
+
const openSheet = React47.useCallback(() => setSheetOpen(true), []);
|
|
9524
|
+
const goToChat = React47.useCallback(() => {
|
|
9084
9525
|
setActivePage("chat");
|
|
9085
9526
|
openSheet();
|
|
9086
9527
|
}, [openSheet]);
|
|
9087
|
-
const backToPreview =
|
|
9528
|
+
const backToPreview = React47.useCallback(() => {
|
|
9088
9529
|
if (Platform11.OS !== "ios") {
|
|
9089
9530
|
Keyboard5.dismiss();
|
|
9090
9531
|
setActivePage("preview");
|
|
@@ -9102,11 +9543,11 @@ function StudioOverlay({
|
|
|
9102
9543
|
const t = setTimeout(finalize, 350);
|
|
9103
9544
|
Keyboard5.dismiss();
|
|
9104
9545
|
}, []);
|
|
9105
|
-
const startDraw =
|
|
9546
|
+
const startDraw = React47.useCallback(() => {
|
|
9106
9547
|
setDrawing(true);
|
|
9107
9548
|
closeSheet();
|
|
9108
9549
|
}, [closeSheet]);
|
|
9109
|
-
const handleDrawCapture =
|
|
9550
|
+
const handleDrawCapture = React47.useCallback(
|
|
9110
9551
|
(dataUrl) => {
|
|
9111
9552
|
setChatAttachments((prev) => [...prev, dataUrl]);
|
|
9112
9553
|
setDrawing(false);
|
|
@@ -9115,7 +9556,7 @@ function StudioOverlay({
|
|
|
9115
9556
|
},
|
|
9116
9557
|
[openSheet]
|
|
9117
9558
|
);
|
|
9118
|
-
const toggleSheet =
|
|
9559
|
+
const toggleSheet = React47.useCallback(async () => {
|
|
9119
9560
|
if (!sheetOpen) {
|
|
9120
9561
|
const shouldExitTest = Boolean(testingMrId) || isTesting;
|
|
9121
9562
|
if (shouldExitTest) {
|
|
@@ -9127,7 +9568,7 @@ function StudioOverlay({
|
|
|
9127
9568
|
closeSheet();
|
|
9128
9569
|
}
|
|
9129
9570
|
}, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
|
|
9130
|
-
const handleTestMr =
|
|
9571
|
+
const handleTestMr = React47.useCallback(
|
|
9131
9572
|
async (mr) => {
|
|
9132
9573
|
if (!onTestMr) return;
|
|
9133
9574
|
await onTestMr(mr);
|
|
@@ -9135,7 +9576,7 @@ function StudioOverlay({
|
|
|
9135
9576
|
},
|
|
9136
9577
|
[closeSheet, onTestMr]
|
|
9137
9578
|
);
|
|
9138
|
-
const handleNavigateHome =
|
|
9579
|
+
const handleNavigateHome = React47.useCallback(() => {
|
|
9139
9580
|
if (!onNavigateHome) return;
|
|
9140
9581
|
if (Platform11.OS !== "android") {
|
|
9141
9582
|
onNavigateHome();
|
|
@@ -9152,7 +9593,7 @@ function StudioOverlay({
|
|
|
9152
9593
|
setActivePage("preview");
|
|
9153
9594
|
closeSheet();
|
|
9154
9595
|
}, [closeSheet, onNavigateHome]);
|
|
9155
|
-
const handleSheetDismiss =
|
|
9596
|
+
const handleSheetDismiss = React47.useCallback(() => {
|
|
9156
9597
|
if (Platform11.OS !== "android") return;
|
|
9157
9598
|
if (!pendingNavigateHomeRef.current) return;
|
|
9158
9599
|
pendingNavigateHomeRef.current = false;
|
|
@@ -9160,21 +9601,21 @@ function StudioOverlay({
|
|
|
9160
9601
|
onNavigateHome == null ? void 0 : onNavigateHome();
|
|
9161
9602
|
});
|
|
9162
9603
|
}, [onNavigateHome]);
|
|
9163
|
-
|
|
9604
|
+
React47.useEffect(() => {
|
|
9164
9605
|
if (!sheetOpen) {
|
|
9165
9606
|
return;
|
|
9166
9607
|
}
|
|
9167
9608
|
pendingNavigateHomeRef.current = false;
|
|
9168
9609
|
}, [sheetOpen]);
|
|
9169
|
-
|
|
9610
|
+
React47.useEffect(() => {
|
|
9170
9611
|
return () => {
|
|
9171
9612
|
pendingNavigateHomeRef.current = false;
|
|
9172
9613
|
};
|
|
9173
9614
|
}, []);
|
|
9174
|
-
|
|
9615
|
+
React47.useEffect(() => {
|
|
9175
9616
|
sheetOpenRef.current = sheetOpen;
|
|
9176
9617
|
}, [sheetOpen]);
|
|
9177
|
-
|
|
9618
|
+
React47.useEffect(() => {
|
|
9178
9619
|
const poller = startStudioControlPolling((action) => {
|
|
9179
9620
|
if (action === "show" && !sheetOpenRef.current) openSheet();
|
|
9180
9621
|
if (action === "hide" && sheetOpenRef.current) closeSheet();
|
|
@@ -9182,17 +9623,17 @@ function StudioOverlay({
|
|
|
9182
9623
|
}, studioControlOptions);
|
|
9183
9624
|
return () => poller.stop();
|
|
9184
9625
|
}, [closeSheet, openSheet, studioControlOptions, toggleSheet]);
|
|
9185
|
-
|
|
9626
|
+
React47.useEffect(() => {
|
|
9186
9627
|
void publishComergeStudioUIState(sheetOpen, studioControlOptions);
|
|
9187
9628
|
}, [sheetOpen, studioControlOptions]);
|
|
9188
|
-
return /* @__PURE__ */
|
|
9189
|
-
/* @__PURE__ */
|
|
9190
|
-
/* @__PURE__ */
|
|
9629
|
+
return /* @__PURE__ */ jsxs41(Fragment8, { children: [
|
|
9630
|
+
/* @__PURE__ */ jsx65(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
|
|
9631
|
+
/* @__PURE__ */ jsx65(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, onDismiss: handleSheetDismiss, children: /* @__PURE__ */ jsx65(
|
|
9191
9632
|
StudioSheetPager,
|
|
9192
9633
|
{
|
|
9193
9634
|
activePage,
|
|
9194
9635
|
width,
|
|
9195
|
-
preview: /* @__PURE__ */
|
|
9636
|
+
preview: /* @__PURE__ */ jsx65(
|
|
9196
9637
|
PreviewPanel,
|
|
9197
9638
|
{
|
|
9198
9639
|
app,
|
|
@@ -9226,7 +9667,7 @@ function StudioOverlay({
|
|
|
9226
9667
|
onSwitchRelatedApp
|
|
9227
9668
|
}
|
|
9228
9669
|
),
|
|
9229
|
-
chat: /* @__PURE__ */
|
|
9670
|
+
chat: /* @__PURE__ */ jsx65(
|
|
9230
9671
|
ChatPanel,
|
|
9231
9672
|
{
|
|
9232
9673
|
messages: optimistic.messages,
|
|
@@ -9246,6 +9687,7 @@ function StudioOverlay({
|
|
|
9246
9687
|
onSend: optimistic.onSend,
|
|
9247
9688
|
onRetryMessage: optimistic.onRetry,
|
|
9248
9689
|
isRetryingMessage: optimistic.isRetrying,
|
|
9690
|
+
onAttachmentLoadError: onChatAttachmentLoadError,
|
|
9249
9691
|
queueItems: queueItemsForChat,
|
|
9250
9692
|
onRemoveQueueItem,
|
|
9251
9693
|
progress: chatProgress
|
|
@@ -9253,7 +9695,7 @@ function StudioOverlay({
|
|
|
9253
9695
|
)
|
|
9254
9696
|
}
|
|
9255
9697
|
) }),
|
|
9256
|
-
showBubble && /* @__PURE__ */
|
|
9698
|
+
showBubble && /* @__PURE__ */ jsx65(
|
|
9257
9699
|
Bubble,
|
|
9258
9700
|
{
|
|
9259
9701
|
visible: !sheetOpen && !drawing,
|
|
@@ -9262,10 +9704,10 @@ function StudioOverlay({
|
|
|
9262
9704
|
onPress: toggleSheet,
|
|
9263
9705
|
isLoading: isBubbleLoading,
|
|
9264
9706
|
loadingBorderTone: isBaseBundleDownloading ? "warning" : "default",
|
|
9265
|
-
children: /* @__PURE__ */
|
|
9707
|
+
children: /* @__PURE__ */ jsx65(View49, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: isBubbleLoading ? /* @__PURE__ */ jsx65(RemixXLoopLottie, { size: 24 }) : /* @__PURE__ */ jsx65(RemixUpIcon, { width: 24, height: 24 }) })
|
|
9266
9708
|
}
|
|
9267
9709
|
),
|
|
9268
|
-
/* @__PURE__ */
|
|
9710
|
+
/* @__PURE__ */ jsx65(
|
|
9269
9711
|
DrawModeOverlay,
|
|
9270
9712
|
{
|
|
9271
9713
|
visible: drawing,
|
|
@@ -9274,7 +9716,7 @@ function StudioOverlay({
|
|
|
9274
9716
|
onCapture: handleDrawCapture
|
|
9275
9717
|
}
|
|
9276
9718
|
),
|
|
9277
|
-
/* @__PURE__ */
|
|
9719
|
+
/* @__PURE__ */ jsx65(
|
|
9278
9720
|
ConfirmMergeFlow,
|
|
9279
9721
|
{
|
|
9280
9722
|
visible: Boolean(confirmMr),
|
|
@@ -9288,7 +9730,7 @@ function StudioOverlay({
|
|
|
9288
9730
|
onTestFirst: handleTestMr
|
|
9289
9731
|
}
|
|
9290
9732
|
),
|
|
9291
|
-
/* @__PURE__ */
|
|
9733
|
+
/* @__PURE__ */ jsx65(
|
|
9292
9734
|
AppCommentsSheet,
|
|
9293
9735
|
{
|
|
9294
9736
|
appId: commentsAppId,
|
|
@@ -9301,7 +9743,7 @@ function StudioOverlay({
|
|
|
9301
9743
|
}
|
|
9302
9744
|
|
|
9303
9745
|
// src/studio/hooks/useEditQueue.ts
|
|
9304
|
-
import * as
|
|
9746
|
+
import * as React48 from "react";
|
|
9305
9747
|
|
|
9306
9748
|
// src/data/apps/edit-queue/remote.ts
|
|
9307
9749
|
var EditQueueRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -9410,17 +9852,17 @@ var editQueueRepository = new EditQueueRepositoryImpl(
|
|
|
9410
9852
|
|
|
9411
9853
|
// src/studio/hooks/useEditQueue.ts
|
|
9412
9854
|
function useEditQueue(appId) {
|
|
9413
|
-
const [items, setItems] =
|
|
9414
|
-
const [loading, setLoading] =
|
|
9415
|
-
const [error, setError] =
|
|
9416
|
-
const activeRequestIdRef =
|
|
9855
|
+
const [items, setItems] = React48.useState([]);
|
|
9856
|
+
const [loading, setLoading] = React48.useState(false);
|
|
9857
|
+
const [error, setError] = React48.useState(null);
|
|
9858
|
+
const activeRequestIdRef = React48.useRef(0);
|
|
9417
9859
|
const foregroundSignal = useForegroundSignal(Boolean(appId));
|
|
9418
|
-
const upsertSorted =
|
|
9860
|
+
const upsertSorted = React48.useCallback((prev, nextItem) => {
|
|
9419
9861
|
const next = prev.some((x) => x.id === nextItem.id) ? prev.map((x) => x.id === nextItem.id ? nextItem : x) : [...prev, nextItem];
|
|
9420
9862
|
next.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
9421
9863
|
return next;
|
|
9422
9864
|
}, []);
|
|
9423
|
-
const refetch =
|
|
9865
|
+
const refetch = React48.useCallback(async () => {
|
|
9424
9866
|
if (!appId) {
|
|
9425
9867
|
setItems([]);
|
|
9426
9868
|
return;
|
|
@@ -9440,10 +9882,10 @@ function useEditQueue(appId) {
|
|
|
9440
9882
|
if (activeRequestIdRef.current === requestId) setLoading(false);
|
|
9441
9883
|
}
|
|
9442
9884
|
}, [appId]);
|
|
9443
|
-
|
|
9885
|
+
React48.useEffect(() => {
|
|
9444
9886
|
void refetch();
|
|
9445
9887
|
}, [refetch]);
|
|
9446
|
-
|
|
9888
|
+
React48.useEffect(() => {
|
|
9447
9889
|
if (!appId) return;
|
|
9448
9890
|
const unsubscribe = editQueueRepository.subscribeEditQueue(appId, {
|
|
9449
9891
|
onInsert: (item) => setItems((prev) => upsertSorted(prev, item)),
|
|
@@ -9452,7 +9894,7 @@ function useEditQueue(appId) {
|
|
|
9452
9894
|
});
|
|
9453
9895
|
return unsubscribe;
|
|
9454
9896
|
}, [appId, upsertSorted, foregroundSignal]);
|
|
9455
|
-
|
|
9897
|
+
React48.useEffect(() => {
|
|
9456
9898
|
if (!appId) return;
|
|
9457
9899
|
if (foregroundSignal <= 0) return;
|
|
9458
9900
|
void refetch();
|
|
@@ -9461,16 +9903,16 @@ function useEditQueue(appId) {
|
|
|
9461
9903
|
}
|
|
9462
9904
|
|
|
9463
9905
|
// src/studio/hooks/useEditQueueActions.ts
|
|
9464
|
-
import * as
|
|
9906
|
+
import * as React49 from "react";
|
|
9465
9907
|
function useEditQueueActions(appId) {
|
|
9466
|
-
const update =
|
|
9908
|
+
const update = React49.useCallback(
|
|
9467
9909
|
async (queueItemId, payload) => {
|
|
9468
9910
|
if (!appId) return;
|
|
9469
9911
|
await editQueueRepository.update(appId, queueItemId, payload);
|
|
9470
9912
|
},
|
|
9471
9913
|
[appId]
|
|
9472
9914
|
);
|
|
9473
|
-
const cancel =
|
|
9915
|
+
const cancel = React49.useCallback(
|
|
9474
9916
|
async (queueItemId) => {
|
|
9475
9917
|
if (!appId) return;
|
|
9476
9918
|
await editQueueRepository.cancel(appId, queueItemId);
|
|
@@ -9481,7 +9923,7 @@ function useEditQueueActions(appId) {
|
|
|
9481
9923
|
}
|
|
9482
9924
|
|
|
9483
9925
|
// src/studio/hooks/useAgentRunProgress.ts
|
|
9484
|
-
import * as
|
|
9926
|
+
import * as React50 from "react";
|
|
9485
9927
|
|
|
9486
9928
|
// src/data/agent-progress/repository.ts
|
|
9487
9929
|
function mapRun(row) {
|
|
@@ -9747,23 +10189,23 @@ function deriveView(run, events, nowMs) {
|
|
|
9747
10189
|
function useAgentRunProgress(threadId, opts) {
|
|
9748
10190
|
var _a;
|
|
9749
10191
|
const enabled = Boolean((opts == null ? void 0 : opts.enabled) ?? true);
|
|
9750
|
-
const [run, setRun] =
|
|
9751
|
-
const [events, setEvents] =
|
|
9752
|
-
const [loading, setLoading] =
|
|
9753
|
-
const [error, setError] =
|
|
9754
|
-
const activeRequestIdRef =
|
|
9755
|
-
const lastSeqRef =
|
|
9756
|
-
const runRef =
|
|
10192
|
+
const [run, setRun] = React50.useState(null);
|
|
10193
|
+
const [events, setEvents] = React50.useState([]);
|
|
10194
|
+
const [loading, setLoading] = React50.useState(false);
|
|
10195
|
+
const [error, setError] = React50.useState(null);
|
|
10196
|
+
const activeRequestIdRef = React50.useRef(0);
|
|
10197
|
+
const lastSeqRef = React50.useRef(0);
|
|
10198
|
+
const runRef = React50.useRef(null);
|
|
9757
10199
|
const foregroundSignal = useForegroundSignal(Boolean(threadId) && enabled);
|
|
9758
|
-
const [bundleTick, setBundleTick] =
|
|
9759
|
-
|
|
10200
|
+
const [bundleTick, setBundleTick] = React50.useState(0);
|
|
10201
|
+
React50.useEffect(() => {
|
|
9760
10202
|
lastSeqRef.current = 0;
|
|
9761
10203
|
runRef.current = null;
|
|
9762
10204
|
}, [threadId]);
|
|
9763
|
-
|
|
10205
|
+
React50.useEffect(() => {
|
|
9764
10206
|
runRef.current = run;
|
|
9765
10207
|
}, [run]);
|
|
9766
|
-
const refetch =
|
|
10208
|
+
const refetch = React50.useCallback(async () => {
|
|
9767
10209
|
if (!threadId || !enabled) {
|
|
9768
10210
|
setRun(null);
|
|
9769
10211
|
setEvents([]);
|
|
@@ -9799,15 +10241,15 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9799
10241
|
if (activeRequestIdRef.current === requestId) setLoading(false);
|
|
9800
10242
|
}
|
|
9801
10243
|
}, [enabled, threadId]);
|
|
9802
|
-
|
|
10244
|
+
React50.useEffect(() => {
|
|
9803
10245
|
void refetch();
|
|
9804
10246
|
}, [refetch]);
|
|
9805
|
-
|
|
10247
|
+
React50.useEffect(() => {
|
|
9806
10248
|
if (!threadId || !enabled) return;
|
|
9807
10249
|
if (foregroundSignal <= 0) return;
|
|
9808
10250
|
void refetch();
|
|
9809
10251
|
}, [enabled, foregroundSignal, refetch, threadId]);
|
|
9810
|
-
|
|
10252
|
+
React50.useEffect(() => {
|
|
9811
10253
|
if (!threadId || !enabled) return;
|
|
9812
10254
|
const unsubRuns = agentProgressRepository.subscribeThreadRuns(threadId, {
|
|
9813
10255
|
onInsert: (nextRun) => {
|
|
@@ -9837,7 +10279,7 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9837
10279
|
});
|
|
9838
10280
|
return unsubRuns;
|
|
9839
10281
|
}, [enabled, threadId, foregroundSignal]);
|
|
9840
|
-
|
|
10282
|
+
React50.useEffect(() => {
|
|
9841
10283
|
if (!enabled || !(run == null ? void 0 : run.id)) return;
|
|
9842
10284
|
const runId = run.id;
|
|
9843
10285
|
const processIncoming = (incoming) => {
|
|
@@ -9869,8 +10311,8 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9869
10311
|
});
|
|
9870
10312
|
return unsubscribe;
|
|
9871
10313
|
}, [enabled, run == null ? void 0 : run.id, foregroundSignal]);
|
|
9872
|
-
const view =
|
|
9873
|
-
|
|
10314
|
+
const view = React50.useMemo(() => deriveView(run, events, Date.now()), [bundleTick, events, run]);
|
|
10315
|
+
React50.useEffect(() => {
|
|
9874
10316
|
var _a2;
|
|
9875
10317
|
if (!((_a2 = view.bundle) == null ? void 0 : _a2.active)) return;
|
|
9876
10318
|
const interval = setInterval(() => {
|
|
@@ -9883,13 +10325,13 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9883
10325
|
}
|
|
9884
10326
|
|
|
9885
10327
|
// src/studio/hooks/useRelatedApps.ts
|
|
9886
|
-
import * as
|
|
10328
|
+
import * as React51 from "react";
|
|
9887
10329
|
function useRelatedApps(appId) {
|
|
9888
|
-
const [relatedApps, setRelatedApps] =
|
|
9889
|
-
const [loading, setLoading] =
|
|
9890
|
-
const [error, setError] =
|
|
9891
|
-
const requestSeqRef =
|
|
9892
|
-
const fetchRelatedApps =
|
|
10330
|
+
const [relatedApps, setRelatedApps] = React51.useState(null);
|
|
10331
|
+
const [loading, setLoading] = React51.useState(false);
|
|
10332
|
+
const [error, setError] = React51.useState(null);
|
|
10333
|
+
const requestSeqRef = React51.useRef(0);
|
|
10334
|
+
const fetchRelatedApps = React51.useCallback(async () => {
|
|
9893
10335
|
if (!appId) {
|
|
9894
10336
|
setRelatedApps(null);
|
|
9895
10337
|
setError(null);
|
|
@@ -9915,7 +10357,7 @@ function useRelatedApps(appId) {
|
|
|
9915
10357
|
}
|
|
9916
10358
|
}
|
|
9917
10359
|
}, [appId]);
|
|
9918
|
-
|
|
10360
|
+
React51.useEffect(() => {
|
|
9919
10361
|
void fetchRelatedApps();
|
|
9920
10362
|
}, [fetchRelatedApps]);
|
|
9921
10363
|
return {
|
|
@@ -9927,7 +10369,7 @@ function useRelatedApps(appId) {
|
|
|
9927
10369
|
}
|
|
9928
10370
|
|
|
9929
10371
|
// src/studio/ComergeStudio.tsx
|
|
9930
|
-
import { jsx as
|
|
10372
|
+
import { jsx as jsx66, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
9931
10373
|
function ComergeStudio({
|
|
9932
10374
|
appId,
|
|
9933
10375
|
clientKey: clientKey2,
|
|
@@ -9943,13 +10385,13 @@ function ComergeStudio({
|
|
|
9943
10385
|
embeddedBaseBundles,
|
|
9944
10386
|
onSystemEvent
|
|
9945
10387
|
}) {
|
|
9946
|
-
const [activeAppId, setActiveAppId] =
|
|
9947
|
-
const [runtimeAppId, setRuntimeAppId] =
|
|
9948
|
-
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] =
|
|
9949
|
-
const didSyncFromHostRef =
|
|
9950
|
-
const lastNotifiedRef =
|
|
9951
|
-
const platform =
|
|
9952
|
-
const notifyActiveAppChanged =
|
|
10388
|
+
const [activeAppId, setActiveAppId] = React52.useState(appId);
|
|
10389
|
+
const [runtimeAppId, setRuntimeAppId] = React52.useState(appId);
|
|
10390
|
+
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React52.useState(null);
|
|
10391
|
+
const didSyncFromHostRef = React52.useRef(false);
|
|
10392
|
+
const lastNotifiedRef = React52.useRef(null);
|
|
10393
|
+
const platform = React52.useMemo(() => RNPlatform.OS === "ios" ? "ios" : "android", []);
|
|
10394
|
+
const notifyActiveAppChanged = React52.useCallback(
|
|
9953
10395
|
(nextAppId, source) => {
|
|
9954
10396
|
if (!onActiveAppChanged) return;
|
|
9955
10397
|
const trimmedAppId = nextAppId.trim();
|
|
@@ -9962,28 +10404,28 @@ function ComergeStudio({
|
|
|
9962
10404
|
},
|
|
9963
10405
|
[appKey, onActiveAppChanged]
|
|
9964
10406
|
);
|
|
9965
|
-
const setActiveAppIdWithSource =
|
|
10407
|
+
const setActiveAppIdWithSource = React52.useCallback(
|
|
9966
10408
|
(nextAppId, source) => {
|
|
9967
10409
|
setActiveAppId(nextAppId);
|
|
9968
10410
|
notifyActiveAppChanged(nextAppId, source);
|
|
9969
10411
|
},
|
|
9970
10412
|
[notifyActiveAppChanged]
|
|
9971
10413
|
);
|
|
9972
|
-
|
|
10414
|
+
React52.useEffect(() => {
|
|
9973
10415
|
const source = didSyncFromHostRef.current ? "host_route_sync" : "initial";
|
|
9974
10416
|
didSyncFromHostRef.current = true;
|
|
9975
10417
|
setActiveAppIdWithSource(appId, source);
|
|
9976
10418
|
setRuntimeAppId(appId);
|
|
9977
10419
|
setPendingRuntimeTargetAppId(null);
|
|
9978
10420
|
}, [appId, setActiveAppIdWithSource]);
|
|
9979
|
-
const captureTargetRef =
|
|
9980
|
-
return /* @__PURE__ */
|
|
10421
|
+
const captureTargetRef = React52.useRef(null);
|
|
10422
|
+
return /* @__PURE__ */ jsx66(
|
|
9981
10423
|
StudioBootstrap,
|
|
9982
10424
|
{
|
|
9983
10425
|
clientKey: clientKey2,
|
|
9984
10426
|
analyticsEnabled,
|
|
9985
|
-
fallback: /* @__PURE__ */
|
|
9986
|
-
children: ({ userId }) => /* @__PURE__ */
|
|
10427
|
+
fallback: /* @__PURE__ */ jsx66(View50, { style: { flex: 1 } }),
|
|
10428
|
+
children: ({ userId }) => /* @__PURE__ */ jsx66(BottomSheetModalProvider, { children: /* @__PURE__ */ jsx66(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ jsx66(
|
|
9987
10429
|
ComergeStudioInner,
|
|
9988
10430
|
{
|
|
9989
10431
|
userId,
|
|
@@ -10033,11 +10475,11 @@ function ComergeStudioInner({
|
|
|
10033
10475
|
const { app, loading: appLoading } = useApp(activeAppId);
|
|
10034
10476
|
const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
|
|
10035
10477
|
const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
|
|
10036
|
-
const sawEditingOnPendingTargetRef =
|
|
10037
|
-
|
|
10478
|
+
const sawEditingOnPendingTargetRef = React52.useRef(false);
|
|
10479
|
+
React52.useEffect(() => {
|
|
10038
10480
|
sawEditingOnPendingTargetRef.current = false;
|
|
10039
10481
|
}, [pendingRuntimeTargetAppId]);
|
|
10040
|
-
|
|
10482
|
+
React52.useEffect(() => {
|
|
10041
10483
|
if (!pendingRuntimeTargetAppId) return;
|
|
10042
10484
|
if (activeAppId !== pendingRuntimeTargetAppId) return;
|
|
10043
10485
|
if ((app == null ? void 0 : app.status) === "editing") {
|
|
@@ -10055,13 +10497,13 @@ function ComergeStudioInner({
|
|
|
10055
10497
|
canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready",
|
|
10056
10498
|
embeddedBaseBundles
|
|
10057
10499
|
});
|
|
10058
|
-
const sawEditingOnActiveAppRef =
|
|
10059
|
-
const [showPostEditPreparing, setShowPostEditPreparing] =
|
|
10060
|
-
|
|
10500
|
+
const sawEditingOnActiveAppRef = React52.useRef(false);
|
|
10501
|
+
const [showPostEditPreparing, setShowPostEditPreparing] = React52.useState(false);
|
|
10502
|
+
React52.useEffect(() => {
|
|
10061
10503
|
sawEditingOnActiveAppRef.current = false;
|
|
10062
10504
|
setShowPostEditPreparing(false);
|
|
10063
10505
|
}, [activeAppId]);
|
|
10064
|
-
|
|
10506
|
+
React52.useEffect(() => {
|
|
10065
10507
|
if (!(app == null ? void 0 : app.id)) return;
|
|
10066
10508
|
if (app.status === "editing") {
|
|
10067
10509
|
sawEditingOnActiveAppRef.current = true;
|
|
@@ -10073,7 +10515,7 @@ function ComergeStudioInner({
|
|
|
10073
10515
|
sawEditingOnActiveAppRef.current = false;
|
|
10074
10516
|
}
|
|
10075
10517
|
}, [app == null ? void 0 : app.id, app == null ? void 0 : app.status]);
|
|
10076
|
-
|
|
10518
|
+
React52.useEffect(() => {
|
|
10077
10519
|
if (!showPostEditPreparing) return;
|
|
10078
10520
|
const stillProcessingBaseBundle = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
|
|
10079
10521
|
if (!stillProcessingBaseBundle) {
|
|
@@ -10085,19 +10527,19 @@ function ComergeStudioInner({
|
|
|
10085
10527
|
const editQueue = useEditQueue(activeAppId);
|
|
10086
10528
|
const agentProgress = useAgentRunProgress(threadId, { enabled: enableAgentProgress });
|
|
10087
10529
|
const editQueueActions = useEditQueueActions(activeAppId);
|
|
10088
|
-
const [lastEditQueueInfo, setLastEditQueueInfo] =
|
|
10089
|
-
const lastEditQueueInfoRef =
|
|
10090
|
-
const [suppressQueueUntilResponse, setSuppressQueueUntilResponse] =
|
|
10530
|
+
const [lastEditQueueInfo, setLastEditQueueInfo] = React52.useState(null);
|
|
10531
|
+
const lastEditQueueInfoRef = React52.useRef(null);
|
|
10532
|
+
const [suppressQueueUntilResponse, setSuppressQueueUntilResponse] = React52.useState(false);
|
|
10091
10533
|
const mergeRequests = useMergeRequests({ appId: activeAppId });
|
|
10092
|
-
const hasOpenOutgoingMr =
|
|
10534
|
+
const hasOpenOutgoingMr = React52.useMemo(() => {
|
|
10093
10535
|
return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
|
|
10094
10536
|
}, [mergeRequests.lists.outgoing]);
|
|
10095
|
-
const incomingReviewMrs =
|
|
10537
|
+
const incomingReviewMrs = React52.useMemo(() => {
|
|
10096
10538
|
if (!userId) return mergeRequests.lists.incoming;
|
|
10097
10539
|
return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
|
|
10098
10540
|
}, [mergeRequests.lists.incoming, userId]);
|
|
10099
10541
|
const uploader = useAttachmentUpload();
|
|
10100
|
-
const updateLastEditQueueInfo =
|
|
10542
|
+
const updateLastEditQueueInfo = React52.useCallback(
|
|
10101
10543
|
(info) => {
|
|
10102
10544
|
lastEditQueueInfoRef.current = info;
|
|
10103
10545
|
setLastEditQueueInfo(info);
|
|
@@ -10139,13 +10581,13 @@ function ComergeStudioInner({
|
|
|
10139
10581
|
}
|
|
10140
10582
|
});
|
|
10141
10583
|
const chatSendDisabled = false;
|
|
10142
|
-
const [processingMrId, setProcessingMrId] =
|
|
10143
|
-
const [testingMrId, setTestingMrId] =
|
|
10144
|
-
const [syncingUpstream, setSyncingUpstream] =
|
|
10145
|
-
const [upstreamSyncStatus, setUpstreamSyncStatus] =
|
|
10584
|
+
const [processingMrId, setProcessingMrId] = React52.useState(null);
|
|
10585
|
+
const [testingMrId, setTestingMrId] = React52.useState(null);
|
|
10586
|
+
const [syncingUpstream, setSyncingUpstream] = React52.useState(false);
|
|
10587
|
+
const [upstreamSyncStatus, setUpstreamSyncStatus] = React52.useState(null);
|
|
10146
10588
|
const isMrTestBuildInProgress = bundle.loading && bundle.loadingMode === "test";
|
|
10147
10589
|
const isBaseBundleDownloading = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
|
|
10148
|
-
const runtimePreparingText =
|
|
10590
|
+
const runtimePreparingText = React52.useMemo(() => {
|
|
10149
10591
|
const status = app == null ? void 0 : app.status;
|
|
10150
10592
|
if (status === "ready" && bundle.bundleStatus === "pending") {
|
|
10151
10593
|
return "Bundling app\u2026 this may take a few minutes";
|
|
@@ -10165,7 +10607,7 @@ function ComergeStudioInner({
|
|
|
10165
10607
|
return "Preparing app\u2026";
|
|
10166
10608
|
}
|
|
10167
10609
|
}, [app == null ? void 0 : app.status, bundle.bundleStatus]);
|
|
10168
|
-
const chatShowTypingIndicator =
|
|
10610
|
+
const chatShowTypingIndicator = React52.useMemo(() => {
|
|
10169
10611
|
var _a2;
|
|
10170
10612
|
if (agentProgress.hasLiveProgress) return false;
|
|
10171
10613
|
if (!thread.raw || thread.raw.length === 0) return false;
|
|
@@ -10174,12 +10616,12 @@ function ComergeStudioInner({
|
|
|
10174
10616
|
return payloadType !== "outcome";
|
|
10175
10617
|
}, [agentProgress.hasLiveProgress, thread.raw]);
|
|
10176
10618
|
const showChatProgress = agentProgress.hasLiveProgress || Boolean((_a = agentProgress.view.bundle) == null ? void 0 : _a.active);
|
|
10177
|
-
|
|
10619
|
+
React52.useEffect(() => {
|
|
10178
10620
|
updateLastEditQueueInfo(null);
|
|
10179
10621
|
setSuppressQueueUntilResponse(false);
|
|
10180
10622
|
setUpstreamSyncStatus(null);
|
|
10181
10623
|
}, [activeAppId, updateLastEditQueueInfo]);
|
|
10182
|
-
const handleSyncUpstream =
|
|
10624
|
+
const handleSyncUpstream = React52.useCallback(async () => {
|
|
10183
10625
|
if (!(app == null ? void 0 : app.id)) {
|
|
10184
10626
|
throw new Error("Missing app");
|
|
10185
10627
|
}
|
|
@@ -10192,7 +10634,7 @@ function ComergeStudioInner({
|
|
|
10192
10634
|
setSyncingUpstream(false);
|
|
10193
10635
|
}
|
|
10194
10636
|
}, [activeAppId, app == null ? void 0 : app.id]);
|
|
10195
|
-
|
|
10637
|
+
React52.useEffect(() => {
|
|
10196
10638
|
if (!(lastEditQueueInfo == null ? void 0 : lastEditQueueInfo.queueItemId)) return;
|
|
10197
10639
|
const stillPresent = editQueue.items.some((item) => item.id === lastEditQueueInfo.queueItemId);
|
|
10198
10640
|
if (!stillPresent) {
|
|
@@ -10200,7 +10642,7 @@ function ComergeStudioInner({
|
|
|
10200
10642
|
setSuppressQueueUntilResponse(false);
|
|
10201
10643
|
}
|
|
10202
10644
|
}, [editQueue.items, lastEditQueueInfo == null ? void 0 : lastEditQueueInfo.queueItemId]);
|
|
10203
|
-
const chatQueueItems =
|
|
10645
|
+
const chatQueueItems = React52.useMemo(() => {
|
|
10204
10646
|
var _a2;
|
|
10205
10647
|
if (suppressQueueUntilResponse && editQueue.items.length <= 1) {
|
|
10206
10648
|
return [];
|
|
@@ -10214,8 +10656,8 @@ function ComergeStudioInner({
|
|
|
10214
10656
|
return editQueue.items;
|
|
10215
10657
|
}, [editQueue.items, lastEditQueueInfo, suppressQueueUntilResponse]);
|
|
10216
10658
|
const { relatedApps, loading: relatedAppsLoading } = useRelatedApps(activeAppId);
|
|
10217
|
-
const [switchingRelatedAppId, setSwitchingRelatedAppId] =
|
|
10218
|
-
const handleOpenRelatedApps =
|
|
10659
|
+
const [switchingRelatedAppId, setSwitchingRelatedAppId] = React52.useState(null);
|
|
10660
|
+
const handleOpenRelatedApps = React52.useCallback(() => {
|
|
10219
10661
|
var _a2;
|
|
10220
10662
|
if (!relatedApps) return;
|
|
10221
10663
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -10224,7 +10666,7 @@ function ComergeStudioInner({
|
|
|
10224
10666
|
for (const remix of relatedApps.remixes) ids.add(remix.id);
|
|
10225
10667
|
void trackRelatedAppsOpened({ appId: relatedApps.current.id, relatedCount: ids.size });
|
|
10226
10668
|
}, [relatedApps]);
|
|
10227
|
-
const handleSwitchRelatedApp =
|
|
10669
|
+
const handleSwitchRelatedApp = React52.useCallback(
|
|
10228
10670
|
async (targetAppId) => {
|
|
10229
10671
|
var _a2;
|
|
10230
10672
|
if (!targetAppId || targetAppId === activeAppId) return;
|
|
@@ -10285,8 +10727,8 @@ function ComergeStudioInner({
|
|
|
10285
10727
|
setRuntimeAppId
|
|
10286
10728
|
]
|
|
10287
10729
|
);
|
|
10288
|
-
return /* @__PURE__ */
|
|
10289
|
-
/* @__PURE__ */
|
|
10730
|
+
return /* @__PURE__ */ jsx66(View50, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsxs42(View50, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
|
|
10731
|
+
/* @__PURE__ */ jsx66(
|
|
10290
10732
|
RuntimeRenderer,
|
|
10291
10733
|
{
|
|
10292
10734
|
appKey,
|
|
@@ -10310,7 +10752,7 @@ function ComergeStudioInner({
|
|
|
10310
10752
|
}
|
|
10311
10753
|
}
|
|
10312
10754
|
),
|
|
10313
|
-
/* @__PURE__ */
|
|
10755
|
+
/* @__PURE__ */ jsx66(
|
|
10314
10756
|
StudioOverlay,
|
|
10315
10757
|
{
|
|
10316
10758
|
captureTargetRef,
|
|
@@ -10367,6 +10809,9 @@ function ComergeStudioInner({
|
|
|
10367
10809
|
chatSending: actions.sending,
|
|
10368
10810
|
chatShowTypingIndicator,
|
|
10369
10811
|
onSendChat: (text, attachments) => actions.sendEdit({ prompt: text, attachments }),
|
|
10812
|
+
onChatAttachmentLoadError: () => {
|
|
10813
|
+
thread.recoverAttachmentUrls();
|
|
10814
|
+
},
|
|
10370
10815
|
chatQueueItems,
|
|
10371
10816
|
onRemoveQueueItem: (id) => editQueueActions.cancel(id),
|
|
10372
10817
|
chatProgress: showChatProgress ? agentProgress.view : null,
|