codexmate 0.0.22 → 0.0.23

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.
@@ -0,0 +1,85 @@
1
+ import {
2
+ buildSessionFilterCacheState,
3
+ isSessionQueryEnabled
4
+ } from '../logic.mjs';
5
+
6
+ export function normalizeSessionRoleFilter(value) {
7
+ const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
8
+ if (normalized === 'user' || normalized === 'assistant' || normalized === 'system') {
9
+ return normalized;
10
+ }
11
+ return 'all';
12
+ }
13
+
14
+ export function normalizeSessionTimePreset(value) {
15
+ const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
16
+ if (normalized === '7d' || normalized === '30d' || normalized === '90d') {
17
+ return normalized;
18
+ }
19
+ return 'all';
20
+ }
21
+
22
+ export function readSessionsFilterUrlState() {
23
+ try {
24
+ const url = new URL(window.location.href);
25
+ if (url.pathname === '/session') return null;
26
+ const source = (url.searchParams.get('s_source') || '').trim().toLowerCase();
27
+ const pathFilter = url.searchParams.get('s_path') || '';
28
+ const query = url.searchParams.get('s_query') || '';
29
+ const roleFilter = url.searchParams.get('s_role') || 'all';
30
+ const timeRangePreset = url.searchParams.get('s_time') || 'all';
31
+ const hasAny = !!(source || pathFilter || query || roleFilter !== 'all' || timeRangePreset !== 'all');
32
+ if (!hasAny) return null;
33
+ return {
34
+ source: source || 'all',
35
+ pathFilter,
36
+ query,
37
+ roleFilter,
38
+ timeRangePreset
39
+ };
40
+ } catch (_) {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ export function applySessionsFilterUrlState(vm, state) {
46
+ if (!vm || !state) return;
47
+ const cached = buildSessionFilterCacheState(state.source, state.pathFilter);
48
+ vm.sessionFilterSource = cached.source;
49
+ vm.sessionPathFilter = cached.pathFilter;
50
+ vm.sessionQuery = typeof state.query === 'string' ? state.query : '';
51
+ vm.sessionRoleFilter = normalizeSessionRoleFilter(state.roleFilter);
52
+ vm.sessionTimePreset = normalizeSessionTimePreset(state.timeRangePreset);
53
+ if (typeof vm.refreshSessionPathOptions === 'function') {
54
+ vm.refreshSessionPathOptions(vm.sessionFilterSource);
55
+ }
56
+ }
57
+
58
+ export function buildSessionsFilterShareUrl(vm) {
59
+ try {
60
+ const url = new URL(window.location.href);
61
+ if (url.pathname === '/session') return '';
62
+ url.searchParams.set('s_source', String(vm.sessionFilterSource || 'all'));
63
+ if (vm.sessionPathFilter) url.searchParams.set('s_path', String(vm.sessionPathFilter || ''));
64
+ else url.searchParams.delete('s_path');
65
+ if (vm.sessionQuery && isSessionQueryEnabled(vm.sessionFilterSource)) url.searchParams.set('s_query', String(vm.sessionQuery || ''));
66
+ else url.searchParams.delete('s_query');
67
+ if (vm.sessionRoleFilter && vm.sessionRoleFilter !== 'all') url.searchParams.set('s_role', String(vm.sessionRoleFilter || 'all'));
68
+ else url.searchParams.delete('s_role');
69
+ if (vm.sessionTimePreset && vm.sessionTimePreset !== 'all') url.searchParams.set('s_time', String(vm.sessionTimePreset || 'all'));
70
+ else url.searchParams.delete('s_time');
71
+ url.searchParams.set('tab', 'sessions');
72
+ return url.toString();
73
+ } catch (_) {
74
+ return '';
75
+ }
76
+ }
77
+
78
+ export function syncSessionsFilterUrl(vm) {
79
+ const url = buildSessionsFilterShareUrl(vm);
80
+ if (!url) return;
81
+ try {
82
+ window.history.replaceState(null, '', url);
83
+ } catch (_) {}
84
+ }
85
+
@@ -128,11 +128,11 @@
128
128
  <div class="brand-head">
129
129
  <img class="brand-logo" src="/res/logo.png" alt="Codex Mate logo">
130
130
  <div class="brand-copy">
131
- <div class="brand-kicker">Workspace</div>
131
+ <div class="brand-kicker">{{ t('brand.kicker.workspace') }}</div>
132
132
  <div class="brand-title">Codex Mate</div>
133
133
  </div>
134
134
  </div>
135
- <div class="brand-subtitle">Local config & sessions workspace</div>
135
+ <div class="brand-subtitle">{{ t('brand.subtitle.localConfigSessionsWorkspace') }}</div>
136
136
  </div>
137
137
 
138
138
  <div class="side-rail-nav">
@@ -5,6 +5,26 @@
5
5
  id="panel-config-claude"
6
6
  role="tabpanel"
7
7
  :aria-labelledby="'tab-config-claude'">
8
+ <template v-if="shouldShowCliInstallPlaceholder('claude')">
9
+ <div class="selector-section">
10
+ <div class="empty-state">
11
+ <div class="empty-state-title">{{ t('cli.missing.title', { name: 'Claude' }) }}</div>
12
+ <div class="empty-state-subtitle">{{ t('cli.missing.subtitle', { name: 'Claude' }) }}</div>
13
+ <div class="docs-command-row">
14
+ <div class="docs-command-box" role="group" :aria-label="t('cli.missing.commandAria', { name: 'Claude' })">
15
+ <code class="install-command">{{ getInstallCommand('claude', 'install') }}</code>
16
+ <button
17
+ type="button"
18
+ class="btn-mini docs-copy-btn"
19
+ :disabled="!getInstallCommand('claude', 'install')"
20
+ @click="copyInstallCommand(getInstallCommand('claude', 'install'))">{{ t('common.copy') }}</button>
21
+ </div>
22
+ </div>
23
+ <button type="button" class="btn-tool btn-tool-compact" @click="mainTab = 'docs'; setInstallCommandAction('install')">{{ t('cli.missing.openDocs') }}</button>
24
+ </div>
25
+ </div>
26
+ </template>
27
+ <template v-else>
8
28
  <!-- 添加提供商按钮 -->
9
29
  <button class="btn-add" @click="openClaudeConfigModal" v-if="!loading && !initError">
10
30
  <svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
@@ -135,4 +155,5 @@
135
155
  </div>
136
156
  </div>
137
157
  </div>
158
+ </template>
138
159
  </div>
@@ -5,6 +5,26 @@
5
5
  id="panel-config-provider"
6
6
  role="tabpanel"
7
7
  :aria-labelledby="'tab-config-' + configMode">
8
+ <template v-if="isCodexConfigMode && shouldShowCliInstallPlaceholder('codex')">
9
+ <div class="selector-section">
10
+ <div class="empty-state">
11
+ <div class="empty-state-title">{{ t('cli.missing.title', { name: 'Codex' }) }}</div>
12
+ <div class="empty-state-subtitle">{{ t('cli.missing.subtitle', { name: 'Codex' }) }}</div>
13
+ <div class="docs-command-row">
14
+ <div class="docs-command-box" role="group" :aria-label="t('cli.missing.commandAria', { name: 'Codex' })">
15
+ <code class="install-command">{{ getInstallCommand('codex', 'install') }}</code>
16
+ <button
17
+ type="button"
18
+ class="btn-mini docs-copy-btn"
19
+ :disabled="!getInstallCommand('codex', 'install')"
20
+ @click="copyInstallCommand(getInstallCommand('codex', 'install'))">{{ t('common.copy') }}</button>
21
+ </div>
22
+ </div>
23
+ <button type="button" class="btn-tool btn-tool-compact" @click="mainTab = 'docs'; setInstallCommandAction('install')">{{ t('cli.missing.openDocs') }}</button>
24
+ </div>
25
+ </div>
26
+ </template>
27
+ <template v-else>
8
28
  <!-- 添加提供商按钮 -->
9
29
  <button class="btn-add" @click="showAddModal = true" v-if="!loading && !initError">
10
30
  <svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
@@ -231,4 +251,5 @@
231
251
  </div>
232
252
  </div>
233
253
  </div>
254
+ </template>
234
255
  </div>