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