ikanban-web 0.2.6 → 0.2.8
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/README.md +25 -20
- package/dist/assets/{ghostty-web-BsS8qmby.js → ghostty-web--axxBQj6.js} +1 -1
- package/dist/assets/{home-BVcfU4oW.js → home-BAEIhduF.js} +1 -1
- package/dist/assets/{index-B1DFsnCu.css → index-B0TEjAod.css} +1 -1
- package/dist/assets/{index-BbYqEnGb.js → index-BR3vRMWX.js} +124 -116
- package/dist/assets/session-Bp9iU6SU.js +24 -0
- package/dist/index.html +19 -6
- package/package.json +1 -1
- package/src/components/dialog-session-timeline.tsx +85 -0
- package/src/components/prompt-input.tsx +3 -3
- package/src/components/session/session-header.tsx +2 -211
- package/src/components/settings-general.tsx +18 -93
- package/src/context/global-sync/child-store.ts +1 -0
- package/src/context/global-sync/event-reducer.test.ts +5 -0
- package/src/context/global-sync/event-reducer.ts +263 -183
- package/src/context/global-sync/types.ts +3 -0
- package/src/context/highlights.tsx +4 -176
- package/src/context/server.tsx +24 -4
- package/src/context/sync.tsx +237 -2
- package/src/i18n/en.ts +12 -1
- package/src/i18n/parity.test.ts +4 -22
- package/src/i18n/zh.ts +23 -1
- package/src/pages/layout.tsx +13 -56
- package/src/pages/session/review-tab.tsx +3 -1
- package/src/pages/session/session-side-panel.tsx +17 -51
- package/src/pages/session/use-session-commands.tsx +91 -154
- package/src/pages/session.tsx +87 -16
- package/dist/assets/session-CZ-wC_3g.js +0 -24
- package/src/i18n/ar.ts +0 -751
- package/src/i18n/br.ts +0 -759
- package/src/i18n/bs.ts +0 -836
- package/src/i18n/da.ts +0 -830
- package/src/i18n/de.ts +0 -768
- package/src/i18n/es.ts +0 -842
- package/src/i18n/fr.ts +0 -766
- package/src/i18n/ja.ts +0 -755
- package/src/i18n/ko.ts +0 -755
- package/src/i18n/no.ts +0 -838
- package/src/i18n/pl.ts +0 -757
- package/src/i18n/ru.ts +0 -838
- package/src/i18n/th.ts +0 -828
- package/src/i18n/tr.ts +0 -849
- package/src/i18n/zht.ts +0 -821
package/src/pages/session.tsx
CHANGED
|
@@ -360,9 +360,8 @@ export default function Page() {
|
|
|
360
360
|
})
|
|
361
361
|
|
|
362
362
|
const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
const hasReview = createMemo(() => reviewCount() > 0)
|
|
363
|
+
const sessionDiffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : []))
|
|
364
|
+
const projectDiffs = createMemo(() => sync.data.project_diff[sdk.directory] ?? [])
|
|
366
365
|
const revertMessageID = createMemo(() => info()?.revert?.messageID)
|
|
367
366
|
const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : []))
|
|
368
367
|
const messagesReady = createMemo(() => {
|
|
@@ -414,7 +413,7 @@ export default function Page() {
|
|
|
414
413
|
const [store, setStore] = createStore({
|
|
415
414
|
messageId: undefined as string | undefined,
|
|
416
415
|
mobileTab: "session" as "session" | "changes",
|
|
417
|
-
changes: "
|
|
416
|
+
changes: "project" as "session" | "project" | "turn",
|
|
418
417
|
newSessionWorktree: "main",
|
|
419
418
|
deferRender: false,
|
|
420
419
|
})
|
|
@@ -431,7 +430,42 @@ export default function Page() {
|
|
|
431
430
|
}, sessionKey())
|
|
432
431
|
|
|
433
432
|
const turnDiffs = createMemo(() => lastUserMessage()?.summary?.diffs ?? [])
|
|
434
|
-
const reviewDiffs = createMemo(() =>
|
|
433
|
+
const reviewDiffs = createMemo(() => {
|
|
434
|
+
if (store.changes === "project") return projectDiffs()
|
|
435
|
+
if (store.changes === "turn") return turnDiffs()
|
|
436
|
+
return sessionDiffs()
|
|
437
|
+
})
|
|
438
|
+
const reviewDiffFiles = createMemo(() => reviewDiffs().map((diff) => diff.file))
|
|
439
|
+
const reviewKinds = createMemo(() => {
|
|
440
|
+
const merge = (a: "add" | "del" | "mix" | undefined, b: "add" | "del" | "mix") => {
|
|
441
|
+
if (!a) return b
|
|
442
|
+
if (a === b) return a
|
|
443
|
+
return "mix" as const
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const normalize = (p: string) => p.replaceAll("\\", "/").replace(/\/+$/, "")
|
|
447
|
+
|
|
448
|
+
const out = new Map<string, "add" | "del" | "mix">()
|
|
449
|
+
for (const diff of reviewDiffs()) {
|
|
450
|
+
const file = normalize(diff.file)
|
|
451
|
+
const kind = diff.status === "added" ? "add" : diff.status === "deleted" ? "del" : "mix"
|
|
452
|
+
|
|
453
|
+
out.set(file, kind)
|
|
454
|
+
|
|
455
|
+
const parts = file.split("/")
|
|
456
|
+
for (const [idx] of parts.slice(0, -1).entries()) {
|
|
457
|
+
const dir = parts.slice(0, idx + 1).join("/")
|
|
458
|
+
if (!dir) continue
|
|
459
|
+
out.set(dir, merge(out.get(dir), kind))
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return out
|
|
463
|
+
})
|
|
464
|
+
const reviewCount = createMemo(() => reviewDiffs().length)
|
|
465
|
+
const hasReview = createMemo(() => reviewCount() > 0)
|
|
466
|
+
const hasAnyReview = createMemo(
|
|
467
|
+
() => sessionDiffs().length > 0 || projectDiffs().length > 0 || turnDiffs().length > 0,
|
|
468
|
+
)
|
|
435
469
|
|
|
436
470
|
const newSessionWorktree = createMemo(() => {
|
|
437
471
|
if (store.newSessionWorktree === "create") return "create"
|
|
@@ -471,10 +505,17 @@ export default function Page() {
|
|
|
471
505
|
const diffsReady = createMemo(() => {
|
|
472
506
|
const id = params.id
|
|
473
507
|
if (!id) return true
|
|
508
|
+
if (store.changes === "turn") return true
|
|
474
509
|
if (!hasReview()) return true
|
|
510
|
+
if (store.changes === "project") return sync.data.project_diff[sdk.directory] !== undefined
|
|
475
511
|
return sync.data.session_diff[id] !== undefined
|
|
476
512
|
})
|
|
477
513
|
const reviewEmptyKey = createMemo(() => {
|
|
514
|
+
if (store.changes === "project") {
|
|
515
|
+
const project = sync.project
|
|
516
|
+
if (!project || project.vcs) return "session.review.emptyProject"
|
|
517
|
+
return "session.review.noVcsProject"
|
|
518
|
+
}
|
|
478
519
|
const project = sync.project
|
|
479
520
|
if (!project || project.vcs) return "session.review.empty"
|
|
480
521
|
return "session.review.noVcs"
|
|
@@ -528,7 +569,7 @@ export default function Page() {
|
|
|
528
569
|
sessionKey,
|
|
529
570
|
() => {
|
|
530
571
|
setStore("messageId", undefined)
|
|
531
|
-
setStore("changes", "
|
|
572
|
+
setStore("changes", "project")
|
|
532
573
|
},
|
|
533
574
|
{ defer: true },
|
|
534
575
|
),
|
|
@@ -705,16 +746,18 @@ export default function Page() {
|
|
|
705
746
|
loadFile: file.load,
|
|
706
747
|
})
|
|
707
748
|
|
|
708
|
-
const changesOptions = ["session", "turn"] as const
|
|
749
|
+
const changesOptions = ["project", "session", "turn"] as const
|
|
709
750
|
const changesOptionsList = [...changesOptions]
|
|
710
751
|
|
|
711
752
|
const changesTitle = () => (
|
|
712
753
|
<Select
|
|
713
754
|
options={changesOptionsList}
|
|
714
755
|
current={store.changes}
|
|
715
|
-
label={(option) =>
|
|
716
|
-
option === "
|
|
717
|
-
|
|
756
|
+
label={(option) => {
|
|
757
|
+
if (option === "project") return language.t("ui.sessionReview.title.project")
|
|
758
|
+
if (option === "turn") return language.t("ui.sessionReview.title.lastTurn")
|
|
759
|
+
return language.t("ui.sessionReview.title")
|
|
760
|
+
}}
|
|
718
761
|
onSelect={(option) => option && setStore("changes", option)}
|
|
719
762
|
variant="ghost"
|
|
720
763
|
size="small"
|
|
@@ -743,6 +786,10 @@ export default function Page() {
|
|
|
743
786
|
title={changesTitle()}
|
|
744
787
|
empty={emptyTurn()}
|
|
745
788
|
diffs={reviewDiffs}
|
|
789
|
+
onRevealFile={(file) => {
|
|
790
|
+
if (store.changes !== "project") return
|
|
791
|
+
void sync.projectDiff.hydrate(file)
|
|
792
|
+
}}
|
|
746
793
|
view={view}
|
|
747
794
|
diffStyle={input.diffStyle}
|
|
748
795
|
onDiffStyleChange={input.onDiffStyleChange}
|
|
@@ -767,6 +814,10 @@ export default function Page() {
|
|
|
767
814
|
<SessionReviewTab
|
|
768
815
|
title={changesTitle()}
|
|
769
816
|
diffs={reviewDiffs}
|
|
817
|
+
onRevealFile={(file) => {
|
|
818
|
+
if (store.changes !== "project") return
|
|
819
|
+
void sync.projectDiff.hydrate(file)
|
|
820
|
+
}}
|
|
770
821
|
view={view}
|
|
771
822
|
diffStyle={input.diffStyle}
|
|
772
823
|
onDiffStyleChange={input.onDiffStyleChange}
|
|
@@ -935,14 +986,14 @@ export default function Page() {
|
|
|
935
986
|
const first = openedTabs()[0]
|
|
936
987
|
if (first) return first
|
|
937
988
|
if (contextOpen()) return "context"
|
|
938
|
-
if (reviewTab() &&
|
|
989
|
+
if (reviewTab() && hasAnyReview()) return "review"
|
|
939
990
|
return "empty"
|
|
940
991
|
})
|
|
941
992
|
|
|
942
993
|
createEffect(() => {
|
|
943
994
|
if (!layout.ready()) return
|
|
944
995
|
if (tabs().active()) return
|
|
945
|
-
if (openedTabs().length === 0 && !contextOpen() && !(reviewTab() &&
|
|
996
|
+
if (openedTabs().length === 0 && !contextOpen() && !(reviewTab() && hasAnyReview())) return
|
|
946
997
|
|
|
947
998
|
const next = activeTab()
|
|
948
999
|
if (next === "empty") return
|
|
@@ -958,7 +1009,7 @@ export default function Page() {
|
|
|
958
1009
|
|
|
959
1010
|
if (opened) {
|
|
960
1011
|
const active = tabs().active()
|
|
961
|
-
const tab = active === "review" || (!active &&
|
|
1012
|
+
const tab = active === "review" || (!active && hasAnyReview()) ? "changes" : "all"
|
|
962
1013
|
layout.fileTree.setTab(tab)
|
|
963
1014
|
}
|
|
964
1015
|
},
|
|
@@ -974,9 +1025,19 @@ export default function Page() {
|
|
|
974
1025
|
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
|
|
975
1026
|
: store.mobileTab === "changes"
|
|
976
1027
|
if (!wants) return
|
|
977
|
-
if (
|
|
1028
|
+
if (store.changes === "project") {
|
|
1029
|
+
if (sync.data.project_diff[sdk.directory] !== undefined) return
|
|
1030
|
+
} else if (store.changes === "session") {
|
|
1031
|
+
if (sync.data.session_diff[id] !== undefined) return
|
|
1032
|
+
} else {
|
|
1033
|
+
return
|
|
1034
|
+
}
|
|
978
1035
|
if (sync.status === "loading") return
|
|
979
1036
|
|
|
1037
|
+
if (store.changes === "project") {
|
|
1038
|
+
void sync.projectDiff.diff()
|
|
1039
|
+
return
|
|
1040
|
+
}
|
|
980
1041
|
void sync.session.diff(id)
|
|
981
1042
|
})
|
|
982
1043
|
|
|
@@ -1165,7 +1226,7 @@ export default function Page() {
|
|
|
1165
1226
|
<SessionMobileTabs
|
|
1166
1227
|
open={!isDesktop() && !!params.id}
|
|
1167
1228
|
mobileTab={store.mobileTab}
|
|
1168
|
-
hasReview={
|
|
1229
|
+
hasReview={hasAnyReview()}
|
|
1169
1230
|
reviewCount={reviewCount()}
|
|
1170
1231
|
onSession={() => setStore("mobileTab", "session")}
|
|
1171
1232
|
onChanges={() => setStore("mobileTab", "changes")}
|
|
@@ -1281,7 +1342,17 @@ export default function Page() {
|
|
|
1281
1342
|
</Show>
|
|
1282
1343
|
</div>
|
|
1283
1344
|
|
|
1284
|
-
<SessionSidePanel
|
|
1345
|
+
<SessionSidePanel
|
|
1346
|
+
reviewPanel={reviewPanel}
|
|
1347
|
+
activeDiff={tree.activeDiff}
|
|
1348
|
+
focusReviewDiff={focusReviewDiff}
|
|
1349
|
+
showReview={hasAnyReview}
|
|
1350
|
+
reviewCount={reviewCount}
|
|
1351
|
+
hasReview={hasReview}
|
|
1352
|
+
diffsReady={diffsReady}
|
|
1353
|
+
diffFiles={reviewDiffFiles}
|
|
1354
|
+
kinds={reviewKinds}
|
|
1355
|
+
/>
|
|
1285
1356
|
</div>
|
|
1286
1357
|
|
|
1287
1358
|
<TerminalPanel />
|