Compare commits
4 Commits
07d2e215e4
..
v1.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 120b61a423 | |||
| cd16b7ea28 | |||
| afbdefa549 | |||
| f1e192c5d4 |
@@ -79,29 +79,7 @@ jobs:
|
||||
|
||||
- name: Create Gitea release
|
||||
run: |
|
||||
cat > /tmp/make_release.py << 'PYEOF'
|
||||
import json, os
|
||||
v = os.environ['VERSION']
|
||||
img = os.environ['IMAGE']
|
||||
raw = open('/tmp/release_notes.txt').read().strip()
|
||||
feats, fixes = [], []
|
||||
for line in raw.splitlines():
|
||||
msg = line.lstrip('- ').strip()
|
||||
if msg.startswith('feat:'):
|
||||
feats.append('- ' + msg[5:].strip())
|
||||
elif msg.startswith('fix:'):
|
||||
fixes.append('- ' + msg[4:].strip())
|
||||
sections = []
|
||||
if feats:
|
||||
sections.append('### New Features\n\n' + '\n'.join(feats))
|
||||
if fixes:
|
||||
sections.append('### Bug Fixes\n\n' + '\n'.join(fixes))
|
||||
notes = '\n\n'.join(sections) or '_No changes_'
|
||||
body = notes + '\n\n### Image\n\n`' + img + ':' + v + '`'
|
||||
payload = {'tag_name': 'v'+v, 'name': 'Catalyst v'+v, 'body': body, 'draft': False, 'prerelease': False}
|
||||
open('/tmp/release_body.json', 'w').write(json.dumps(payload))
|
||||
PYEOF
|
||||
python3 /tmp/make_release.py
|
||||
python3 -c "import json,os; v=os.environ['VERSION']; img=os.environ['IMAGE']; notes=open('/tmp/release_notes.txt').read(); open('/tmp/release_body.json','w').write(json.dumps({'tag_name':'v'+v,'name':'Catalyst v'+v,'body':'### Changes\n\n'+notes+'\n\n### Image\n\n'+img+':'+v,'draft':False,'prerelease':False}))"
|
||||
curl -sf -X POST \
|
||||
-H "Authorization: token ${{ secrets.TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
|
||||
-52
@@ -712,55 +712,3 @@ select:focus { border-color: var(--accent); }
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
|
||||
/* ── MOBILE ── */
|
||||
@media (max-width: 640px) {
|
||||
/* Reset desktop zoom — mobile browsers handle scaling themselves */
|
||||
html { zoom: 1; }
|
||||
|
||||
/* Nav */
|
||||
nav { padding: 0 16px; }
|
||||
|
||||
/* Dashboard header */
|
||||
.dash-header { padding: 18px 16px 14px; }
|
||||
|
||||
/* Stats bar */
|
||||
.stat-cell { padding: 10px 16px; }
|
||||
|
||||
/* Toolbar — search full-width on first row, filters + button below */
|
||||
.toolbar { flex-wrap: wrap; padding: 10px 16px; gap: 8px; }
|
||||
.search-wrap { max-width: 100%; }
|
||||
.toolbar-right { margin-left: 0; width: 100%; justify-content: flex-end; }
|
||||
|
||||
/* Instance grid — single column */
|
||||
.instance-grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 12px 16px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Detail page */
|
||||
.detail-page { padding: 16px; }
|
||||
|
||||
/* Detail header — stack title block above actions */
|
||||
.detail-header { flex-direction: column; align-items: flex-start; gap: 14px; }
|
||||
|
||||
/* Detail sub — wrap items when they don't fit */
|
||||
.detail-sub { flex-wrap: wrap; row-gap: 4px; }
|
||||
|
||||
/* Detail grid — single column */
|
||||
.detail-grid { grid-template-columns: 1fr; }
|
||||
|
||||
/* Toggle grid — 2 columns instead of 3 */
|
||||
.toggle-grid { grid-template-columns: 1fr 1fr; }
|
||||
|
||||
/* Confirm box — no fixed width on mobile */
|
||||
.confirm-box { width: auto; max-width: calc(100vw - 32px); padding: 18px; }
|
||||
|
||||
/* History timeline — stack timestamp above event */
|
||||
.tl-item { flex-direction: column; align-items: flex-start; gap: 3px; }
|
||||
.tl-time { order: -1; }
|
||||
|
||||
/* Toast — stretch across bottom */
|
||||
.toast { right: 16px; left: 16px; bottom: 16px; }
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
const VERSION = "1.3.1";
|
||||
const VERSION = "1.3.0";
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "catalyst",
|
||||
"version": "1.3.1",
|
||||
"version": "1.3.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node server/server.js",
|
||||
|
||||
+1
-3
@@ -151,13 +151,11 @@ export function updateInstance(vmid, data) {
|
||||
}
|
||||
|
||||
export function deleteInstance(vmid) {
|
||||
db.prepare('DELETE FROM instance_history WHERE vmid = ?').run(vmid);
|
||||
db.prepare('DELETE FROM instances WHERE vmid = ?').run(vmid);
|
||||
return db.prepare('DELETE FROM instances WHERE vmid = ?').run(vmid);
|
||||
}
|
||||
|
||||
export function importInstances(rows) {
|
||||
db.exec('BEGIN');
|
||||
db.exec('DELETE FROM instance_history');
|
||||
db.exec('DELETE FROM instances');
|
||||
const insert = db.prepare(`
|
||||
INSERT INTO instances
|
||||
|
||||
@@ -164,19 +164,6 @@ describe('deleteInstance', () => {
|
||||
expect(getInstance(1)).toBeNull();
|
||||
expect(getInstance(2)).not.toBeNull();
|
||||
});
|
||||
|
||||
it('clears history for the deleted instance', () => {
|
||||
createInstance({ ...base, name: 'a', vmid: 1 });
|
||||
deleteInstance(1);
|
||||
expect(getInstanceHistory(1)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('does not clear history for other instances', () => {
|
||||
createInstance({ ...base, name: 'a', vmid: 1 });
|
||||
createInstance({ ...base, name: 'b', vmid: 2 });
|
||||
deleteInstance(1);
|
||||
expect(getInstanceHistory(2).length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
// ── importInstances ───────────────────────────────────────────────────────────
|
||||
@@ -196,12 +183,6 @@ describe('importInstances', () => {
|
||||
importInstances([]);
|
||||
expect(getInstances()).toEqual([]);
|
||||
});
|
||||
|
||||
it('clears history for all replaced instances', () => {
|
||||
createInstance({ ...base, name: 'old', vmid: 1 });
|
||||
importInstances([{ ...base, name: 'new', vmid: 2 }]);
|
||||
expect(getInstanceHistory(1)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
// ── instance history ─────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user