@orbit-work/ui 0.1.0 → 0.1.2-preview.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/index.cjs +13 -13
- package/dist/index.d.cts +23 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +13 -13
- package/dist/orbitwork.css +97 -22
- package/package.json +1 -1
- package/src/components/composite/ContextUsageIndicatorView/index.tsx +1 -1
- package/src/components/composite/Icons/index.tsx +24 -4
- package/src/components/composite/Markdown/MarkdownStyleSource.test.mjs +16 -1
- package/src/components/domain/desktop/DesktopLibraryAuthorizationDialog/DesktopLibraryAuthorizationDialogSource.test.mjs +22 -0
- package/src/components/domain/desktop/DesktopLibraryAuthorizationDialog/index.tsx +72 -57
- package/src/components/domain/desktop/DesktopLibraryPageView/DesktopLibraryPageView.stories.tsx +7 -0
- package/src/components/domain/desktop/DesktopLibraryPageView/index.tsx +14 -0
- package/src/components/domain/desktop/DesktopLoginView/DesktopLoginViewSource.test.mjs +8 -1
- package/src/components/domain/desktop/DesktopLoginView/index.tsx +28 -14
- package/src/components/domain/desktop/DesktopSidebarView/DesktopSidebarViewSource.test.mjs +6 -4
- package/src/components/domain/desktop/DesktopSidebarView/index.tsx +53 -14
- package/src/components/domain/desktop/DesktopSitesListView/index.tsx +2 -2
- package/src/components/primitives/Button/index.tsx +4 -1
- package/src/components/primitives/Menu/index.tsx +2 -1
- package/src/components/primitives/Select/index.tsx +103 -61
package/dist/orbitwork.css
CHANGED
|
@@ -244,6 +244,9 @@
|
|
|
244
244
|
.collapse {
|
|
245
245
|
visibility: collapse;
|
|
246
246
|
}
|
|
247
|
+
.invisible {
|
|
248
|
+
visibility: hidden;
|
|
249
|
+
}
|
|
247
250
|
.visible {
|
|
248
251
|
visibility: visible;
|
|
249
252
|
}
|
|
@@ -6178,23 +6181,30 @@
|
|
|
6178
6181
|
max-width: 100%;
|
|
6179
6182
|
margin: var(--ow-space-2, 8px) 0 var(--ow-space-3, 12px);
|
|
6180
6183
|
overflow-x: auto;
|
|
6184
|
+
overscroll-behavior-inline: contain;
|
|
6181
6185
|
border: var(--ow-border-width-thin, 1px) solid var(--ow-border);
|
|
6182
6186
|
border-radius: var(--ow-radius-card);
|
|
6183
6187
|
background: var(--ow-surface);
|
|
6184
6188
|
}
|
|
6185
6189
|
.md table {
|
|
6186
|
-
width:
|
|
6187
|
-
min-width: 100
|
|
6190
|
+
width: 100%;
|
|
6191
|
+
min-width: min(480px, 100%);
|
|
6188
6192
|
border-collapse: collapse;
|
|
6189
|
-
|
|
6193
|
+
table-layout: auto;
|
|
6194
|
+
font: 400 var(--ow-fs-ui)/1.55 var(--ow-font-sans);
|
|
6190
6195
|
}
|
|
6191
6196
|
.md th, .md td {
|
|
6197
|
+
min-width: 88px;
|
|
6198
|
+
max-width: 360px;
|
|
6192
6199
|
padding: var(--ow-space-2, 8px) var(--ow-space-3, 12px);
|
|
6193
6200
|
border-bottom: var(--ow-border-width-thin, 1px) solid var(--ow-border);
|
|
6194
6201
|
color: var(--ow-text-2);
|
|
6195
6202
|
text-align: left;
|
|
6196
6203
|
vertical-align: top;
|
|
6197
|
-
white-space:
|
|
6204
|
+
white-space: normal;
|
|
6205
|
+
overflow-wrap: anywhere;
|
|
6206
|
+
word-break: break-word;
|
|
6207
|
+
text-wrap: pretty;
|
|
6198
6208
|
}
|
|
6199
6209
|
.md tr:last-child td {
|
|
6200
6210
|
border-bottom: 0;
|
|
@@ -6203,9 +6213,11 @@
|
|
|
6203
6213
|
background: var(--ow-surface-2);
|
|
6204
6214
|
font-weight: 500;
|
|
6205
6215
|
color: var(--ow-text);
|
|
6216
|
+
text-wrap: balance;
|
|
6206
6217
|
}
|
|
6207
6218
|
.md td code, .md th code {
|
|
6208
|
-
white-space:
|
|
6219
|
+
white-space: normal;
|
|
6220
|
+
overflow-wrap: anywhere;
|
|
6209
6221
|
}
|
|
6210
6222
|
.md .al-right {
|
|
6211
6223
|
text-align: right;
|
|
@@ -6825,6 +6837,24 @@
|
|
|
6825
6837
|
border-radius: 0;
|
|
6826
6838
|
box-shadow: none;
|
|
6827
6839
|
}
|
|
6840
|
+
.auth-restore-splash {
|
|
6841
|
+
position: absolute;
|
|
6842
|
+
inset: 0;
|
|
6843
|
+
display: flex;
|
|
6844
|
+
flex-direction: column;
|
|
6845
|
+
align-items: center;
|
|
6846
|
+
justify-content: center;
|
|
6847
|
+
gap: var(--ow-space-4, 16px);
|
|
6848
|
+
-webkit-app-region: drag;
|
|
6849
|
+
}
|
|
6850
|
+
.auth-restore-splash img {
|
|
6851
|
+
opacity: 0.9;
|
|
6852
|
+
}
|
|
6853
|
+
.auth-restore-splash p {
|
|
6854
|
+
margin: 0;
|
|
6855
|
+
color: var(--ow-text-3);
|
|
6856
|
+
font-size: var(--ow-text-sm, 13px);
|
|
6857
|
+
}
|
|
6828
6858
|
.window-chrome {
|
|
6829
6859
|
position: absolute;
|
|
6830
6860
|
left: 12px;
|
|
@@ -7122,6 +7152,16 @@
|
|
|
7122
7152
|
gap: var(--ow-space-1, 4px);
|
|
7123
7153
|
padding-top: 2px;
|
|
7124
7154
|
}
|
|
7155
|
+
.owprojects-boot {
|
|
7156
|
+
flex: 1;
|
|
7157
|
+
min-height: 120px;
|
|
7158
|
+
display: flex;
|
|
7159
|
+
flex-direction: column;
|
|
7160
|
+
align-items: center;
|
|
7161
|
+
justify-content: center;
|
|
7162
|
+
gap: var(--ow-space-3, 12px);
|
|
7163
|
+
color: var(--ow-text-3);
|
|
7164
|
+
}
|
|
7125
7165
|
.owprojects::-webkit-scrollbar {
|
|
7126
7166
|
width: 0;
|
|
7127
7167
|
}
|
|
@@ -7853,20 +7893,31 @@
|
|
|
7853
7893
|
cursor: default;
|
|
7854
7894
|
opacity: 1;
|
|
7855
7895
|
}
|
|
7856
|
-
.owuser-update
|
|
7857
|
-
|
|
7896
|
+
.owuser-update-ic {
|
|
7897
|
+
position: relative;
|
|
7898
|
+
display: inline-flex;
|
|
7899
|
+
width: 14px;
|
|
7900
|
+
height: 14px;
|
|
7901
|
+
}
|
|
7902
|
+
.owuser-update-ic svg {
|
|
7903
|
+
width: 14px;
|
|
7904
|
+
height: 14px;
|
|
7858
7905
|
}
|
|
7859
7906
|
.owuser-update em {
|
|
7860
|
-
font: 400 var(--ow-fs-caption)/1 var(--ow-font-
|
|
7907
|
+
font: 400 var(--ow-fs-caption)/1 var(--ow-font-mono);
|
|
7861
7908
|
font-style: normal;
|
|
7909
|
+
font-variant-numeric: tabular-nums;
|
|
7862
7910
|
color: var(--ow-text-3);
|
|
7863
7911
|
}
|
|
7864
7912
|
.owuser-update-dot {
|
|
7913
|
+
position: absolute;
|
|
7914
|
+
top: -2px;
|
|
7915
|
+
right: -4px;
|
|
7865
7916
|
width: 5px;
|
|
7866
7917
|
height: 5px;
|
|
7867
|
-
flex: 0 0 auto;
|
|
7868
7918
|
border-radius: 50%;
|
|
7869
7919
|
background: var(--ow-accent);
|
|
7920
|
+
box-shadow: 0 0 0 1.5px var(--ow-bg);
|
|
7870
7921
|
}
|
|
7871
7922
|
.owuser-update.error .owuser-update-dot {
|
|
7872
7923
|
background: var(--ow-error);
|
|
@@ -8055,7 +8106,7 @@
|
|
|
8055
8106
|
.desktop-library-page__state strong {
|
|
8056
8107
|
color: var(--ow-error);
|
|
8057
8108
|
}
|
|
8058
|
-
.desktop-library-page__state span, .desktop-library-page__demo p {
|
|
8109
|
+
.desktop-library-page__state > span, .desktop-library-page__demo p {
|
|
8059
8110
|
margin: 0;
|
|
8060
8111
|
color: var(--ow-text-3);
|
|
8061
8112
|
font: 400 var(--ow-fs-ui)/1.6 var(--ow-font-sans);
|
|
@@ -8077,6 +8128,8 @@
|
|
|
8077
8128
|
border-bottom: var(--ow-border-width-thin, 1px) solid var(--ow-border);
|
|
8078
8129
|
}
|
|
8079
8130
|
.desktop-library-authorization-dialog [data-slot="dialog-body"] {
|
|
8131
|
+
display: flex;
|
|
8132
|
+
min-height: 0;
|
|
8080
8133
|
padding: 0;
|
|
8081
8134
|
}
|
|
8082
8135
|
.desktop-library-consent {
|
|
@@ -8088,6 +8141,13 @@
|
|
|
8088
8141
|
padding: var(--ow-space-5, 20px) var(--ow-space-6, 24px) var(--ow-space-6, 24px);
|
|
8089
8142
|
color: var(--ow-text-2);
|
|
8090
8143
|
}
|
|
8144
|
+
.desktop-library-consent--authorizing {
|
|
8145
|
+
width: 100%;
|
|
8146
|
+
height: min(680px, 72vh);
|
|
8147
|
+
min-height: 0;
|
|
8148
|
+
box-sizing: border-box;
|
|
8149
|
+
overflow: hidden;
|
|
8150
|
+
}
|
|
8091
8151
|
.desktop-library-consent__flow {
|
|
8092
8152
|
display: flex;
|
|
8093
8153
|
align-items: center;
|
|
@@ -8226,21 +8286,24 @@
|
|
|
8226
8286
|
font: 400 var(--ow-fs-body-sm)/1.5 var(--ow-font-sans);
|
|
8227
8287
|
}
|
|
8228
8288
|
.desktop-library-consent__webview {
|
|
8229
|
-
|
|
8230
|
-
width:
|
|
8231
|
-
height:
|
|
8232
|
-
|
|
8289
|
+
display: flex;
|
|
8290
|
+
min-width: 0;
|
|
8291
|
+
min-height: 360px;
|
|
8292
|
+
flex: 1;
|
|
8233
8293
|
overflow: hidden;
|
|
8234
|
-
border:
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
clip: rect(0 0 0 0);
|
|
8294
|
+
border: var(--ow-border-width-thin, 1px) solid var(--ow-border);
|
|
8295
|
+
border-radius: var(--ow-radius-lg);
|
|
8296
|
+
background: var(--ow-surface-2);
|
|
8238
8297
|
}
|
|
8239
8298
|
.desktop-library-consent__webview webview {
|
|
8240
|
-
display:
|
|
8241
|
-
width:
|
|
8242
|
-
height:
|
|
8299
|
+
display: flex;
|
|
8300
|
+
width: 100%;
|
|
8301
|
+
height: 100%;
|
|
8302
|
+
min-width: 0;
|
|
8303
|
+
min-height: 0;
|
|
8304
|
+
flex: 1;
|
|
8243
8305
|
border: 0;
|
|
8306
|
+
background: var(--ow-bg);
|
|
8244
8307
|
}
|
|
8245
8308
|
.desktop-library-consent__error {
|
|
8246
8309
|
margin: 0;
|
|
@@ -8266,6 +8329,12 @@
|
|
|
8266
8329
|
max-height: 82vh;
|
|
8267
8330
|
padding: var(--ow-space-4, 16px);
|
|
8268
8331
|
}
|
|
8332
|
+
.desktop-library-consent--authorizing {
|
|
8333
|
+
height: 74vh;
|
|
8334
|
+
}
|
|
8335
|
+
.desktop-library-consent__webview {
|
|
8336
|
+
min-height: 280px;
|
|
8337
|
+
}
|
|
8269
8338
|
.desktop-library-consent__actions {
|
|
8270
8339
|
position: sticky;
|
|
8271
8340
|
bottom: calc(var(--ow-space-2, 8px) * -1);
|
|
@@ -9482,6 +9551,12 @@
|
|
|
9482
9551
|
.history-status {
|
|
9483
9552
|
margin-bottom: 18px;
|
|
9484
9553
|
}
|
|
9554
|
+
.history-status:has([data-ow-part="spinner"]),
|
|
9555
|
+
.history-top-status:has([data-ow-part="spinner"]) {
|
|
9556
|
+
display: inline-flex;
|
|
9557
|
+
align-items: center;
|
|
9558
|
+
gap: var(--ow-space-15, 6px);
|
|
9559
|
+
}
|
|
9485
9560
|
.history-top-status.error,
|
|
9486
9561
|
.history-status.error {
|
|
9487
9562
|
border-color: var(--ow-error-tint-border);
|
|
@@ -18078,7 +18153,7 @@ img.g {
|
|
|
18078
18153
|
word-break: break-all;
|
|
18079
18154
|
}
|
|
18080
18155
|
.browser-sidebar {
|
|
18081
|
-
width: min(
|
|
18156
|
+
width: min(400px, 38vw);
|
|
18082
18157
|
max-width: calc(100% - clamp(0px, calc(100% - 300px), 400px));
|
|
18083
18158
|
flex: 0 0 auto;
|
|
18084
18159
|
display: flex;
|
package/package.json
CHANGED
|
@@ -110,7 +110,7 @@ export function ContextUsageIndicatorView(props: ContextUsageIndicatorViewProps)
|
|
|
110
110
|
<TotalRow label="总可用" value={props.totalLabel} strong />
|
|
111
111
|
{props.totalLabel === "—" && (
|
|
112
112
|
<p className="context-usage-card__unavailable">
|
|
113
|
-
{props.modelLoading ? "正在获取模型上下文上限。" : "
|
|
113
|
+
{props.modelLoading ? "正在获取模型上下文上限。" : "Platform 暂未提供此模型的上下文上限。"}
|
|
114
114
|
</p>
|
|
115
115
|
)}
|
|
116
116
|
</Card>
|
|
@@ -780,6 +780,19 @@ export const Help = (p: IconProps) => (
|
|
|
780
780
|
/>
|
|
781
781
|
</svg>
|
|
782
782
|
)
|
|
783
|
+
/** 通知铃(基形 lucide:bell)。规格:ow/components/icons/BeaconIcons 九枚以外沿用 Lucide 清单+§7 参数。 */
|
|
784
|
+
export const Bell = (p: IconProps) => (
|
|
785
|
+
<svg viewBox="0 0 24 24" fill="none" {...p}>
|
|
786
|
+
<path
|
|
787
|
+
d="M6 9a6 6 0 1 1 12 0c0 5.25 2 7.5 2 7.5H4S6 14.25 6 9"
|
|
788
|
+
stroke="currentColor"
|
|
789
|
+
strokeWidth="1.75"
|
|
790
|
+
strokeLinecap="round"
|
|
791
|
+
strokeLinejoin="round"
|
|
792
|
+
/>
|
|
793
|
+
<path d="M10.35 20.4a1.9 1.9 0 0 0 3.3 0" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" />
|
|
794
|
+
</svg>
|
|
795
|
+
)
|
|
783
796
|
/** 信标族 schedule(基形 lucide:timer;指针末端→卫星珠=.dot,弧的末端=此刻)。规格:ow/components/icons/BeaconIcons。 */
|
|
784
797
|
export const Clock = (p: IconProps) => (
|
|
785
798
|
<svg viewBox="0 0 24 24" fill="none" {...p}>
|
|
@@ -1144,12 +1157,17 @@ export const PanelFold = (p: IconProps) => (
|
|
|
1144
1157
|
)
|
|
1145
1158
|
|
|
1146
1159
|
// Product integration icons are intentionally outside the Figma 05 Icons catalog.
|
|
1160
|
+
const dingTalkPath =
|
|
1161
|
+
"M849.92 51.2H174.08c-67.8656 0-122.88 55.0144-122.88 122.88v675.84c0 67.8656 55.0144 122.88 122.88 122.88h675.84c67.8656 0 122.88-55.0144 122.88-122.88V174.08c0-67.8656-55.0144-122.88-122.88-122.88z m-97.17248 383.4112c-1.00352 4.61824-3.61472 10.84928-7.22944 19.18976l-0.50688 0.50176c-21.69856 46.01344-77.66016 136.13568-77.66016 136.13568l-0.50688-0.50176-16.57344 28.43136h79.17056L578.33472 819.2l34.16064-136.63744h-62.09024l21.69856-90.624c-17.58208 4.1216-38.28224 9.85088-62.592 18.08384 0 0-33.15712 19.18976-95.24736-37.26848 0 0-41.89696-37.2736-17.58208-46.01344 10.34752-4.1216 50.23232-8.84736 81.78176-12.95872 42.3936-5.72928 68.81792-8.84736 68.81792-8.84736s-130.90816 2.10944-161.95584-3.10784c-31.04256-4.62336-70.4256-56.97024-78.6688-102.48192 0 0-12.95872-24.81664 27.9296-12.95872 40.39168 11.8528 210.18112 46.01344 210.18112 46.01344S324.2496 365.2864 309.78048 348.70784c-14.46912-16.57856-42.99776-90.01984-39.38304-135.13216 0 0 1.50528-11.35104 12.95872-8.23808 0 0 162.55488 74.5472 273.77664 114.93376 111.8208 41.40032 208.57344 62.09536 195.61472 114.33984z"
|
|
1147
1162
|
export const DingTalk = (p: IconProps) => (
|
|
1148
1163
|
<svg viewBox="0 0 1024 1024" {...p}>
|
|
1149
|
-
<path
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1164
|
+
<path d={dingTalkPath} fill="#3296FA" />
|
|
1165
|
+
</svg>
|
|
1166
|
+
)
|
|
1167
|
+
/** 钉钉 AI 伙伴:同 DingTalk 几何,fill 换 #1677FF 作同族第二色区分(登录页双钉钉入口用)。 */
|
|
1168
|
+
export const DingTalkAi = (p: IconProps) => (
|
|
1169
|
+
<svg viewBox="0 0 1024 1024" {...p}>
|
|
1170
|
+
<path d={dingTalkPath} fill="#1677FF" />
|
|
1153
1171
|
</svg>
|
|
1154
1172
|
)
|
|
1155
1173
|
export const Feishu = (p: IconProps) => (
|
|
@@ -1272,6 +1290,7 @@ export const Icons = {
|
|
|
1272
1290
|
Archive,
|
|
1273
1291
|
Logout,
|
|
1274
1292
|
Help,
|
|
1293
|
+
Bell,
|
|
1275
1294
|
Skill,
|
|
1276
1295
|
Sparkle,
|
|
1277
1296
|
Clock,
|
|
@@ -1300,6 +1319,7 @@ export const Icons = {
|
|
|
1300
1319
|
Skills,
|
|
1301
1320
|
AlertCircle,
|
|
1302
1321
|
DingTalk,
|
|
1322
|
+
DingTalkAi,
|
|
1303
1323
|
Feishu,
|
|
1304
1324
|
WeCom,
|
|
1305
1325
|
CommentPlus,
|
|
@@ -98,7 +98,7 @@ test("markdown tables reuse the DataTable facade in one theme-agnostic block", (
|
|
|
98
98
|
)
|
|
99
99
|
assert.match(
|
|
100
100
|
styleSource,
|
|
101
|
-
/\.md th \{ background: var\(--ow-surface-2\); font-weight: 500; color: var\(--ow-text\); \}/,
|
|
101
|
+
/\.md th \{ background: var\(--ow-surface-2\); font-weight: 500; color: var\(--ow-text\); text-wrap: balance; \}/,
|
|
102
102
|
)
|
|
103
103
|
assert.doesNotMatch(styleSource, /var\(--ow-gray-00\)/)
|
|
104
104
|
assert.doesNotMatch(styleSource, /\[data-theme="dark"\] \.md/)
|
|
@@ -120,6 +120,21 @@ test("markdown tables draw row rules only — no vertical cell borders, header a
|
|
|
120
120
|
assert.doesNotMatch(styleSource, /\.md th:last-child, \.md td:last-child \{ border-right: 0; \}/)
|
|
121
121
|
})
|
|
122
122
|
|
|
123
|
+
// 可读性修复:nowrap + width:max-content 会把长内容顶成强制横滚,
|
|
124
|
+
// 改为列宽 88–360px、任意断词、容器内滚不链到页面(overscroll-behavior-inline)。
|
|
125
|
+
// 斑马纹(tbody tr:nth-child(even))上游设计新增,DS2 立面没有——不迁。
|
|
126
|
+
test("markdown tables wrap long content while preserving readable column widths", () => {
|
|
127
|
+
assert.match(styleSource, /\.md table \{[^}]*width: 100%; min-width: min\(480px, 100%\)/)
|
|
128
|
+
assert.match(styleSource, /\.md th, \.md td \{[^}]*min-width: 88px; max-width: 360px/)
|
|
129
|
+
assert.match(
|
|
130
|
+
styleSource,
|
|
131
|
+
/\.md th, \.md td \{[^}]*white-space: normal; overflow-wrap: anywhere; word-break: break-word/,
|
|
132
|
+
)
|
|
133
|
+
assert.match(styleSource, /\.md__table-wrap \{[^}]*overscroll-behavior-inline: contain/)
|
|
134
|
+
assert.match(styleSource, /\.md td code, \.md th code \{ white-space: normal; overflow-wrap: anywhere; \}/)
|
|
135
|
+
assert.doesNotMatch(styleSource, /nth-child\(even\)/)
|
|
136
|
+
})
|
|
137
|
+
|
|
123
138
|
// 列表(§8):全局 reset 会把 ol/ul 的 list-style 清成 none,.md 族必须自己补回,
|
|
124
139
|
// 否则无序列表没圆点、有序列表没序号(W0 断链)。
|
|
125
140
|
test("markdown lists restore their bullets and numbering after the global reset", () => {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import assert from "node:assert/strict"
|
|
2
|
+
import { readFile } from "node:fs/promises"
|
|
3
|
+
import test from "node:test"
|
|
4
|
+
|
|
5
|
+
const source = await readFile(new URL("./index.tsx", import.meta.url), "utf8")
|
|
6
|
+
const styles = await readFile(new URL("../../../../../styles/desktop-surfaces.css", import.meta.url), "utf8")
|
|
7
|
+
|
|
8
|
+
test("embedded authorization shows an interactive webview after consent", () => {
|
|
9
|
+
assert.ok(source.includes("width={authorizationUrl ? 920 : 520}"))
|
|
10
|
+
assert.ok(source.includes('className="desktop-library-consent__webview"'))
|
|
11
|
+
assert.ok(source.includes('role="region"'))
|
|
12
|
+
assert.ok(source.includes('authorizationUrl ? "取消授权" : "拒绝"'))
|
|
13
|
+
|
|
14
|
+
const hostRule = styles.match(/\.desktop-library-consent__webview \{([^}]*)\}/)?.[1] ?? ""
|
|
15
|
+
const webviewRule = styles.match(/\.desktop-library-consent__webview webview \{([^}]*)\}/)?.[1] ?? ""
|
|
16
|
+
assert.match(hostRule, /display: flex/)
|
|
17
|
+
assert.match(hostRule, /min-height: 360px/)
|
|
18
|
+
assert.match(hostRule, /flex: 1/)
|
|
19
|
+
assert.match(webviewRule, /width: 100%; height: 100%/)
|
|
20
|
+
assert.match(webviewRule, /flex: 1/)
|
|
21
|
+
assert.doesNotMatch(hostRule, /opacity: 0|pointer-events: none|clip:/)
|
|
22
|
+
})
|
|
@@ -56,6 +56,7 @@ export function DesktopLibraryAuthorizationDialog({
|
|
|
56
56
|
if (!host || !authorizationUrl) return
|
|
57
57
|
host.replaceChildren()
|
|
58
58
|
const webview = document.createElement("webview")
|
|
59
|
+
webview.setAttribute("aria-label", `${appName} 授权页面`)
|
|
59
60
|
webview.setAttribute("partition", "persist:library-authorization")
|
|
60
61
|
webview.setAttribute("webpreferences", "contextIsolation=yes, nodeIntegration=no, sandbox=yes")
|
|
61
62
|
webview.setAttribute("src", authorizationUrl)
|
|
@@ -63,7 +64,7 @@ export function DesktopLibraryAuthorizationDialog({
|
|
|
63
64
|
return () => {
|
|
64
65
|
webview.remove()
|
|
65
66
|
}
|
|
66
|
-
}, [authorizationUrl])
|
|
67
|
+
}, [appName, authorizationUrl])
|
|
67
68
|
|
|
68
69
|
return (
|
|
69
70
|
<Dialog
|
|
@@ -71,63 +72,75 @@ export function DesktopLibraryAuthorizationDialog({
|
|
|
71
72
|
title="授权访问"
|
|
72
73
|
subtitle={`${appName} · Orbitwork 安全授权`}
|
|
73
74
|
className="desktop-library-authorization-dialog"
|
|
74
|
-
width={520}
|
|
75
|
+
width={authorizationUrl ? 920 : 520}
|
|
75
76
|
padded={false}
|
|
76
77
|
onClose={submitting === "deny" ? undefined : onClose}
|
|
77
78
|
closable={submitting !== "deny"}
|
|
78
79
|
>
|
|
79
|
-
<div
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
{scope.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
80
|
+
<div
|
|
81
|
+
className={`desktop-library-consent${authorizationUrl ? " desktop-library-consent--authorizing" : ""}`}
|
|
82
|
+
aria-busy={loading || submitting !== null}
|
|
83
|
+
>
|
|
84
|
+
{!authorizationUrl && (
|
|
85
|
+
<>
|
|
86
|
+
<div className="desktop-library-consent__flow" aria-hidden="true">
|
|
87
|
+
<span className="desktop-library-consent__mark desktop-library-consent__mark--orbitwork">
|
|
88
|
+
<OrbitworkMark size={40} />
|
|
89
|
+
</span>
|
|
90
|
+
<span className="desktop-library-consent__arrow">→</span>
|
|
91
|
+
<span
|
|
92
|
+
className={`desktop-library-consent__mark desktop-library-consent__mark--accent${appIconSource ? " desktop-library-consent__mark--image" : ""}`}
|
|
93
|
+
>
|
|
94
|
+
{appIconSource ? (
|
|
95
|
+
<img src={appIconSource} alt="" onError={() => setAppIconFailed(true)} />
|
|
96
|
+
) : (
|
|
97
|
+
initial(appName)
|
|
98
|
+
)}
|
|
99
|
+
</span>
|
|
100
|
+
</div>
|
|
101
|
+
<h2>
|
|
102
|
+
<strong>{appName}</strong> 请求访问你的账号
|
|
103
|
+
</h2>
|
|
104
|
+
<p className="desktop-library-consent__description">{appDescription}</p>
|
|
105
|
+
<div className="desktop-library-consent__facts">
|
|
106
|
+
<span>
|
|
107
|
+
<Lock aria-hidden="true" /> 使用 Orbitwork 账号凭证
|
|
108
|
+
</span>
|
|
109
|
+
<span>
|
|
110
|
+
<Shield aria-hidden="true" /> 仅在资料库请求中生效
|
|
111
|
+
</span>
|
|
112
|
+
</div>
|
|
113
|
+
<section className="desktop-library-consent__scopes" aria-labelledby="desktop-library-consent-scopes">
|
|
114
|
+
<h3 id="desktop-library-consent-scopes">将授予以下权限</h3>
|
|
115
|
+
{loading ? (
|
|
116
|
+
<p className="desktop-library-consent__loading">正在检查登录状态…</p>
|
|
117
|
+
) : scopes.length > 0 ? (
|
|
118
|
+
<ul>
|
|
119
|
+
{scopes.map((scope) => (
|
|
120
|
+
<li key={`${scope.owner ?? ""}:${scope.title}`}>
|
|
121
|
+
<CheckCircle aria-hidden="true" />
|
|
122
|
+
<span>
|
|
123
|
+
<strong>{scope.title}</strong>
|
|
124
|
+
{scope.owner && <small>{scope.owner}</small>}
|
|
125
|
+
{scope.description && <em>{scope.description}</em>}
|
|
126
|
+
</span>
|
|
127
|
+
{scope.required && <b>必需</b>}
|
|
128
|
+
</li>
|
|
129
|
+
))}
|
|
130
|
+
</ul>
|
|
131
|
+
) : (
|
|
132
|
+
<p className="desktop-library-consent__loading">访问资料库内容</p>
|
|
133
|
+
)}
|
|
134
|
+
</section>
|
|
135
|
+
</>
|
|
136
|
+
)}
|
|
129
137
|
{authorizationUrl && (
|
|
130
|
-
<div
|
|
138
|
+
<div
|
|
139
|
+
ref={webviewHostRef}
|
|
140
|
+
className="desktop-library-consent__webview"
|
|
141
|
+
role="region"
|
|
142
|
+
aria-label={`${appName} 授权页面`}
|
|
143
|
+
/>
|
|
131
144
|
)}
|
|
132
145
|
{error && (
|
|
133
146
|
<p className="desktop-library-consent__error" role="alert">
|
|
@@ -139,11 +152,13 @@ export function DesktopLibraryAuthorizationDialog({
|
|
|
139
152
|
</p>
|
|
140
153
|
<div className="desktop-library-consent__actions">
|
|
141
154
|
<Button variant="ghost" disabled={submitting === "deny"} onClick={onDeny}>
|
|
142
|
-
{submitting === "deny" ? "处理中…" : "拒绝"}
|
|
143
|
-
</Button>
|
|
144
|
-
<Button variant="primary" disabled={loading || submitting !== null} onClick={onApprove}>
|
|
145
|
-
{submitting === "approve" ? "授权中…" : "同意授权"}
|
|
155
|
+
{submitting === "deny" ? "处理中…" : authorizationUrl ? "取消授权" : "拒绝"}
|
|
146
156
|
</Button>
|
|
157
|
+
{!authorizationUrl && (
|
|
158
|
+
<Button variant="primary" disabled={loading || submitting !== null} onClick={onApprove}>
|
|
159
|
+
{submitting === "approve" ? "授权中…" : "同意授权"}
|
|
160
|
+
</Button>
|
|
161
|
+
)}
|
|
147
162
|
</div>
|
|
148
163
|
</div>
|
|
149
164
|
</Dialog>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import type { Ref } from "react"
|
|
4
|
+
import { Button } from "../../../primitives"
|
|
4
5
|
|
|
5
6
|
export interface DesktopLibraryPageViewProps {
|
|
6
7
|
loading?: boolean
|
|
7
8
|
error?: string | null
|
|
9
|
+
authorizationRequired?: boolean
|
|
10
|
+
onRequestAuthorization?: () => void
|
|
8
11
|
webviewHostRef?: Ref<HTMLDivElement>
|
|
9
12
|
}
|
|
10
13
|
|
|
@@ -12,6 +15,8 @@ export interface DesktopLibraryPageViewProps {
|
|
|
12
15
|
export function DesktopLibraryPageView({
|
|
13
16
|
loading = false,
|
|
14
17
|
error = null,
|
|
18
|
+
authorizationRequired = false,
|
|
19
|
+
onRequestAuthorization,
|
|
15
20
|
webviewHostRef,
|
|
16
21
|
}: DesktopLibraryPageViewProps): React.ReactElement {
|
|
17
22
|
return (
|
|
@@ -22,6 +27,15 @@ export function DesktopLibraryPageView({
|
|
|
22
27
|
<strong>资料库页面加载失败</strong>
|
|
23
28
|
<span>{error}</span>
|
|
24
29
|
</div>
|
|
30
|
+
) : authorizationRequired ? (
|
|
31
|
+
<div className="desktop-library-page__state" role="status">
|
|
32
|
+
<span>需要授权后才能访问资料库。</span>
|
|
33
|
+
{onRequestAuthorization && (
|
|
34
|
+
<Button variant="primary" onClick={onRequestAuthorization}>
|
|
35
|
+
立即授权
|
|
36
|
+
</Button>
|
|
37
|
+
)}
|
|
38
|
+
</div>
|
|
25
39
|
) : webviewHostRef ? (
|
|
26
40
|
<div ref={webviewHostRef} className="desktop-library-page__webview-host" aria-busy={loading} />
|
|
27
41
|
) : (
|
|
@@ -115,7 +115,7 @@ test("登录段控件补齐 §6 状态:focus-visible 到位,禁用不用统
|
|
|
115
115
|
test("§7 图标:手搓件退役,归口 composite/Icons;QR 面渲染主进程编码的真图", () => {
|
|
116
116
|
assert.match(
|
|
117
117
|
source,
|
|
118
|
-
/import
|
|
118
|
+
/import { ChevLeft, DingTalk, DingTalkAi, Feishu, Globe, WeCom } from "\.\.\/\.\.\/\.\.\/composite\/Icons"/,
|
|
119
119
|
)
|
|
120
120
|
assert.doesNotMatch(source, /function (?:BackIcon|CheckIcon)\(/)
|
|
121
121
|
assert.doesNotMatch(source, /<Check \/>/)
|
|
@@ -131,6 +131,13 @@ test("§7 图标:手搓件退役,归口 composite/Icons;QR 面渲染主进
|
|
|
131
131
|
assert.match(source, /case "IDENTITY_PROVIDER_KIND_FEISHU": return Feishu/)
|
|
132
132
|
assert.match(source, /case "IDENTITY_PROVIDER_KIND_WECOM": return WeCom/)
|
|
133
133
|
assert.match(source, /default: return Globe/)
|
|
134
|
+
// 「钉钉 AI 伙伴」临时按 displayName 精确匹配出同族蓝色标(kind 契约无独立枚举、
|
|
135
|
+
// 连接 id 为随机 UUID);proto 加 DINGTALK_AI 后此处应翻成 kind 分派断言。
|
|
136
|
+
assert.match(
|
|
137
|
+
source,
|
|
138
|
+
/provider\.kind === "IDENTITY_PROVIDER_KIND_DINGTALK" && provider\.displayName === "钉钉(AI伙伴)"[\s\S]*return DingTalkAi/,
|
|
139
|
+
)
|
|
140
|
+
assert.match(source, /TODO\(kind-dingtalk-ai\)/)
|
|
134
141
|
// 未知 kind 的通用入口:Globe 标+displayName 文本,不再隐藏连接。
|
|
135
142
|
assert.match(source, /login-provider--generic/)
|
|
136
143
|
assert.match(source, /Icon === Globe \? <span>\{provider\.displayName\}<\/span>/)
|