cohvu 2.13.0 → 2.15.0
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/dist/api.d.ts +48 -0
- package/dist/api.js +15 -0
- package/dist/api.js.map +1 -1
- package/dist/instructions.d.ts +2 -2
- package/dist/instructions.js +135 -55
- package/dist/instructions.js.map +1 -1
- package/dist/tui/App.js +243 -14
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/Banner.js +12 -18
- package/dist/tui/components/Banner.js.map +1 -1
- package/dist/tui/components/Footer.js +1 -1
- package/dist/tui/components/Footer.js.map +1 -1
- package/dist/tui/components/Header.js +51 -80
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/Modal.js +42 -4
- package/dist/tui/components/Modal.js.map +1 -1
- package/dist/tui/components/TabBar.js +1 -0
- package/dist/tui/components/TabBar.js.map +1 -1
- package/dist/tui/state.d.ts +41 -2
- package/dist/tui/state.js +28 -1
- package/dist/tui/state.js.map +1 -1
- package/dist/tui/tabs/BillingTab.js +33 -39
- package/dist/tui/tabs/BillingTab.js.map +1 -1
- package/dist/tui/tabs/KeysTab.d.ts +5 -0
- package/dist/tui/tabs/KeysTab.js +34 -0
- package/dist/tui/tabs/KeysTab.js.map +1 -0
- package/dist/tui/tabs/KnowledgeTab.js +3 -3
- package/dist/tui/tabs/KnowledgeTab.js.map +1 -1
- package/dist/tui/tabs/ProjectTab.js +2 -2
- package/dist/tui/tabs/ProjectTab.js.map +1 -1
- package/package.json +1 -1
package/dist/tui/App.js
CHANGED
|
@@ -18,7 +18,9 @@ import { KnowledgeTab } from './tabs/KnowledgeTab.js';
|
|
|
18
18
|
import { TeamTab } from './tabs/TeamTab.js';
|
|
19
19
|
import { BillingTab } from './tabs/BillingTab.js';
|
|
20
20
|
import { ProjectTab } from './tabs/ProjectTab.js';
|
|
21
|
+
import { KeysTab } from './tabs/KeysTab.js';
|
|
21
22
|
import { YouTab } from './tabs/YouTab.js';
|
|
23
|
+
import { KNOWN_TOOL_NAMES } from './state.js';
|
|
22
24
|
import { daysUntil, timeUntil } from './utils.js';
|
|
23
25
|
import { exec, execFile } from 'child_process';
|
|
24
26
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, watch } from 'fs';
|
|
@@ -219,6 +221,20 @@ export default function App() {
|
|
|
219
221
|
}
|
|
220
222
|
break;
|
|
221
223
|
}
|
|
224
|
+
case 'project':
|
|
225
|
+
break;
|
|
226
|
+
case 'keys': {
|
|
227
|
+
dispatch({ type: 'SET_API_KEYS_LOADING', loading: true });
|
|
228
|
+
// Integration keys require admin on the active project — skip the
|
|
229
|
+
// call if not, since the API will 403 anyway.
|
|
230
|
+
const integrationKeys = (s.userRole === 'admin')
|
|
231
|
+
? await api.listIntegrationKeys(projectId).catch(() => [])
|
|
232
|
+
: [];
|
|
233
|
+
if (stateRef.current.activeProjectId !== projectId)
|
|
234
|
+
break;
|
|
235
|
+
dispatch({ type: 'SET_API_KEYS', keys: integrationKeys });
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
222
238
|
}
|
|
223
239
|
}
|
|
224
240
|
catch {
|
|
@@ -501,7 +517,7 @@ export default function App() {
|
|
|
501
517
|
}
|
|
502
518
|
// Number keys switch tabs (but not when typing in search mode)
|
|
503
519
|
const tabIdx = parseInt(input, 10);
|
|
504
|
-
if (tabIdx >= 1 && tabIdx <=
|
|
520
|
+
if (tabIdx >= 1 && tabIdx <= TABS.length && !key.ctrl && !key.meta && !(s.tab === 'knowledge' && s.knowledgeMode !== 'browse')) {
|
|
505
521
|
dispatch({ type: 'SWITCH_TAB', tab: TABS[tabIdx - 1] });
|
|
506
522
|
setTimeout(() => loadTabData(), 0);
|
|
507
523
|
return;
|
|
@@ -525,11 +541,50 @@ export default function App() {
|
|
|
525
541
|
case 'project':
|
|
526
542
|
await handleProjectKey(input, key);
|
|
527
543
|
break;
|
|
544
|
+
case 'keys':
|
|
545
|
+
await handleKeysKey(input, key);
|
|
546
|
+
break;
|
|
528
547
|
case 'you':
|
|
529
548
|
await handleYouKey(input, key);
|
|
530
549
|
break;
|
|
531
550
|
}
|
|
532
551
|
}
|
|
552
|
+
// ---- Keys tab keys ----
|
|
553
|
+
async function handleKeysKey(input, key) {
|
|
554
|
+
const s = stateRef.current;
|
|
555
|
+
if (key.upArrow) {
|
|
556
|
+
dispatch({ type: 'SET_API_KEYS_SELECTED', index: Math.max(0, s.apiKeysSelected - 1) });
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (key.downArrow) {
|
|
560
|
+
const max = Math.max(0, s.apiKeys.length - 1);
|
|
561
|
+
dispatch({ type: 'SET_API_KEYS_SELECTED', index: Math.min(max, s.apiKeysSelected + 1) });
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (input === 'n' && s.userRole === 'admin') {
|
|
565
|
+
const adminProjects = adminScopableProjects(s);
|
|
566
|
+
dispatch({ type: 'OPEN_MODAL', modal: {
|
|
567
|
+
kind: 'create-integration-key',
|
|
568
|
+
step: 'name',
|
|
569
|
+
input: '',
|
|
570
|
+
projectId: adminProjects[0]?.project_id ?? '',
|
|
571
|
+
projectSelectedIdx: 0,
|
|
572
|
+
role: 'member',
|
|
573
|
+
roleSelectedIdx: 1,
|
|
574
|
+
allowedTools: [],
|
|
575
|
+
toolsSelectedIdx: 0,
|
|
576
|
+
agentName: '',
|
|
577
|
+
} });
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (input === 'x' && s.apiKeys.length > 0) {
|
|
581
|
+
const target = s.apiKeys[s.apiKeysSelected];
|
|
582
|
+
if (target) {
|
|
583
|
+
dispatch({ type: 'OPEN_MODAL', modal: { kind: 'confirm-revoke-key', keyId: target.id, keyName: target.name } });
|
|
584
|
+
}
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
533
588
|
// ---- Knowledge keys ----
|
|
534
589
|
async function handleKnowledgeKey(input, key) {
|
|
535
590
|
const s = stateRef.current;
|
|
@@ -579,7 +634,7 @@ export default function App() {
|
|
|
579
634
|
const projectId = s.activeProjectId;
|
|
580
635
|
if (projectId) {
|
|
581
636
|
let failures = 0;
|
|
582
|
-
dispatch({ type: 'SET_OPERATION', operation: 'Removing
|
|
637
|
+
dispatch({ type: 'SET_OPERATION', operation: 'Removing contributions' });
|
|
583
638
|
await Promise.all([...s.forgetSelected].map(async (id) => {
|
|
584
639
|
try {
|
|
585
640
|
await api.deleteMemory(projectId, id);
|
|
@@ -838,7 +893,7 @@ export default function App() {
|
|
|
838
893
|
}
|
|
839
894
|
}
|
|
840
895
|
// ---- Project keys ----
|
|
841
|
-
async function handleProjectKey(input,
|
|
896
|
+
async function handleProjectKey(input, key) {
|
|
842
897
|
const s = stateRef.current;
|
|
843
898
|
if (input === 't') {
|
|
844
899
|
dispatch({ type: 'OPEN_MODAL', modal: { kind: 'create-team', input: '' } });
|
|
@@ -955,7 +1010,7 @@ export default function App() {
|
|
|
955
1010
|
if (modal.kind === 'confirm-forget' || modal.kind === 'confirm-remove-member' ||
|
|
956
1011
|
modal.kind === 'confirm-leave' || modal.kind === 'confirm-logout' ||
|
|
957
1012
|
modal.kind === 'confirm-regen-link' || modal.kind === 'initiate-consensus' ||
|
|
958
|
-
modal.kind === 'approve-action') {
|
|
1013
|
+
modal.kind === 'approve-action' || modal.kind === 'confirm-revoke-key') {
|
|
959
1014
|
if (input === 'y') {
|
|
960
1015
|
const willExit = modal.kind === 'confirm-logout';
|
|
961
1016
|
await confirmModal(modal);
|
|
@@ -967,6 +1022,116 @@ export default function App() {
|
|
|
967
1022
|
}
|
|
968
1023
|
return;
|
|
969
1024
|
}
|
|
1025
|
+
// Integration key creation wizard
|
|
1026
|
+
if (modal.kind === 'create-integration-key') {
|
|
1027
|
+
const adminProjects = adminScopableProjects(s);
|
|
1028
|
+
if (modal.step === 'name') {
|
|
1029
|
+
if (key.return && modal.input.trim().length > 0) {
|
|
1030
|
+
if (adminProjects.length === 0) {
|
|
1031
|
+
showInlineError('no projects you can scope an integration key to', 3000);
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, step: 'project' } });
|
|
1035
|
+
}
|
|
1036
|
+
else if (key.backspace || key.delete) {
|
|
1037
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, input: modal.input.slice(0, -1) } });
|
|
1038
|
+
}
|
|
1039
|
+
else if (input === ' ') {
|
|
1040
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, input: modal.input + ' ' } });
|
|
1041
|
+
}
|
|
1042
|
+
else if (input.length === 1 && !key.ctrl && !key.meta) {
|
|
1043
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, input: modal.input + input } });
|
|
1044
|
+
}
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
if (modal.step === 'project') {
|
|
1048
|
+
if (adminProjects.length === 0)
|
|
1049
|
+
return;
|
|
1050
|
+
if (key.upArrow) {
|
|
1051
|
+
const i = Math.max(0, modal.projectSelectedIdx - 1);
|
|
1052
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, projectSelectedIdx: i, projectId: adminProjects[i].project_id } });
|
|
1053
|
+
}
|
|
1054
|
+
else if (key.downArrow) {
|
|
1055
|
+
const i = Math.min(adminProjects.length - 1, modal.projectSelectedIdx + 1);
|
|
1056
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, projectSelectedIdx: i, projectId: adminProjects[i].project_id } });
|
|
1057
|
+
}
|
|
1058
|
+
else if (key.return && modal.projectId) {
|
|
1059
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, step: 'role' } });
|
|
1060
|
+
}
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
if (modal.step === 'role') {
|
|
1064
|
+
const roles = ['admin', 'member', 'viewer'];
|
|
1065
|
+
if (key.upArrow) {
|
|
1066
|
+
const i = Math.max(0, modal.roleSelectedIdx - 1);
|
|
1067
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, roleSelectedIdx: i, role: roles[i] } });
|
|
1068
|
+
}
|
|
1069
|
+
else if (key.downArrow) {
|
|
1070
|
+
const i = Math.min(2, modal.roleSelectedIdx + 1);
|
|
1071
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, roleSelectedIdx: i, role: roles[i] } });
|
|
1072
|
+
}
|
|
1073
|
+
else if (key.return) {
|
|
1074
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, step: 'tools' } });
|
|
1075
|
+
}
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
if (modal.step === 'tools') {
|
|
1079
|
+
if (key.upArrow) {
|
|
1080
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, toolsSelectedIdx: Math.max(0, modal.toolsSelectedIdx - 1) } });
|
|
1081
|
+
}
|
|
1082
|
+
else if (key.downArrow) {
|
|
1083
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, toolsSelectedIdx: Math.min(KNOWN_TOOL_NAMES.length - 1, modal.toolsSelectedIdx + 1) } });
|
|
1084
|
+
}
|
|
1085
|
+
else if (input === ' ') {
|
|
1086
|
+
const t = KNOWN_TOOL_NAMES[modal.toolsSelectedIdx];
|
|
1087
|
+
const next = modal.allowedTools.includes(t)
|
|
1088
|
+
? modal.allowedTools.filter(x => x !== t)
|
|
1089
|
+
: [...modal.allowedTools, t];
|
|
1090
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, allowedTools: next } });
|
|
1091
|
+
}
|
|
1092
|
+
else if (key.return) {
|
|
1093
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, step: 'agent' } });
|
|
1094
|
+
}
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
if (modal.step === 'agent') {
|
|
1098
|
+
if (key.return) {
|
|
1099
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, step: 'confirm' } });
|
|
1100
|
+
}
|
|
1101
|
+
else if (key.backspace || key.delete) {
|
|
1102
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, agentName: modal.agentName.slice(0, -1) } });
|
|
1103
|
+
}
|
|
1104
|
+
else if (input === ' ') {
|
|
1105
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, agentName: modal.agentName + ' ' } });
|
|
1106
|
+
}
|
|
1107
|
+
else if (input.length === 1 && !key.ctrl && !key.meta) {
|
|
1108
|
+
dispatch({ type: 'OPEN_MODAL', modal: { ...modal, agentName: modal.agentName + input } });
|
|
1109
|
+
}
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
if (modal.step === 'confirm') {
|
|
1113
|
+
if (input === 'y') {
|
|
1114
|
+
await confirmModal(modal);
|
|
1115
|
+
// confirmModal handles the modal transition (closes on error, opens key-created on success)
|
|
1116
|
+
}
|
|
1117
|
+
else if (input === 'n') {
|
|
1118
|
+
dispatch({ type: 'CLOSE_MODAL' });
|
|
1119
|
+
}
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
// Key created — copy or dismiss (esc handled at top)
|
|
1125
|
+
if (modal.kind === 'key-created') {
|
|
1126
|
+
if (input === 'c') {
|
|
1127
|
+
copyToClipboard(modal.keyValue);
|
|
1128
|
+
dispatch({ type: 'SET_COPIED_FEEDBACK', active: true });
|
|
1129
|
+
if (copiedTimerRef.current)
|
|
1130
|
+
clearTimeout(copiedTimerRef.current);
|
|
1131
|
+
copiedTimerRef.current = setTimeout(() => dispatch({ type: 'SET_COPIED_FEEDBACK', active: false }), 1500);
|
|
1132
|
+
}
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
970
1135
|
// Text input modals
|
|
971
1136
|
if ('input' in modal) {
|
|
972
1137
|
if (key.return) {
|
|
@@ -1338,6 +1503,55 @@ export default function App() {
|
|
|
1338
1503
|
}
|
|
1339
1504
|
return false;
|
|
1340
1505
|
}
|
|
1506
|
+
if (modal.kind === 'create-integration-key') {
|
|
1507
|
+
// Only the confirm step submits — earlier steps just advance via OPEN_MODAL.
|
|
1508
|
+
if (modal.step !== 'confirm')
|
|
1509
|
+
return false;
|
|
1510
|
+
if (!modal.input.trim() || !modal.projectId)
|
|
1511
|
+
return false;
|
|
1512
|
+
try {
|
|
1513
|
+
dispatch({ type: 'SET_OPERATION', operation: 'Creating key' });
|
|
1514
|
+
const result = await api.createApiKey({
|
|
1515
|
+
kind: 'integration',
|
|
1516
|
+
name: modal.input.trim(),
|
|
1517
|
+
projects: [{ project_id: modal.projectId, role: modal.role }],
|
|
1518
|
+
...(modal.allowedTools.length > 0 ? { allowed_tools: modal.allowedTools } : {}),
|
|
1519
|
+
...(modal.agentName.trim() ? { default_agent_name: modal.agentName.trim() } : {}),
|
|
1520
|
+
});
|
|
1521
|
+
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1522
|
+
const integrationKeys = stateRef.current.userRole === 'admin' && stateRef.current.activeProjectId
|
|
1523
|
+
? await api.listIntegrationKeys(stateRef.current.activeProjectId).catch(() => [])
|
|
1524
|
+
: [];
|
|
1525
|
+
dispatch({ type: 'SET_API_KEYS', keys: integrationKeys });
|
|
1526
|
+
dispatch({ type: 'OPEN_MODAL', modal: {
|
|
1527
|
+
kind: 'key-created',
|
|
1528
|
+
keyId: result.api_key.id,
|
|
1529
|
+
keyValue: result.key,
|
|
1530
|
+
keyName: result.api_key.name,
|
|
1531
|
+
kind2: 'integration',
|
|
1532
|
+
} });
|
|
1533
|
+
return true;
|
|
1534
|
+
}
|
|
1535
|
+
catch {
|
|
1536
|
+
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1537
|
+
showToast('Failed to create key', 'error');
|
|
1538
|
+
}
|
|
1539
|
+
return false;
|
|
1540
|
+
}
|
|
1541
|
+
if (modal.kind === 'confirm-revoke-key') {
|
|
1542
|
+
try {
|
|
1543
|
+
dispatch({ type: 'SET_OPERATION', operation: 'Revoking key' });
|
|
1544
|
+
await api.deleteApiKey(modal.keyId);
|
|
1545
|
+
dispatch({ type: 'REMOVE_API_KEY', id: modal.keyId });
|
|
1546
|
+
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1547
|
+
showToast('Key revoked', 'success');
|
|
1548
|
+
}
|
|
1549
|
+
catch {
|
|
1550
|
+
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1551
|
+
showToast('Failed to revoke key', 'error');
|
|
1552
|
+
}
|
|
1553
|
+
return false;
|
|
1554
|
+
}
|
|
1341
1555
|
const projectId = s.activeProjectId;
|
|
1342
1556
|
if (!projectId)
|
|
1343
1557
|
return false;
|
|
@@ -1365,15 +1579,15 @@ export default function App() {
|
|
|
1365
1579
|
}
|
|
1366
1580
|
case 'confirm-forget':
|
|
1367
1581
|
try {
|
|
1368
|
-
dispatch({ type: 'SET_OPERATION', operation: 'Removing
|
|
1582
|
+
dispatch({ type: 'SET_OPERATION', operation: 'Removing contribution' });
|
|
1369
1583
|
await api.deleteMemory(projectId, modal.memoryId);
|
|
1370
1584
|
dispatch({ type: 'REMOVE_MEMORY', id: modal.memoryId });
|
|
1371
1585
|
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1372
|
-
showToast('
|
|
1586
|
+
showToast('Contribution removed', 'success');
|
|
1373
1587
|
}
|
|
1374
1588
|
catch {
|
|
1375
1589
|
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1376
|
-
showToast('Failed to remove
|
|
1590
|
+
showToast('Failed to remove contribution', 'error');
|
|
1377
1591
|
}
|
|
1378
1592
|
break;
|
|
1379
1593
|
case 'confirm-forget-all':
|
|
@@ -1384,7 +1598,7 @@ export default function App() {
|
|
|
1384
1598
|
const team = getActiveTeam(s);
|
|
1385
1599
|
if (team) {
|
|
1386
1600
|
try {
|
|
1387
|
-
await api.initiateApproval(team.team_id, 'clear_memories', `clear all
|
|
1601
|
+
await api.initiateApproval(team.team_id, 'clear_memories', `clear all contributions from "${project.slug}"`, projectId);
|
|
1388
1602
|
const approvals = await api.listApprovals(team.team_id);
|
|
1389
1603
|
dispatch({ type: 'SET_PENDING_APPROVALS', approvals });
|
|
1390
1604
|
showToast('Approval requested', 'info');
|
|
@@ -1396,15 +1610,15 @@ export default function App() {
|
|
|
1396
1610
|
}
|
|
1397
1611
|
}
|
|
1398
1612
|
try {
|
|
1399
|
-
dispatch({ type: 'SET_OPERATION', operation: 'Clearing
|
|
1613
|
+
dispatch({ type: 'SET_OPERATION', operation: 'Clearing contributions' });
|
|
1400
1614
|
await api.clearMemories(projectId);
|
|
1401
1615
|
dispatch({ type: 'SET_MEMORIES', memories: [], total: 0 });
|
|
1402
1616
|
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1403
|
-
showToast('All
|
|
1617
|
+
showToast('All contributions cleared', 'success');
|
|
1404
1618
|
}
|
|
1405
1619
|
catch {
|
|
1406
1620
|
dispatch({ type: 'SET_OPERATION', operation: null });
|
|
1407
|
-
showToast('Failed to clear
|
|
1621
|
+
showToast('Failed to clear contributions', 'error');
|
|
1408
1622
|
}
|
|
1409
1623
|
}
|
|
1410
1624
|
break;
|
|
@@ -1641,19 +1855,31 @@ function renderTab(state, height) {
|
|
|
1641
1855
|
case 'team': return _jsx(TeamTab, { state: state, height: height });
|
|
1642
1856
|
case 'billing': return _jsx(BillingTab, { state: state, height: height });
|
|
1643
1857
|
case 'project': return _jsx(ProjectTab, { state: state, height: height });
|
|
1858
|
+
case 'keys': return _jsx(KeysTab, { state: state, height: height });
|
|
1644
1859
|
case 'you': return _jsx(YouTab, { state: state, height: height });
|
|
1645
1860
|
}
|
|
1646
1861
|
}
|
|
1862
|
+
// Projects the caller can scope an integration key to. Personal projects are
|
|
1863
|
+
// always scopable by their owner; team projects only by team admins.
|
|
1864
|
+
function adminScopableProjects(s) {
|
|
1865
|
+
return s.projects.filter(p => {
|
|
1866
|
+
if (p.owner.kind === 'personal')
|
|
1867
|
+
return true; // user owns it
|
|
1868
|
+
const teamId = p.owner.teamId;
|
|
1869
|
+
const team = s.teams.find(t => t.team_id === teamId);
|
|
1870
|
+
return team?.role === 'admin';
|
|
1871
|
+
});
|
|
1872
|
+
}
|
|
1647
1873
|
function HelpOverlay({ state }) {
|
|
1648
1874
|
const lines = [
|
|
1649
|
-
['tab / 1-
|
|
1875
|
+
['tab / 1-6', 'switch tabs'],
|
|
1650
1876
|
['?', 'toggle this help'],
|
|
1651
1877
|
['q', 'quit'],
|
|
1652
1878
|
['', ''],
|
|
1653
1879
|
];
|
|
1654
1880
|
switch (state.tab) {
|
|
1655
1881
|
case 'knowledge':
|
|
1656
|
-
lines.push(['/', 'search'], ['enter', 'expand
|
|
1882
|
+
lines.push(['/', 'search'], ['enter', 'expand contribution'], ['↑↓', 'navigate'], ['space', 'load more'], ['d', 'forget mode'], ['D', 'forget all (admin)']);
|
|
1657
1883
|
break;
|
|
1658
1884
|
case 'team':
|
|
1659
1885
|
lines.push(['↑↓', 'navigate'], ['i', 'invite'], ['e', 'edit role (admin)'], ['x', 'remove member'], ['c', 'copy invite link'], ['r', 'regenerate link']);
|
|
@@ -1662,7 +1888,10 @@ function HelpOverlay({ state }) {
|
|
|
1662
1888
|
lines.push(['s', 'subscribe'], ['p', 'billing portal']);
|
|
1663
1889
|
break;
|
|
1664
1890
|
case 'project':
|
|
1665
|
-
lines.push(['w', 'switch project'], ['n', 'new project'], ['t', 'new team'], ['r', 'rename'], ['c', 'clear knowledge'], ['d', 'delete project']);
|
|
1891
|
+
lines.push(['↑↓', 'navigate links'], ['w', 'switch project'], ['n', 'new project'], ['t', 'new team'], ['r', 'rename'], ['c', 'clear knowledge'], ['d', 'delete project']);
|
|
1892
|
+
break;
|
|
1893
|
+
case 'keys':
|
|
1894
|
+
lines.push(['↑↓', 'navigate'], ['n', 'new key'], ['x', 'revoke selected']);
|
|
1666
1895
|
break;
|
|
1667
1896
|
case 'you':
|
|
1668
1897
|
lines.push(['p', 'pause / resume'], ['r', 're-run setup'], ['l', 'logout']);
|