@shendeguize/dsh-agent-sidecar 0.1.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/LICENSE +21 -0
- package/README.md +167 -0
- package/cordis.patch.yml +10 -0
- package/lib/client.js +8062 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +396 -0
- package/lib/index.js +4166 -0
- package/package.json +101 -0
- package/src/analysis.ts +782 -0
- package/src/bridge.ts +841 -0
- package/src/client/analysis/AnalysisPanel.tsx +191 -0
- package/src/client/analysis/analysis.module.css +183 -0
- package/src/client/analysis-glue.ts +331 -0
- package/src/client/api.ts +380 -0
- package/src/client/board/Board.tsx +214 -0
- package/src/client/board/board.module.css +302 -0
- package/src/client/board/logic.ts +556 -0
- package/src/client/board/project-view-logic.ts +361 -0
- package/src/client/board/project-view.module.css +307 -0
- package/src/client/board/project-view.tsx +189 -0
- package/src/client/board/strings.ts +112 -0
- package/src/client/commands.ts +484 -0
- package/src/client/controller.ts +360 -0
- package/src/client/css-modules.d.ts +11 -0
- package/src/client/detail/SessionDetail.tsx +270 -0
- package/src/client/detail/detail.module.css +433 -0
- package/src/client/detail/logic.ts +779 -0
- package/src/client/detail/strings.ts +98 -0
- package/src/client/detail/transport.ts +175 -0
- package/src/client/detail-glue.ts +397 -0
- package/src/client/detail-view.module.css +79 -0
- package/src/client/detail-view.tsx +233 -0
- package/src/client/dsh-tools/LineageTree.tsx +210 -0
- package/src/client/dsh-tools/SearchPanel.tsx +169 -0
- package/src/client/dsh-tools/dsh-tools.module.css +374 -0
- package/src/client/dsh-tools/logic.ts +596 -0
- package/src/client/dsh-tools/strings.ts +90 -0
- package/src/client/index.ts +315 -0
- package/src/client/inject/InjectPanel.tsx +482 -0
- package/src/client/inject/inject.module.css +446 -0
- package/src/client/inject/logic.ts +516 -0
- package/src/client/inject/overlay.module.css +22 -0
- package/src/client/inject-glue.ts +171 -0
- package/src/client/locales/command.ts +48 -0
- package/src/client/locales/en.ts +385 -0
- package/src/client/locales/index.ts +123 -0
- package/src/client/locales/zh.ts +402 -0
- package/src/client/m3-transport.ts +151 -0
- package/src/client/mount.tsx +307 -0
- package/src/client/project-glue.ts +134 -0
- package/src/client/search-glue.ts +143 -0
- package/src/client/settings-card.module.css +359 -0
- package/src/client/settings-card.tsx +565 -0
- package/src/client/settings-glue.ts +130 -0
- package/src/client/sidebar-tab.tsx +494 -0
- package/src/client/sse.ts +366 -0
- package/src/client/widget.tsx +80 -0
- package/src/config.ts +193 -0
- package/src/dsh-inject.ts +240 -0
- package/src/fusion.ts +988 -0
- package/src/guard.ts +274 -0
- package/src/index.ts +950 -0
- package/src/inject-gateway.ts +574 -0
- package/src/routes.ts +1133 -0
- package/src/send-cli.ts +340 -0
- package/src/session-store.ts +184 -0
- package/src/skills-provider.ts +293 -0
- package/src/supervisor.ts +463 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-agent search data glue (T5.10b): a framework-free store feeding
|
|
3
|
+
* the controlled SearchPanel. Normalization (matchedBy vocabulary, snippet
|
|
4
|
+
* highlighting) stays in dsh-tools/logic.ts — this store owns the query
|
|
5
|
+
* box state and transport orchestration only.
|
|
6
|
+
*
|
|
7
|
+
* Submit model: explicit user submit (no as-you-type dialing). A blank
|
|
8
|
+
* query with no project filter clears the results locally — the host
|
|
9
|
+
* answers 400 `invalid_request` for it, so the store never dials that.
|
|
10
|
+
* Stale results are replaced per settle; a failed submit keeps the last
|
|
11
|
+
* results visible with an error banner (SearchPanel renders error-first).
|
|
12
|
+
*
|
|
13
|
+
* Same store discipline as controller.ts: subscribe/getState for
|
|
14
|
+
* `useSyncExternalStore`, immutable snapshots, dispose() = late no-ops.
|
|
15
|
+
* Out-of-order settles are ignored via a submit ticket.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { isApiError, type RequestOptions } from './api.ts'
|
|
21
|
+
import { fetchSearch } from './m3-transport.ts'
|
|
22
|
+
import {
|
|
23
|
+
normalizeSearchItems,
|
|
24
|
+
type SearchItemVM,
|
|
25
|
+
type SearchMode,
|
|
26
|
+
type SearchResponseVM,
|
|
27
|
+
} from './dsh-tools/logic.ts'
|
|
28
|
+
|
|
29
|
+
export interface SearchGlueState {
|
|
30
|
+
/** Controlled query box value. */
|
|
31
|
+
query: string
|
|
32
|
+
/** Query echoed by the last settled response ('' before the first). */
|
|
33
|
+
submittedQuery: string
|
|
34
|
+
/** Mode of the last settled response; 'full-text' until told otherwise. */
|
|
35
|
+
mode: SearchMode
|
|
36
|
+
items: SearchItemVM[]
|
|
37
|
+
loading: boolean
|
|
38
|
+
/** Machine reason code of the last failure, or null. */
|
|
39
|
+
error: string | null
|
|
40
|
+
/** Active project filter sent with submits and echoed back, if any. */
|
|
41
|
+
project: string | null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface SearchStoreOptions {
|
|
45
|
+
fetchSearchFn?: (
|
|
46
|
+
opts?: RequestOptions & { q?: string; project?: string | null; limit?: number },
|
|
47
|
+
) => Promise<SearchResponseVM>
|
|
48
|
+
/** Result cap passed to the endpoint (server default if unset). */
|
|
49
|
+
limit?: number
|
|
50
|
+
/** Fixed project filter (e.g. a search scoped from the project view). */
|
|
51
|
+
project?: string | null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const INITIAL_STATE: SearchGlueState = {
|
|
55
|
+
query: '',
|
|
56
|
+
submittedQuery: '',
|
|
57
|
+
mode: 'full-text',
|
|
58
|
+
items: [],
|
|
59
|
+
loading: false,
|
|
60
|
+
error: null,
|
|
61
|
+
project: null,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class SearchStore {
|
|
65
|
+
private state: SearchGlueState
|
|
66
|
+
private readonly listeners = new Set<() => void>()
|
|
67
|
+
private readonly fetchSearchFn: NonNullable<SearchStoreOptions['fetchSearchFn']>
|
|
68
|
+
private readonly limit: number | undefined
|
|
69
|
+
private disposed = false
|
|
70
|
+
private ticket = 0
|
|
71
|
+
|
|
72
|
+
constructor(options: SearchStoreOptions = {}) {
|
|
73
|
+
this.fetchSearchFn = options.fetchSearchFn ?? fetchSearch
|
|
74
|
+
this.limit = options.limit
|
|
75
|
+
this.state = { ...INITIAL_STATE, project: options.project ?? null }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
subscribe = (fn: () => void): (() => void) => {
|
|
79
|
+
this.listeners.add(fn)
|
|
80
|
+
return () => { this.listeners.delete(fn) }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getState = (): SearchGlueState => this.state
|
|
84
|
+
|
|
85
|
+
private setState(patch: Partial<SearchGlueState>): void {
|
|
86
|
+
if (this.disposed) return
|
|
87
|
+
this.state = { ...this.state, ...patch }
|
|
88
|
+
for (const fn of [...this.listeners]) fn()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Controlled input change (no dialing). */
|
|
92
|
+
setQuery(query: string): void {
|
|
93
|
+
this.setState({ query })
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Submit the current query; blank + no project filter clears locally. */
|
|
97
|
+
async submit(): Promise<void> {
|
|
98
|
+
if (this.disposed) return
|
|
99
|
+
const q = this.state.query.trim()
|
|
100
|
+
const project = this.state.project
|
|
101
|
+
if (q === '' && (project === null || project.trim() === '')) {
|
|
102
|
+
this.ticket += 1 // outrun any in-flight settle
|
|
103
|
+
this.setState({
|
|
104
|
+
items: [], submittedQuery: '', loading: false, error: null,
|
|
105
|
+
})
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
const ticket = (this.ticket += 1)
|
|
109
|
+
this.setState({ loading: true, error: null })
|
|
110
|
+
try {
|
|
111
|
+
const response = await this.fetchSearchFn({
|
|
112
|
+
q,
|
|
113
|
+
project,
|
|
114
|
+
...(this.limit !== undefined ? { limit: this.limit } : {}),
|
|
115
|
+
})
|
|
116
|
+
if (this.disposed || ticket !== this.ticket) return
|
|
117
|
+
this.adoptResponse(response)
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (this.disposed || ticket !== this.ticket) return
|
|
120
|
+
this.setState({
|
|
121
|
+
loading: false,
|
|
122
|
+
error: isApiError(err) ? err.reason : 'network_error',
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Apply one settled wire response (public seam for tests/materialize). */
|
|
128
|
+
adoptResponse(response: SearchResponseVM): void {
|
|
129
|
+
this.setState({
|
|
130
|
+
items: normalizeSearchItems(response),
|
|
131
|
+
mode: response.mode,
|
|
132
|
+
submittedQuery: response.query,
|
|
133
|
+
project: response.project,
|
|
134
|
+
loading: false,
|
|
135
|
+
error: null,
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
dispose(): void {
|
|
140
|
+
this.disposed = true
|
|
141
|
+
this.listeners.clear()
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/* Agent Sidecar settings card. Design language follows the shipped
|
|
2
|
+
* ui-settings-plugins PluginCard/fields chrome (disclosure header over a
|
|
3
|
+
* sectioned form body); every color rides a dsh --dsw-alias-* design token,
|
|
4
|
+
* no literal colors. */
|
|
5
|
+
|
|
6
|
+
.card {
|
|
7
|
+
list-style: none;
|
|
8
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
9
|
+
border-radius: 12px;
|
|
10
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
11
|
+
transition: border-color .16s, background .16s;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.card:hover {
|
|
15
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.cardOpen {
|
|
19
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
20
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* ── disclosure header ─────────────────────────────────────────────────── */
|
|
24
|
+
|
|
25
|
+
.header {
|
|
26
|
+
width: 100%;
|
|
27
|
+
appearance: none;
|
|
28
|
+
border: 0;
|
|
29
|
+
background: none;
|
|
30
|
+
font: inherit;
|
|
31
|
+
color: inherit;
|
|
32
|
+
text-align: left;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: 12px;
|
|
37
|
+
padding: 14px 16px;
|
|
38
|
+
border-radius: 12px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.header:focus-visible {
|
|
42
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
43
|
+
outline-offset: -2px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.headText {
|
|
47
|
+
flex: 1;
|
|
48
|
+
min-width: 0;
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
gap: 4px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.name {
|
|
55
|
+
font-size: 15px;
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
line-height: 1.4;
|
|
58
|
+
color: var(--dsw-alias-label-primary);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.description {
|
|
62
|
+
font-size: 13px;
|
|
63
|
+
line-height: 1.5;
|
|
64
|
+
color: var(--dsw-alias-label-tertiary);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Carried on the header so a collapsed card still says it holds edits. */
|
|
68
|
+
.pending {
|
|
69
|
+
flex: none;
|
|
70
|
+
border-radius: 999px;
|
|
71
|
+
padding: 1px 8px;
|
|
72
|
+
font-size: 11px;
|
|
73
|
+
line-height: 17px;
|
|
74
|
+
font-weight: 500;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
background: var(--dsw-alias-bg-module-platform);
|
|
77
|
+
color: var(--dsw-alias-label-secondary);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* CSS-drawn caret (ui-primitives icons are not on this package's dependency
|
|
81
|
+
* surface, so the chevron is a rotated border square). */
|
|
82
|
+
.chevron {
|
|
83
|
+
flex: none;
|
|
84
|
+
width: 8px;
|
|
85
|
+
height: 8px;
|
|
86
|
+
border-right: 1.5px solid var(--dsw-alias-label-tertiary);
|
|
87
|
+
border-bottom: 1.5px solid var(--dsw-alias-label-tertiary);
|
|
88
|
+
transform: rotate(45deg) translateY(-2px);
|
|
89
|
+
transition: transform .16s;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.chevronOpen {
|
|
93
|
+
transform: rotate(225deg) translateY(-2px);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* ── body ──────────────────────────────────────────────────────────────── */
|
|
97
|
+
|
|
98
|
+
.body {
|
|
99
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
100
|
+
margin: 0 16px;
|
|
101
|
+
padding-bottom: 8px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.readOnly {
|
|
105
|
+
margin: 12px 0 0;
|
|
106
|
+
font-size: 12px;
|
|
107
|
+
line-height: 1.5;
|
|
108
|
+
color: var(--dsw-alias-label-tertiary);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.section {
|
|
112
|
+
padding: 12px 0 4px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.section + .section {
|
|
116
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.sectionTitle {
|
|
120
|
+
margin: 0 0 4px;
|
|
121
|
+
font-size: 13px;
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
line-height: 1.5;
|
|
124
|
+
color: var(--dsw-alias-label-primary);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* ── fields ────────────────────────────────────────────────────────────── */
|
|
128
|
+
|
|
129
|
+
.field {
|
|
130
|
+
padding: 8px 0;
|
|
131
|
+
display: flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
gap: 6px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.label {
|
|
137
|
+
font-size: 13px;
|
|
138
|
+
line-height: 1.5;
|
|
139
|
+
color: var(--dsw-alias-label-primary);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.hint {
|
|
143
|
+
margin: 0;
|
|
144
|
+
font-size: 12px;
|
|
145
|
+
line-height: 1.5;
|
|
146
|
+
color: var(--dsw-alias-label-tertiary);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.invalidHint {
|
|
150
|
+
margin: 0;
|
|
151
|
+
font-size: 12px;
|
|
152
|
+
line-height: 1.5;
|
|
153
|
+
color: var(--dsw-alias-label-error);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.input,
|
|
157
|
+
.select {
|
|
158
|
+
appearance: none;
|
|
159
|
+
max-width: 420px;
|
|
160
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
161
|
+
border-radius: 8px;
|
|
162
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
163
|
+
padding: 6px 10px;
|
|
164
|
+
font: inherit;
|
|
165
|
+
font-size: 13px;
|
|
166
|
+
line-height: 1.5;
|
|
167
|
+
color: var(--dsw-alias-label-primary);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.input:focus-visible,
|
|
171
|
+
.select:focus-visible {
|
|
172
|
+
outline: none;
|
|
173
|
+
border-color: var(--dsw-alias-brand-primary);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.input::placeholder {
|
|
177
|
+
color: var(--dsw-alias-label-tertiary);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.input:disabled,
|
|
181
|
+
.select:disabled {
|
|
182
|
+
opacity: 0.5;
|
|
183
|
+
cursor: default;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* Modifier applied ALONGSIDE .input (no `composes`: the tsdown class-map
|
|
187
|
+
* emitter keeps only the local hashed name and would drop composed bases). */
|
|
188
|
+
.inputInvalid {
|
|
189
|
+
border-color: var(--dsw-alias-label-error);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Toggle row: label text left, native checkbox right-aligned with it. */
|
|
193
|
+
.toggleRow {
|
|
194
|
+
display: flex;
|
|
195
|
+
align-items: center;
|
|
196
|
+
gap: 10px;
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.toggleRow input {
|
|
201
|
+
accent-color: var(--dsw-alias-brand-primary);
|
|
202
|
+
width: 16px;
|
|
203
|
+
height: 16px;
|
|
204
|
+
margin: 0;
|
|
205
|
+
cursor: pointer;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.toggleRow input:disabled {
|
|
209
|
+
cursor: default;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* ── notes (safety / daemon guidance) ──────────────────────────────────── */
|
|
213
|
+
|
|
214
|
+
.note {
|
|
215
|
+
margin: 6px 0 2px;
|
|
216
|
+
border-radius: 8px;
|
|
217
|
+
padding: 8px 10px;
|
|
218
|
+
font-size: 12px;
|
|
219
|
+
line-height: 1.6;
|
|
220
|
+
background: var(--dsw-alias-bg-module-platform);
|
|
221
|
+
color: var(--dsw-alias-label-secondary);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* ── daemon status row ─────────────────────────────────────────────────── */
|
|
225
|
+
|
|
226
|
+
.statusRow {
|
|
227
|
+
display: flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
gap: 8px;
|
|
230
|
+
padding: 4px 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.statusDot {
|
|
234
|
+
flex: none;
|
|
235
|
+
width: 8px;
|
|
236
|
+
height: 8px;
|
|
237
|
+
border-radius: 50%;
|
|
238
|
+
background: var(--dsw-alias-label-tertiary);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* Modifiers applied alongside .statusDot (same no-`composes` rationale). */
|
|
242
|
+
.statusOk {
|
|
243
|
+
background: var(--dsw-alias-brand-primary);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.statusError {
|
|
247
|
+
background: var(--dsw-alias-label-error);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.statusText {
|
|
251
|
+
font-size: 13px;
|
|
252
|
+
line-height: 1.5;
|
|
253
|
+
color: var(--dsw-alias-label-primary);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.statusMeta {
|
|
257
|
+
font-size: 12px;
|
|
258
|
+
line-height: 1.5;
|
|
259
|
+
color: var(--dsw-alias-label-tertiary);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.retry {
|
|
263
|
+
appearance: none;
|
|
264
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
265
|
+
border-radius: 8px;
|
|
266
|
+
background: none;
|
|
267
|
+
padding: 3px 12px;
|
|
268
|
+
font: inherit;
|
|
269
|
+
font-size: 12px;
|
|
270
|
+
line-height: 1.5;
|
|
271
|
+
color: var(--dsw-alias-label-secondary);
|
|
272
|
+
cursor: pointer;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.retry:hover:not(:disabled) {
|
|
276
|
+
color: var(--dsw-alias-label-primary);
|
|
277
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.retry:focus-visible {
|
|
281
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
282
|
+
outline-offset: 1px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* ── footer ────────────────────────────────────────────────────────────── */
|
|
286
|
+
|
|
287
|
+
.footer {
|
|
288
|
+
display: flex;
|
|
289
|
+
align-items: center;
|
|
290
|
+
gap: 8px;
|
|
291
|
+
padding: 12px 0 4px;
|
|
292
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.docs {
|
|
296
|
+
font-size: 12px;
|
|
297
|
+
line-height: 1.5;
|
|
298
|
+
color: var(--dsw-alias-label-tertiary);
|
|
299
|
+
text-decoration: none;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.docs:hover {
|
|
303
|
+
color: var(--dsw-alias-label-primary);
|
|
304
|
+
text-decoration: underline;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.failed {
|
|
308
|
+
flex: 1;
|
|
309
|
+
min-width: 0;
|
|
310
|
+
margin: 0;
|
|
311
|
+
text-align: right;
|
|
312
|
+
font-size: 12px;
|
|
313
|
+
line-height: 1.5;
|
|
314
|
+
color: var(--dsw-alias-label-error);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.spacer {
|
|
318
|
+
flex: 1;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.discard,
|
|
322
|
+
.save {
|
|
323
|
+
appearance: none;
|
|
324
|
+
border: 1px solid transparent;
|
|
325
|
+
border-radius: 8px;
|
|
326
|
+
padding: 5px 14px;
|
|
327
|
+
font: inherit;
|
|
328
|
+
font-size: 13px;
|
|
329
|
+
line-height: 1.5;
|
|
330
|
+
cursor: pointer;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.discard {
|
|
334
|
+
border-color: var(--dsw-alias-border-l2);
|
|
335
|
+
background: none;
|
|
336
|
+
color: var(--dsw-alias-label-secondary);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.discard:hover:not(:disabled) {
|
|
340
|
+
color: var(--dsw-alias-label-primary);
|
|
341
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.save {
|
|
345
|
+
background: var(--dsw-alias-label-primary);
|
|
346
|
+
color: var(--dsw-alias-bg-layer-3);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.discard:disabled,
|
|
350
|
+
.save:disabled {
|
|
351
|
+
opacity: 0.4;
|
|
352
|
+
cursor: default;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.discard:focus-visible,
|
|
356
|
+
.save:focus-visible {
|
|
357
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
358
|
+
outline-offset: 1px;
|
|
359
|
+
}
|