@aryacode/dsh-aryacode-polish 0.14.0 → 0.15.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.15.2] - 2026-10-28
4
+
5
+ ### Added
6
+ - **Density modes.** A control in the tree header switches between comfortable and
7
+ compact rows, and the choice is remembered (`aryacode-polish:density.v1`). Density
8
+ changes row height only — the text size stays readable.
9
+
10
+ ### Fixed
11
+ - **Expand all now expands folders too.** The header button only flipped workspace rows, so a
12
+ folded folder kept its workspaces hidden while the button claimed everything was open.
13
+ - **Archived sessions no longer sit in their workspace.** The tree now reads
14
+ `archivedSessionIds` (it never did) and shows those sessions in a collapsed
15
+ **Archived** section at the bottom, each one restorable from its own menu.
16
+
3
17
  ## [0.14.0] - 2026-10-28
4
18
 
5
19
  ### Added
@@ -202,7 +202,7 @@ const WS_ROW = {
202
202
  gap: '6px',
203
203
  boxSizing: 'border-box',
204
204
  width: '100%',
205
- height: '28px',
205
+ height: 'var(--polish-ws-row, 28px)',
206
206
  padding: '0 6px',
207
207
  border: 'none',
208
208
  borderRadius: 'var(--dsw-radius-sm, 6px)',
@@ -385,6 +385,68 @@ export function moveBefore(list, movingId, beforeId) {
385
385
  const LOOK_KEY = 'aryacode-polish:workspace-appearance.v1'
386
386
  const ORDER_KEY = 'aryacode-polish:workspace-order.v1'
387
387
  const FOLD_KEY = 'aryacode-polish:folded.v1'
388
+ const DENSITY_KEY = 'aryacode-polish:density.v1'
389
+
390
+ export const DENSITIES = ['comfortable', 'compact']
391
+
392
+ /** Row height per density: the tree fits more rows without shrinking the text. */
393
+ export const DENSITY_METRICS = {
394
+ comfortable: { row: '28px' },
395
+ compact: { row: '22px' },
396
+ }
397
+
398
+ export function densityOf(value) {
399
+ return value === 'compact' ? 'compact' : 'comfortable'
400
+ }
401
+
402
+ export function readDensity(storage) {
403
+ try {
404
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
405
+ if (!store) return 'comfortable'
406
+ return densityOf(store.getItem(DENSITY_KEY))
407
+ } catch {
408
+ return 'comfortable'
409
+ }
410
+ }
411
+
412
+ export function writeDensity(value, storage) {
413
+ try {
414
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
415
+ if (!store) return
416
+ store.setItem(DENSITY_KEY, densityOf(value))
417
+ } catch {
418
+ /* remembering this is a nicety, not a requirement */
419
+ }
420
+ }
421
+
422
+ /**
423
+ * Split the flat session list into the rows a workspace shows and the ones it has
424
+ * archived. The shipped browser hides archived sessions; here they keep a section of
425
+ * their own at the bottom instead of disappearing without a trace.
426
+ */
427
+ export function splitArchived(sessions, archivedIds) {
428
+ const archive = archivedIds instanceof Set ? archivedIds : new Set(archivedIds || [])
429
+ const active = []
430
+ const archived = []
431
+ for (const session of Array.isArray(sessions) ? sessions : []) {
432
+ if (archive.has(session.id)) archived.push(session)
433
+ else active.push(session)
434
+ }
435
+ return { active, archived }
436
+ }
437
+
438
+ const WS_SECTION = {
439
+ display: 'flex',
440
+ alignItems: 'center',
441
+ gap: '5px',
442
+ padding: '8px 6px 2px',
443
+ textTransform: 'uppercase',
444
+ letterSpacing: '0.04em',
445
+ color: 'var(--dsw-alias-label-quaternary, #8a8a8a)',
446
+ fontSize: 'calc(' + 'var(--dsh-content-font-size-secondary, 13px)' + ' - 3px)',
447
+ cursor: 'pointer',
448
+ userSelect: 'none',
449
+ }
388
450
 
389
451
  /** Which workspaces and folders are folded, kept so a restart looks like yesterday. */
390
452
  export function readFolded(storage) {
@@ -715,6 +777,8 @@ export function BetterWorkspace(props) {
715
777
  const folded = React.useMemo(() => readFolded(), [])
716
778
  const [folders, setFolders] = React.useState(folded.folders)
717
779
  const [switcher, setSwitcher] = React.useState(null)
780
+ const [density, setDensity] = React.useState(() => readDensity())
781
+ const [archiveOpen, setArchiveOpen] = React.useState(false)
718
782
  React.useEffect(() => { writeFolded({ workspaces: expanded, folders }) }, [expanded, folders])
719
783
  const [renaming, setRenaming] = React.useState(null)
720
784
  const commitRename = async () => {
@@ -750,7 +814,11 @@ export function BetterWorkspace(props) {
750
814
  () => new Set((workspaceState && workspaceState.pinnedSessionIds) || []),
751
815
  [workspaceState],
752
816
  )
753
- const allRows = workspaceRows(workspaceList, sessionList)
817
+ const metrics = DENSITY_METRICS[densityOf(density)]
818
+ const archiveSet = new Set((workspaceState && workspaceState.archivedSessionIds) || [])
819
+ const split = splitArchived(sessionList, archiveSet)
820
+ const allRows = workspaceRows(workspaceList, split.active)
821
+ const archivedSessions = split.archived
754
822
  const rows = filterTree(allRows, query, pinned)
755
823
  const folderOf = (workspace) => folderKey(workspace)
756
824
  const visibleRows = rows.filter((group) => {
@@ -763,7 +831,12 @@ export function BetterWorkspace(props) {
763
831
  const entries = React.useMemo(() => rowMenuEntries(slots), [slots, workspaceList.length, sessionList.length])
764
832
  const totalCount = allRows.reduce((sum, row) => sum + row.sessions.length, 0)
765
833
  const shownCount = rows.reduce((sum, row) => sum + row.sessions.length, 0)
766
- const allFolded = rows.length > 0 && rows.every(row => expanded[row.workspace.workspaceId] === false)
834
+ const folderNames = Array.from(new Set(rows.map(row => folderKey(row.workspace)).filter(Boolean)))
835
+ // One click should always do the useful thing: if anything is folded, the button
836
+ // expands everything (folders included); only when nothing is folded does it fold.
837
+ const anyFolded = rows.some(row => expanded[row.workspace.workspaceId] === false)
838
+ || folderNames.some(name => folders[name] === true)
839
+ const allFolded = rows.length > 0 && !anyFolded
767
840
 
768
841
  React.useEffect(() => {
769
842
  if (cursor >= walk.length) setCursor(walk.length - 1)
@@ -833,10 +906,17 @@ export function BetterWorkspace(props) {
833
906
  })
834
907
  }
835
908
  const foldAll = () => {
836
- if (allFolded) { setExpanded({}); return }
909
+ if (anyFolded) {
910
+ setExpanded({})
911
+ setFolders({})
912
+ return
913
+ }
837
914
  const next = {}
838
915
  rows.forEach((row) => { next[row.workspace.workspaceId] = false })
916
+ const nextFolders = {}
917
+ folderNames.forEach((name) => { nextFolders[name] = true })
839
918
  setExpanded(next)
919
+ setFolders(nextFolders)
840
920
  }
841
921
 
842
922
  const reorderWorkspace = async (movingId, beforeId) => {
@@ -980,6 +1060,25 @@ export function BetterWorkspace(props) {
980
1060
  }, armed && armed === menu.workspace.workspaceId ? 'Remove workspace?' : 'Remove workspace'))
981
1061
  : null
982
1062
 
1063
+ const archivedMenu = menu && menu.kind === 'archived'
1064
+ ? React.createElement(RowMenu, { anchor: menu.anchor, onClose: closeMenu },
1065
+ React.createElement('button', {
1066
+ type: 'button',
1067
+ 'data-polish-ws-unarchive': menu.row.id,
1068
+ style: WS_MENU_ITEM,
1069
+ onClick: async () => {
1070
+ const row = menu.row
1071
+ closeMenu()
1072
+ try {
1073
+ await services.unarchiveSession(row.id)
1074
+ setNotice('Restored that session.')
1075
+ } catch {
1076
+ setNotice('Could not restore that session.')
1077
+ }
1078
+ },
1079
+ }, 'Unarchive session'))
1080
+ : null
1081
+
983
1082
  const paintMenu = menu && menu.kind === 'paint'
984
1083
  ? (() => {
985
1084
  const workspace = menu.workspace
@@ -1093,6 +1192,19 @@ export function BetterWorkspace(props) {
1093
1192
  style: WS_ADD,
1094
1193
  onClick: foldAll,
1095
1194
  }, allFolded ? '⌄' : '⌃'),
1195
+ React.createElement('button', {
1196
+ key: 'density',
1197
+ type: 'button',
1198
+ 'data-polish-ws-density': densityOf(density),
1199
+ title: densityOf(density) === 'compact' ? 'Use comfortable rows' : 'Use compact rows',
1200
+ 'aria-label': densityOf(density) === 'compact' ? 'Use comfortable rows' : 'Use compact rows',
1201
+ style: WS_ADD,
1202
+ onClick: () => {
1203
+ const next = densityOf(density) === 'compact' ? 'comfortable' : 'compact'
1204
+ setDensity(next)
1205
+ writeDensity(next)
1206
+ },
1207
+ }, densityOf(density) === 'compact' ? '≡' : '≣'),
1096
1208
  React.createElement('button', {
1097
1209
  key: 'add',
1098
1210
  type: 'button',
@@ -1301,6 +1413,36 @@ export function BetterWorkspace(props) {
1301
1413
  }
1302
1414
  })
1303
1415
 
1416
+ if (archivedSessions.length > 0) {
1417
+ children.push(React.createElement('div', {
1418
+ key: 'archived-head',
1419
+ 'data-polish-ws-archived': 'head',
1420
+ style: WS_SECTION,
1421
+ onClick: () => setArchiveOpen((open) => !open),
1422
+ },
1423
+ React.createElement('span', { 'aria-hidden': 'true' }, archiveOpen ? '⌄' : '›'),
1424
+ React.createElement('span', { style: WS_TITLE }, 'Archived'),
1425
+ React.createElement('span', { style: WS_COUNT }, String(archivedSessions.length))))
1426
+
1427
+ if (archiveOpen) {
1428
+ for (const row of archivedSessions) {
1429
+ children.push(React.createElement('div', {
1430
+ key: 'archived:' + row.id,
1431
+ 'data-polish-ws-archived-row': row.id,
1432
+ title: 'Archived session',
1433
+ style: Object.assign({}, WS_ROW, { opacity: 0.7, fontStyle: 'italic' }),
1434
+ onClick: () => services.openSession(row.id),
1435
+ onContextMenu: (event) => {
1436
+ event.preventDefault()
1437
+ event.stopPropagation()
1438
+ setMenu({ kind: 'archived', row, anchor: { top: event.clientY, left: event.clientX } })
1439
+ },
1440
+ },
1441
+ React.createElement('span', { style: WS_TITLE }, row.displayTitle || row.id)))
1442
+ }
1443
+ }
1444
+ }
1445
+
1304
1446
  return React.createElement('div', {
1305
1447
  'data-polish-ws': 'tree',
1306
1448
  tabIndex: 0,
@@ -1317,6 +1459,7 @@ export function BetterWorkspace(props) {
1317
1459
  overflowX: 'hidden',
1318
1460
  padding: '2px 6px 12px',
1319
1461
  outline: 'none',
1462
+ '--polish-ws-row': metrics.row,
1320
1463
  },
1321
1464
  },
1322
1465
  children,
@@ -1325,6 +1468,7 @@ export function BetterWorkspace(props) {
1325
1468
  : null,
1326
1469
  switcherCard,
1327
1470
  sessionMenu,
1471
+ archivedMenu,
1328
1472
  paintMenu,
1329
1473
  workspaceMenu)
1330
1474
  }
@@ -1451,6 +1595,7 @@ export function installWorkspaceSeat(ctx, configForms, extras = {}) {
1451
1595
  reorderSession: (workspaceId, movingId, beforeId) => seated.workspaces.insertSessionBefore(workspaceId, movingId, beforeId),
1452
1596
  removeWorkspace: (id) => seated.workspaces.delete(id),
1453
1597
  renameWorkspace: (id, title) => seated.workspaces.rename(id, title),
1598
+ unarchiveSession: (id) => seated.workspaces.unarchiveSession(id),
1454
1599
  openFolder: async (path) => {
1455
1600
  const answer = await seated.remote.session.openWorkspacePath({ path })
1456
1601
  if (answer && answer.ok === false) throw new Error('cannot open the folder')
@@ -152,3 +152,27 @@ panel's stacking context can clip it.
152
152
  like the way out. Verified across a real restart: folding `WORK` left
153
153
  `{"workspaces":{},"folders":{"Work":true}}` in storage and the folder still read `› WORK 2`
154
154
  with its workspace hidden.
155
+
156
+ ## Density
157
+
158
+ The header carries a density control that flips between comfortable (28 px rows) and
159
+ compact (22 px rows), remembered under `aryacode-polish:density.v1`. Density changes row
160
+ height only: the text keeps its size, so a compact tree is still readable on a laptop.
161
+ The row height travels through the CSS variable `--polish-ws-row`, which the tree element
162
+ sets from `DENSITY_METRICS`; nothing else in the row styling depends on the mode.
163
+
164
+ ## Archived sessions
165
+
166
+ Archiving a session removes it from its workspace — that is what the Host means by
167
+ archived, and the shipped browser simply stops rendering it. Here those sessions keep a
168
+ collapsed **Archived** section at the bottom of the tree instead, dimmed and italic, with
169
+ their count on the header. Clicking one opens it; right-clicking offers **Unarchive
170
+ session**, which goes through `workspaces.unarchiveSession`. This also fixed a real gap:
171
+ before this, `workspaceRows` never consulted `archivedSessionIds`, so archived sessions
172
+ were being rendered inline in their workspace as if they were live.
173
+
174
+ ## Folding everything
175
+
176
+ The header's fold control expands when anything is folded (folders included) and folds
177
+ only when nothing is. An earlier version only looked at workspace rows, so a folded
178
+ folder left the button saying "Expand all" while its workspaces stayed hidden.
package/lib/client.js CHANGED
@@ -53,7 +53,7 @@ window.__ModuleLoader__.load({
53
53
  ]
54
54
  const ROW_ID = "polish"
55
55
  const ROW_KEY = "@aryacode/dsh-aryacode-polish" + '#' + ROW_ID
56
- const CLIENT_VERSION = "0.14.0"
56
+ const CLIENT_VERSION = "0.15.2"
57
57
 
58
58
  /* html2canvas 1.4.1 — MIT, vendored from vendor/html2canvas.min.js.
59
59
  * A UMD build, so it assigns itself to globalThis; face.js reads it lazily. */
@@ -403,7 +403,7 @@ window.__ModuleLoader__.load({
403
403
  gap: '6px',
404
404
  boxSizing: 'border-box',
405
405
  width: '100%',
406
- height: '28px',
406
+ height: 'var(--polish-ws-row, 28px)',
407
407
  padding: '0 6px',
408
408
  border: 'none',
409
409
  borderRadius: 'var(--dsw-radius-sm, 6px)',
@@ -586,6 +586,68 @@ window.__ModuleLoader__.load({
586
586
  const LOOK_KEY = 'aryacode-polish:workspace-appearance.v1'
587
587
  const ORDER_KEY = 'aryacode-polish:workspace-order.v1'
588
588
  const FOLD_KEY = 'aryacode-polish:folded.v1'
589
+ const DENSITY_KEY = 'aryacode-polish:density.v1'
590
+
591
+ const DENSITIES = ['comfortable', 'compact']
592
+
593
+ /** Row height per density: the tree fits more rows without shrinking the text. */
594
+ const DENSITY_METRICS = {
595
+ comfortable: { row: '28px' },
596
+ compact: { row: '22px' },
597
+ }
598
+
599
+ function densityOf(value) {
600
+ return value === 'compact' ? 'compact' : 'comfortable'
601
+ }
602
+
603
+ function readDensity(storage) {
604
+ try {
605
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
606
+ if (!store) return 'comfortable'
607
+ return densityOf(store.getItem(DENSITY_KEY))
608
+ } catch {
609
+ return 'comfortable'
610
+ }
611
+ }
612
+
613
+ function writeDensity(value, storage) {
614
+ try {
615
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
616
+ if (!store) return
617
+ store.setItem(DENSITY_KEY, densityOf(value))
618
+ } catch {
619
+ /* remembering this is a nicety, not a requirement */
620
+ }
621
+ }
622
+
623
+ /**
624
+ * Split the flat session list into the rows a workspace shows and the ones it has
625
+ * archived. The shipped browser hides archived sessions; here they keep a section of
626
+ * their own at the bottom instead of disappearing without a trace.
627
+ */
628
+ function splitArchived(sessions, archivedIds) {
629
+ const archive = archivedIds instanceof Set ? archivedIds : new Set(archivedIds || [])
630
+ const active = []
631
+ const archived = []
632
+ for (const session of Array.isArray(sessions) ? sessions : []) {
633
+ if (archive.has(session.id)) archived.push(session)
634
+ else active.push(session)
635
+ }
636
+ return { active, archived }
637
+ }
638
+
639
+ const WS_SECTION = {
640
+ display: 'flex',
641
+ alignItems: 'center',
642
+ gap: '5px',
643
+ padding: '8px 6px 2px',
644
+ textTransform: 'uppercase',
645
+ letterSpacing: '0.04em',
646
+ color: 'var(--dsw-alias-label-quaternary, #8a8a8a)',
647
+ fontSize: 'calc(' + 'var(--dsh-content-font-size-secondary, 13px)' + ' - 3px)',
648
+ cursor: 'pointer',
649
+ userSelect: 'none',
650
+ }
589
651
 
590
652
  /** Which workspaces and folders are folded, kept so a restart looks like yesterday. */
591
653
  function readFolded(storage) {
@@ -916,6 +978,8 @@ window.__ModuleLoader__.load({
916
978
  const folded = React.useMemo(() => readFolded(), [])
917
979
  const [folders, setFolders] = React.useState(folded.folders)
918
980
  const [switcher, setSwitcher] = React.useState(null)
981
+ const [density, setDensity] = React.useState(() => readDensity())
982
+ const [archiveOpen, setArchiveOpen] = React.useState(false)
919
983
  React.useEffect(() => { writeFolded({ workspaces: expanded, folders }) }, [expanded, folders])
920
984
  const [renaming, setRenaming] = React.useState(null)
921
985
  const commitRename = async () => {
@@ -951,7 +1015,11 @@ window.__ModuleLoader__.load({
951
1015
  () => new Set((workspaceState && workspaceState.pinnedSessionIds) || []),
952
1016
  [workspaceState],
953
1017
  )
954
- const allRows = workspaceRows(workspaceList, sessionList)
1018
+ const metrics = DENSITY_METRICS[densityOf(density)]
1019
+ const archiveSet = new Set((workspaceState && workspaceState.archivedSessionIds) || [])
1020
+ const split = splitArchived(sessionList, archiveSet)
1021
+ const allRows = workspaceRows(workspaceList, split.active)
1022
+ const archivedSessions = split.archived
955
1023
  const rows = filterTree(allRows, query, pinned)
956
1024
  const folderOf = (workspace) => folderKey(workspace)
957
1025
  const visibleRows = rows.filter((group) => {
@@ -964,7 +1032,12 @@ window.__ModuleLoader__.load({
964
1032
  const entries = React.useMemo(() => rowMenuEntries(slots), [slots, workspaceList.length, sessionList.length])
965
1033
  const totalCount = allRows.reduce((sum, row) => sum + row.sessions.length, 0)
966
1034
  const shownCount = rows.reduce((sum, row) => sum + row.sessions.length, 0)
967
- const allFolded = rows.length > 0 && rows.every(row => expanded[row.workspace.workspaceId] === false)
1035
+ const folderNames = Array.from(new Set(rows.map(row => folderKey(row.workspace)).filter(Boolean)))
1036
+ // One click should always do the useful thing: if anything is folded, the button
1037
+ // expands everything (folders included); only when nothing is folded does it fold.
1038
+ const anyFolded = rows.some(row => expanded[row.workspace.workspaceId] === false)
1039
+ || folderNames.some(name => folders[name] === true)
1040
+ const allFolded = rows.length > 0 && !anyFolded
968
1041
 
969
1042
  React.useEffect(() => {
970
1043
  if (cursor >= walk.length) setCursor(walk.length - 1)
@@ -1034,10 +1107,17 @@ window.__ModuleLoader__.load({
1034
1107
  })
1035
1108
  }
1036
1109
  const foldAll = () => {
1037
- if (allFolded) { setExpanded({}); return }
1110
+ if (anyFolded) {
1111
+ setExpanded({})
1112
+ setFolders({})
1113
+ return
1114
+ }
1038
1115
  const next = {}
1039
1116
  rows.forEach((row) => { next[row.workspace.workspaceId] = false })
1117
+ const nextFolders = {}
1118
+ folderNames.forEach((name) => { nextFolders[name] = true })
1040
1119
  setExpanded(next)
1120
+ setFolders(nextFolders)
1041
1121
  }
1042
1122
 
1043
1123
  const reorderWorkspace = async (movingId, beforeId) => {
@@ -1181,6 +1261,25 @@ window.__ModuleLoader__.load({
1181
1261
  }, armed && armed === menu.workspace.workspaceId ? 'Remove workspace?' : 'Remove workspace'))
1182
1262
  : null
1183
1263
 
1264
+ const archivedMenu = menu && menu.kind === 'archived'
1265
+ ? React.createElement(RowMenu, { anchor: menu.anchor, onClose: closeMenu },
1266
+ React.createElement('button', {
1267
+ type: 'button',
1268
+ 'data-polish-ws-unarchive': menu.row.id,
1269
+ style: WS_MENU_ITEM,
1270
+ onClick: async () => {
1271
+ const row = menu.row
1272
+ closeMenu()
1273
+ try {
1274
+ await services.unarchiveSession(row.id)
1275
+ setNotice('Restored that session.')
1276
+ } catch {
1277
+ setNotice('Could not restore that session.')
1278
+ }
1279
+ },
1280
+ }, 'Unarchive session'))
1281
+ : null
1282
+
1184
1283
  const paintMenu = menu && menu.kind === 'paint'
1185
1284
  ? (() => {
1186
1285
  const workspace = menu.workspace
@@ -1294,6 +1393,19 @@ window.__ModuleLoader__.load({
1294
1393
  style: WS_ADD,
1295
1394
  onClick: foldAll,
1296
1395
  }, allFolded ? '⌄' : '⌃'),
1396
+ React.createElement('button', {
1397
+ key: 'density',
1398
+ type: 'button',
1399
+ 'data-polish-ws-density': densityOf(density),
1400
+ title: densityOf(density) === 'compact' ? 'Use comfortable rows' : 'Use compact rows',
1401
+ 'aria-label': densityOf(density) === 'compact' ? 'Use comfortable rows' : 'Use compact rows',
1402
+ style: WS_ADD,
1403
+ onClick: () => {
1404
+ const next = densityOf(density) === 'compact' ? 'comfortable' : 'compact'
1405
+ setDensity(next)
1406
+ writeDensity(next)
1407
+ },
1408
+ }, densityOf(density) === 'compact' ? '≡' : '≣'),
1297
1409
  React.createElement('button', {
1298
1410
  key: 'add',
1299
1411
  type: 'button',
@@ -1502,6 +1614,36 @@ window.__ModuleLoader__.load({
1502
1614
  }
1503
1615
  })
1504
1616
 
1617
+ if (archivedSessions.length > 0) {
1618
+ children.push(React.createElement('div', {
1619
+ key: 'archived-head',
1620
+ 'data-polish-ws-archived': 'head',
1621
+ style: WS_SECTION,
1622
+ onClick: () => setArchiveOpen((open) => !open),
1623
+ },
1624
+ React.createElement('span', { 'aria-hidden': 'true' }, archiveOpen ? '⌄' : '›'),
1625
+ React.createElement('span', { style: WS_TITLE }, 'Archived'),
1626
+ React.createElement('span', { style: WS_COUNT }, String(archivedSessions.length))))
1627
+
1628
+ if (archiveOpen) {
1629
+ for (const row of archivedSessions) {
1630
+ children.push(React.createElement('div', {
1631
+ key: 'archived:' + row.id,
1632
+ 'data-polish-ws-archived-row': row.id,
1633
+ title: 'Archived session',
1634
+ style: Object.assign({}, WS_ROW, { opacity: 0.7, fontStyle: 'italic' }),
1635
+ onClick: () => services.openSession(row.id),
1636
+ onContextMenu: (event) => {
1637
+ event.preventDefault()
1638
+ event.stopPropagation()
1639
+ setMenu({ kind: 'archived', row, anchor: { top: event.clientY, left: event.clientX } })
1640
+ },
1641
+ },
1642
+ React.createElement('span', { style: WS_TITLE }, row.displayTitle || row.id)))
1643
+ }
1644
+ }
1645
+ }
1646
+
1505
1647
  return React.createElement('div', {
1506
1648
  'data-polish-ws': 'tree',
1507
1649
  tabIndex: 0,
@@ -1518,6 +1660,7 @@ window.__ModuleLoader__.load({
1518
1660
  overflowX: 'hidden',
1519
1661
  padding: '2px 6px 12px',
1520
1662
  outline: 'none',
1663
+ '--polish-ws-row': metrics.row,
1521
1664
  },
1522
1665
  },
1523
1666
  children,
@@ -1526,6 +1669,7 @@ window.__ModuleLoader__.load({
1526
1669
  : null,
1527
1670
  switcherCard,
1528
1671
  sessionMenu,
1672
+ archivedMenu,
1529
1673
  paintMenu,
1530
1674
  workspaceMenu)
1531
1675
  }
@@ -1652,6 +1796,7 @@ window.__ModuleLoader__.load({
1652
1796
  reorderSession: (workspaceId, movingId, beforeId) => seated.workspaces.insertSessionBefore(workspaceId, movingId, beforeId),
1653
1797
  removeWorkspace: (id) => seated.workspaces.delete(id),
1654
1798
  renameWorkspace: (id, title) => seated.workspaces.rename(id, title),
1799
+ unarchiveSession: (id) => seated.workspaces.unarchiveSession(id),
1655
1800
  openFolder: async (path) => {
1656
1801
  const answer = await seated.remote.session.openWorkspacePath({ path })
1657
1802
  if (answer && answer.ok === false) throw new Error('cannot open the folder')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aryacode/dsh-aryacode-polish",
3
- "version": "0.14.0",
3
+ "version": "0.15.2",
4
4
  "description": "AryaCode Polish: one install for the small things that make AryaCode feel finished. One Plugins row, one switch per quality-of-life feature.",
5
5
  "keywords": [
6
6
  "dsh",