| ... | @@ -68,10 +68,7 @@ import { | ... | @@ -68,10 +68,7 @@ import { |
| 68 | clearComposerDraftsEnvironment, | 68 | clearComposerDraftsEnvironment, |
| 69 | composerDraftHasUserContent, | 69 | composerDraftHasUserContent, |
| 70 | finalizePromotedDraftThreadByRef, | 70 | finalizePromotedDraftThreadByRef, |
| 71 | markPromotedDraftThread, | | |
| 72 | markPromotedDraftThreadByRef, | 71 | markPromotedDraftThreadByRef, |
| 73 | markPromotedDraftThreads, | | |
| 74 | markPromotedDraftThreadsByRef, | | |
| 75 | type ComposerFileAttachment, | 72 | type ComposerFileAttachment, |
| 76 | type ComposerImageAttachment, | 73 | type ComposerImageAttachment, |
| 77 | composerFileNeedsReattach, | 74 | composerFileNeedsReattach, |
| ... | @@ -1200,7 +1197,7 @@ describe("composerDraftStore project draft thread mapping", () => { | ... | @@ -1200,7 +1197,7 @@ describe("composerDraftStore project draft thread mapping", () => { |
| 1200 | interactionMode: "plan", | 1197 | interactionMode: "plan", |
| 1201 | }); | 1198 | }); |
| 1202 | store.setPrompt(draftId, "keep this prompt"); | 1199 | store.setPrompt(draftId, "keep this prompt"); |
| 1203 | markPromotedDraftThread(threadId); | 1200 | markPromotedDraftThreadByRef(scopeThreadRef(TEST_ENVIRONMENT_ID, threadId)); |
| 1204 | | 1201 | |
| 1205 | store.setLogicalProjectDraftThreadId(scopedProjectKey(projectRef), projectRef, draftId, { | 1202 | store.setLogicalProjectDraftThreadId(scopedProjectKey(projectRef), projectRef, draftId, { |
| 1206 | threadId: retryThreadId, | 1203 | threadId: retryThreadId, |
| ... | @@ -1363,12 +1360,12 @@ describe("composerDraftStore project draft thread mapping", () => { | ... | @@ -1363,12 +1360,12 @@ describe("composerDraftStore project draft thread mapping", () => { |
| 1363 | expect(draftByKey(draftId)).toBeUndefined(); | 1360 | expect(draftByKey(draftId)).toBeUndefined(); |
| 1364 | }); | 1361 | }); |
| 1365 | | 1362 | |
| 1366 | it("marks a promoted draft by thread id without deleting composer state", () => { | 1363 | it("marks a promoted draft by scoped ref without deleting composer state", () => { |
| 1367 | const store = useComposerDraftStore.getState(); | 1364 | const store = useComposerDraftStore.getState(); |
| 1368 | store.setProjectDraftThreadId(projectRef, draftId, { threadId }); | 1365 | store.setProjectDraftThreadId(projectRef, draftId, { threadId }); |
| 1369 | store.setPrompt(draftId, "promote me"); | 1366 | store.setPrompt(draftId, "promote me"); |
| 1370 | | 1367 | |
| 1371 | markPromotedDraftThread(threadId); | 1368 | markPromotedDraftThreadByRef(scopeThreadRef(TEST_ENVIRONMENT_ID, threadId)); |
| 1372 | | 1369 | |
| 1373 | expect(useComposerDraftStore.getState().getDraftThreadByProjectRef(projectRef)).toBeNull(); | 1370 | expect(useComposerDraftStore.getState().getDraftThreadByProjectRef(projectRef)).toBeNull(); |
| 1374 | expect(useComposerDraftStore.getState().getDraftThread(draftId)?.promotedTo).toEqual( | 1371 | expect(useComposerDraftStore.getState().getDraftThread(draftId)?.promotedTo).toEqual( |
| ... | @@ -1393,20 +1390,20 @@ describe("composerDraftStore project draft thread mapping", () => { | ... | @@ -1393,20 +1390,20 @@ describe("composerDraftStore project draft thread mapping", () => { |
| 1393 | const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); | 1390 | const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); |
| 1394 | store.setPrompt(threadRef, "keep me"); | 1391 | store.setPrompt(threadRef, "keep me"); |
| 1395 | | 1392 | |
| 1396 | markPromotedDraftThread(threadId); | 1393 | markPromotedDraftThreadByRef(scopeThreadRef(TEST_ENVIRONMENT_ID, threadId)); |
| 1397 | | 1394 | |
| 1398 | expect(useComposerDraftStore.getState().getDraftThread(threadRef)).toBeNull(); | 1395 | expect(useComposerDraftStore.getState().getDraftThread(threadRef)).toBeNull(); |
| 1399 | expect(draftFor(threadId, TEST_ENVIRONMENT_ID)?.prompt).toBe("keep me"); | 1396 | expect(draftFor(threadId, TEST_ENVIRONMENT_ID)?.prompt).toBe("keep me"); |
| 1400 | }); | 1397 | }); |
| 1401 | | 1398 | |
| 1402 | it("marks promoted drafts from an iterable of server thread ids", () => { | 1399 | it("promotes a draft without changing another thread's draft", () => { |
| 1403 | const store = useComposerDraftStore.getState(); | 1400 | const store = useComposerDraftStore.getState(); |
| 1404 | store.setProjectDraftThreadId(projectRef, draftId, { threadId }); | 1401 | store.setProjectDraftThreadId(projectRef, draftId, { threadId }); |
| 1405 | store.setPrompt(draftId, "promote me"); | 1402 | store.setPrompt(draftId, "promote me"); |
| 1406 | store.setProjectDraftThreadId(otherProjectRef, otherDraftId, { threadId: otherThreadId }); | 1403 | store.setProjectDraftThreadId(otherProjectRef, otherDraftId, { threadId: otherThreadId }); |
| 1407 | store.setPrompt(otherDraftId, "keep me"); | 1404 | store.setPrompt(otherDraftId, "keep me"); |
| 1408 | | 1405 | |
| 1409 | markPromotedDraftThreads([threadId]); | 1406 | markPromotedDraftThreadByRef(scopeThreadRef(TEST_ENVIRONMENT_ID, threadId)); |
| 1410 | | 1407 | |
| 1411 | expect(useComposerDraftStore.getState().getDraftThread(draftId)?.promotedTo).toEqual( | 1408 | expect(useComposerDraftStore.getState().getDraftThread(draftId)?.promotedTo).toEqual( |
| 1412 | scopeThreadRef(TEST_ENVIRONMENT_ID, threadId), | 1409 | scopeThreadRef(TEST_ENVIRONMENT_ID, threadId), |
| ... | @@ -1418,7 +1415,7 @@ describe("composerDraftStore project draft thread mapping", () => { | ... | @@ -1418,7 +1415,7 @@ describe("composerDraftStore project draft thread mapping", () => { |
| 1418 | expect(draftByKey(otherDraftId)?.prompt).toBe("keep me"); | 1415 | expect(draftByKey(otherDraftId)?.prompt).toBe("keep me"); |
| 1419 | }); | 1416 | }); |
| 1420 | | 1417 | |
| 1421 | it("marks every matching scoped draft when multiple environments share a thread id", () => { | 1418 | it("promotes matching thread ids separately for each environment", () => { |
| 1422 | const store = useComposerDraftStore.getState(); | 1419 | const store = useComposerDraftStore.getState(); |
| 1423 | const localThreadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); | 1420 | const localThreadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); |
| 1424 | const remoteThreadRef = scopeThreadRef(OTHER_TEST_ENVIRONMENT_ID, threadId); | 1421 | const remoteThreadRef = scopeThreadRef(OTHER_TEST_ENVIRONMENT_ID, threadId); |
| ... | @@ -1428,7 +1425,16 @@ describe("composerDraftStore project draft thread mapping", () => { | ... | @@ -1428,7 +1425,16 @@ describe("composerDraftStore project draft thread mapping", () => { |
| 1428 | store.setProjectDraftThreadId(remoteProjectRef, remoteDraftId, { threadId }); | 1425 | store.setProjectDraftThreadId(remoteProjectRef, remoteDraftId, { threadId }); |
| 1429 | store.setPrompt(remoteDraftId, "remote draft"); | 1426 | store.setPrompt(remoteDraftId, "remote draft"); |
| 1430 | | 1427 | |
| 1431 | markPromotedDraftThread(threadId); | 1428 | markPromotedDraftThreadByRef(localThreadRef); |
| | 1429 | |
| | 1430 | expect(store.getDraftThreadByProjectRef(projectRef)).toBeNull(); |
| | 1431 | expect(store.getDraftThreadByProjectRef(remoteProjectRef)?.threadId).toBe(threadId); |
| | 1432 | expect(store.getDraftThreadByRef(localThreadRef)?.promotedTo).toEqual(localThreadRef); |
| | 1433 | expect(store.getDraftThreadByRef(remoteThreadRef)?.promotedTo).toBeNull(); |
| | 1434 | expect(draftByKey(localDraftId)?.prompt).toBe("local draft"); |
| | 1435 | expect(draftByKey(remoteDraftId)?.prompt).toBe("remote draft"); |
| | 1436 | |
| | 1437 | markPromotedDraftThreadByRef(remoteThreadRef); |
| 1432 | | 1438 | |
| 1433 | expect(store.getDraftThreadByProjectRef(projectRef)).toBeNull(); | 1439 | expect(store.getDraftThreadByProjectRef(projectRef)).toBeNull(); |
| 1434 | expect(store.getDraftThreadByProjectRef(remoteProjectRef)).toBeNull(); | 1440 | expect(store.getDraftThreadByProjectRef(remoteProjectRef)).toBeNull(); |
| ... | @@ -1451,34 +1457,10 @@ describe("composerDraftStore project draft thread mapping", () => { | ... | @@ -1451,34 +1457,10 @@ describe("composerDraftStore project draft thread mapping", () => { |
| 1451 | expect(draftByKey(draftId)?.prompt).toBe("promote me"); | 1457 | expect(draftByKey(draftId)?.prompt).toBe("promote me"); |
| 1452 | }); | 1458 | }); |
| 1453 | | 1459 | |
| 1454 | it("only marks iterable promotion cleanup entries for the matching environment refs", () => { | | |
| 1455 | const store = useComposerDraftStore.getState(); | | |
| 1456 | store.setProjectDraftThreadId(projectRef, draftId, { threadId }); | | |
| 1457 | store.setPrompt(draftId, "promote me"); | | |
| 1458 | | | |
| 1459 | markPromotedDraftThreadsByRef([scopeThreadRef(OTHER_TEST_ENVIRONMENT_ID, threadId)]); | | |
| 1460 | | | |
| 1461 | expect(useComposerDraftStore.getState().getDraftThreadByProjectRef(projectRef)?.threadId).toBe( | | |
| 1462 | threadId, | | |
| 1463 | ); | | |
| 1464 | expect(draftByKey(draftId)?.prompt).toBe("promote me"); | | |
| 1465 | }); | | |
| 1466 | | | |
| 1467 | it("keeps existing server-thread composer drafts during iterable promotion cleanup", () => { | | |
| 1468 | const store = useComposerDraftStore.getState(); | | |
| 1469 | const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); | | |
| 1470 | store.setPrompt(threadRef, "keep me"); | | |
| 1471 | | | |
| 1472 | markPromotedDraftThreads([threadId]); | | |
| 1473 | | | |
| 1474 | expect(useComposerDraftStore.getState().getDraftThread(threadRef)).toBeNull(); | | |
| 1475 | expect(draftFor(threadId, TEST_ENVIRONMENT_ID)?.prompt).toBe("keep me"); | | |
| 1476 | }); | | |
| 1477 | | | |
| 1478 | it("moves composer edits made during promotion to the canonical thread", () => { | 1460 | it("moves composer edits made during promotion to the canonical thread", () => { |
| 1479 | const store = useComposerDraftStore.getState(); | 1461 | const store = useComposerDraftStore.getState(); |
| 1480 | store.setProjectDraftThreadId(projectRef, draftId, { threadId }); | 1462 | store.setProjectDraftThreadId(projectRef, draftId, { threadId }); |
| 1481 | markPromotedDraftThread(threadId); | 1463 | markPromotedDraftThreadByRef(scopeThreadRef(TEST_ENVIRONMENT_ID, threadId)); |
| 1482 | store.setPrompt(draftId, "typed during setup"); | 1464 | store.setPrompt(draftId, "typed during setup"); |
| 1483 | | 1465 | |
| 1484 | finalizePromotedDraftThreadByRef(scopeThreadRef(TEST_ENVIRONMENT_ID, threadId)); | 1466 | finalizePromotedDraftThreadByRef(scopeThreadRef(TEST_ENVIRONMENT_ID, threadId)); |