@bakapiano/ccsm 0.16.0 → 0.17.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/bin/ccsm.js +33 -0
- package/lib/config.js +20 -1
- package/lib/folders.js +23 -4
- package/package.json +1 -1
- package/public/css/feedback.css +115 -0
- package/public/css/sidebar.css +17 -0
- package/public/js/api.js +15 -2
- package/public/js/components/App.js +2 -2
- package/public/js/components/EntityFormModal.js +22 -10
- package/public/js/components/HealthOverlay.js +91 -0
- package/public/js/components/KeybindingRecorder.js +138 -0
- package/public/js/components/Sidebar.js +87 -15
- package/public/js/keybindings.js +36 -6
- package/public/js/pages/AboutPage.js +33 -9
- package/public/js/pages/ConfigurePage.js +49 -49
- package/public/js/state.js +22 -3
- package/scripts/dev.js +46 -0
- package/scripts/install.js +14 -19
- package/scripts/upgrade-helper.js +551 -62
- package/server.js +43 -4
package/server.js
CHANGED
|
@@ -506,6 +506,24 @@ app.delete('/api/sessions/:id', asyncH(async (req, res) => {
|
|
|
506
506
|
res.json({ removed });
|
|
507
507
|
}));
|
|
508
508
|
|
|
509
|
+
// Reorder sessions within a folder. Body: { folderId, ids } where ids
|
|
510
|
+
// is the new sequence of session ids in their final display order
|
|
511
|
+
// inside that folder. Each session gets `folderId` + `order: 0..N-1`
|
|
512
|
+
// assigned. Setting folderId here (rather than requiring a separate
|
|
513
|
+
// PUT) lets the drag-and-drop UI move a session across folders AND
|
|
514
|
+
// drop it at a specific position in one shot — without the call, the
|
|
515
|
+
// move would either land at the end of the destination folder (just
|
|
516
|
+
// PUT folderId) or leave it in place (just reorder).
|
|
517
|
+
app.post('/api/sessions/reorder', asyncH(async (req, res) => {
|
|
518
|
+
const ids = Array.isArray(req.body?.ids) ? req.body.ids : null;
|
|
519
|
+
if (!ids) return res.status(400).json({ error: 'ids array required' });
|
|
520
|
+
const folderId = req.body?.folderId ?? null;
|
|
521
|
+
for (let i = 0; i < ids.length; i++) {
|
|
522
|
+
try { await persistedSessions.update(ids[i], { folderId, order: i }); } catch {}
|
|
523
|
+
}
|
|
524
|
+
res.json({ ok: true, count: ids.length });
|
|
525
|
+
}));
|
|
526
|
+
|
|
509
527
|
// ---- workspaces ----
|
|
510
528
|
|
|
511
529
|
// ---- directory browser ----
|
|
@@ -1027,6 +1045,11 @@ function cmpSemver(a, b) {
|
|
|
1027
1045
|
app.get('/api/version', asyncH(async (req, res) => {
|
|
1028
1046
|
const force = String(req.query.refresh || '') === '1';
|
|
1029
1047
|
const now = Date.now();
|
|
1048
|
+
// devMode: set when the server was launched from scripts/dev.js
|
|
1049
|
+
// (CCSM_DEV=1). Lets the About page render a "test upgrade flow"
|
|
1050
|
+
// button that re-installs to a sandbox prefix without affecting the
|
|
1051
|
+
// user's global ccsm install.
|
|
1052
|
+
const devMode = process.env.CCSM_DEV === '1';
|
|
1030
1053
|
if (!force && versionCache && (now - versionCache.fetchedAt) < VERSION_CACHE_MS) {
|
|
1031
1054
|
return res.json({
|
|
1032
1055
|
current: pkg.version,
|
|
@@ -1034,6 +1057,7 @@ app.get('/api/version', asyncH(async (req, res) => {
|
|
|
1034
1057
|
updateAvailable: cmpSemver(versionCache.latest, pkg.version) > 0,
|
|
1035
1058
|
fetchedAt: versionCache.fetchedAt,
|
|
1036
1059
|
cached: true,
|
|
1060
|
+
devMode,
|
|
1037
1061
|
});
|
|
1038
1062
|
}
|
|
1039
1063
|
try {
|
|
@@ -1045,16 +1069,16 @@ app.get('/api/version', asyncH(async (req, res) => {
|
|
|
1045
1069
|
updateAvailable: cmpSemver(latest, pkg.version) > 0,
|
|
1046
1070
|
fetchedAt: now,
|
|
1047
1071
|
cached: false,
|
|
1072
|
+
devMode,
|
|
1048
1073
|
});
|
|
1049
1074
|
} catch (e) {
|
|
1050
|
-
// Swallow: surface "unknown" so the UI doesn't keep showing a stale
|
|
1051
|
-
// "update available" badge based on a 6-hour-old cached value.
|
|
1052
1075
|
res.json({
|
|
1053
1076
|
current: pkg.version,
|
|
1054
1077
|
latest: null,
|
|
1055
1078
|
updateAvailable: false,
|
|
1056
1079
|
fetchedAt: now,
|
|
1057
1080
|
error: String(e.message || e),
|
|
1081
|
+
devMode,
|
|
1058
1082
|
});
|
|
1059
1083
|
}
|
|
1060
1084
|
}));
|
|
@@ -1094,9 +1118,24 @@ app.post('/api/upgrade', asyncH(async (req, res) => {
|
|
|
1094
1118
|
upgradeInFlight = false;
|
|
1095
1119
|
return res.status(500).json({ error: `helper copy failed: ${e.message}` });
|
|
1096
1120
|
}
|
|
1097
|
-
|
|
1121
|
+
// Where to send the user back when the upgrade succeeds. In prod
|
|
1122
|
+
// that's the GH Pages router (it'll re-probe localhost:7777 and
|
|
1123
|
+
// redirect to the matching per-version frontend); in dev (CCSM_DEV=1)
|
|
1124
|
+
// that's our local server on whatever port we're listening on, so
|
|
1125
|
+
// the test sandbox flow returns to the dev instance instead of
|
|
1126
|
+
// hitting GH Pages (which doesn't know about port 7788).
|
|
1127
|
+
const redirectTo = frontendUrl || `http://localhost:${currentPort}/`;
|
|
1098
1128
|
|
|
1099
|
-
|
|
1129
|
+
const args = [helperTmp, target, String(currentPort), String(process.pid), installPrefix, respawn, redirectTo];
|
|
1130
|
+
|
|
1131
|
+
res.json({
|
|
1132
|
+
ok: true,
|
|
1133
|
+
started: true,
|
|
1134
|
+
target,
|
|
1135
|
+
helper: helperTmp,
|
|
1136
|
+
helperUrl: 'http://localhost:7779/',
|
|
1137
|
+
closeFrontend: false,
|
|
1138
|
+
});
|
|
1100
1139
|
|
|
1101
1140
|
// Flush response, then spawn helper detached and gracefulShutdown so
|
|
1102
1141
|
// the helper's npm install isn't fighting our open file handles.
|