openxiangda 1.0.39 → 1.0.40

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.
Files changed (52) hide show
  1. package/README.md +2 -2
  2. package/openxiangda-skills/SKILL.md +6 -3
  3. package/openxiangda-skills/references/best-practices.md +29 -5
  4. package/openxiangda-skills/references/component-guide.md +79 -45
  5. package/openxiangda-skills/references/forms/component-registry.md +33 -1
  6. package/openxiangda-skills/skills/openxiangda-core/SKILL.md +2 -2
  7. package/openxiangda-skills/skills/openxiangda-form/SKILL.md +9 -2
  8. package/openxiangda-skills/skills/openxiangda-page/SKILL.md +5 -3
  9. package/package.json +1 -1
  10. package/packages/sdk/dist/runtime/index.cjs +546 -0
  11. package/packages/sdk/dist/runtime/index.cjs.map +1 -1
  12. package/packages/sdk/dist/runtime/index.mjs +546 -0
  13. package/packages/sdk/dist/runtime/index.mjs.map +1 -1
  14. package/packages/sdk/src/build-source/scripts/build-forms.mjs +5 -1
  15. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-form.mdc +4 -0
  16. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-page.mdc +2 -0
  17. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda.mdc +3 -0
  18. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-form.md +4 -0
  19. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-page.md +2 -0
  20. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda.md +3 -0
  21. package/templates/sy-lowcode-app-workspace/AGENTS.md +5 -0
  22. package/templates/sy-lowcode-app-workspace/examples/best-practices/README.md +8 -0
  23. package/templates/sy-lowcode-app-workspace/examples/best-practices/catalog.json +32 -0
  24. package/templates/sy-lowcode-app-workspace/examples/best-practices/decision-guide.md +20 -0
  25. package/templates/sy-lowcode-app-workspace/examples/best-practices/design-style.md +48 -0
  26. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/App.tsx +8 -0
  27. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/GlassHomeDashboard.tsx +232 -0
  28. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/index.tsx +10 -0
  29. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/page.config.ts +14 -0
  30. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/styles.css +196 -0
  31. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/App.tsx +8 -0
  32. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/MintAnalyticsDashboard.tsx +279 -0
  33. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/index.tsx +10 -0
  34. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/page.config.ts +14 -0
  35. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/styles.css +163 -0
  36. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/App.tsx +8 -0
  37. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/OpsMonitorDashboard.tsx +306 -0
  38. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/index.tsx +10 -0
  39. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/page.config.ts +14 -0
  40. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/styles.css +248 -0
  41. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/App.tsx +8 -0
  42. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/WorkOrderListDrawerPage.tsx +371 -0
  43. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/index.tsx +10 -0
  44. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/page.config.ts +14 -0
  45. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/styles.css +182 -0
  46. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/DashboardPrimitives.tsx +832 -0
  47. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/chartOptions.ts +140 -0
  48. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/sampleData.ts +466 -0
  49. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/styles.css +874 -0
  50. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/types.ts +150 -0
  51. package/templates/sy-lowcode-app-workspace/src/forms/README.md +4 -0
  52. package/templates/sy-lowcode-app-workspace/src/main.tsx +4 -0
@@ -0,0 +1,306 @@
1
+ import { App as AntdApp, Button, DatePicker, Select, Space, Tag } from "antd";
2
+ import { useMemo, useState } from "react";
3
+
4
+ import { QueryState } from "@/shared/components/QueryState";
5
+ import {
6
+ ActivityList,
7
+ AdminShell,
8
+ AdminTopbar,
9
+ DashboardChart,
10
+ HealthScore,
11
+ MetricCard,
12
+ Panel,
13
+ QuickActionGrid,
14
+ TaskProgressList,
15
+ TemplateActionDrawer,
16
+ } from "@/shared/components/admin-ui-templates/DashboardPrimitives";
17
+ import {
18
+ createDonutOption,
19
+ createLineAreaOption,
20
+ } from "@/shared/components/admin-ui-templates/chartOptions";
21
+ import {
22
+ activities,
23
+ monitorNavItems,
24
+ opsMetrics,
25
+ quickActions,
26
+ taskProgressItems,
27
+ } from "@/shared/components/admin-ui-templates/sampleData";
28
+ import type {
29
+ DrawerMode,
30
+ QuickAction,
31
+ } from "@/shared/components/admin-ui-templates/types";
32
+
33
+ type ViewState = "ready" | "loading" | "empty" | "error";
34
+ type TrafficMode = "realtime" | "7" | "30";
35
+
36
+ const hourLabels = [
37
+ "00:00",
38
+ "02:00",
39
+ "04:00",
40
+ "06:00",
41
+ "08:00",
42
+ "10:00",
43
+ "12:00",
44
+ "14:00",
45
+ "16:00",
46
+ "18:00",
47
+ "20:00",
48
+ "22:00",
49
+ "24:00",
50
+ ];
51
+
52
+ const alerts = [
53
+ ["数据库响应超时", "严重", "未处理", "10秒前", "red"],
54
+ ["API接口调用失败率高", "警告", "未处理", "2分钟前", "orange"],
55
+ ["存储空间使用率超过85%", "警告", "处理中", "5分钟前", "orange"],
56
+ ["用户登录异常检测", "提示", "已处理", "15分钟前", "blue"],
57
+ ["计划任务执行延迟", "提示", "已处理", "30分钟前", "blue"],
58
+ ] as const;
59
+
60
+ export function OpsMonitorDashboard() {
61
+ const { message } = AntdApp.useApp();
62
+ const [activeNav, setActiveNav] = useState("monitor");
63
+ const [trafficMode, setTrafficMode] = useState<TrafficMode>("realtime");
64
+ const [viewState, setViewState] = useState<ViewState>("ready");
65
+ const [drawerAction, setDrawerAction] = useState<QuickAction | null>(null);
66
+ const [drawerMode, setDrawerMode] = useState<DrawerMode>("create");
67
+
68
+ const trafficOption = useMemo(
69
+ () =>
70
+ createLineAreaOption({
71
+ colors: ["#4f46e5", "#14b8a6"],
72
+ labels: hourLabels,
73
+ primaryName: "访问量",
74
+ secondaryName: "独立访客",
75
+ primary:
76
+ trafficMode === "realtime"
77
+ ? [3400, 7600, 8400, 10100, 12000, 10600, 11300, 9846, 7200, 11600, 6500, 5900, 8600]
78
+ : [6200, 7000, 7600, 8300, 9100, 9600, 10200, 11000, 10400, 11200, 11800, 12100, 12600],
79
+ secondary:
80
+ trafficMode === "realtime"
81
+ ? [2200, 4200, 4800, 6200, 7200, 6600, 6900, 5800, 4300, 6500, 3900, 3500, 5200]
82
+ : [3800, 4400, 4800, 5300, 6000, 6300, 6800, 7200, 7000, 7400, 7800, 8100, 8400],
83
+ }),
84
+ [trafficMode],
85
+ );
86
+
87
+ const deviceOption = useMemo(
88
+ () =>
89
+ createDonutOption({
90
+ centerLabel: "总设备数",
91
+ centerValue: "1,268",
92
+ data: [
93
+ { name: "在线设备 78.2%", value: 78.2, color: "#3b82f6" },
94
+ { name: "离线设备 14.4%", value: 14.4, color: "#8b5cf6" },
95
+ { name: "告警设备 4.6%", value: 4.6, color: "#f59e0b" },
96
+ { name: "维护设备 2.8%", value: 2.8, color: "#ef4444" },
97
+ ],
98
+ }),
99
+ [],
100
+ );
101
+
102
+ function refresh() {
103
+ setViewState("loading");
104
+ window.setTimeout(() => {
105
+ setViewState("ready");
106
+ message.success("监控数据已刷新");
107
+ }, 500);
108
+ }
109
+
110
+ function openActionDrawer(action: QuickAction, mode: DrawerMode = "create") {
111
+ setDrawerAction(action);
112
+ setDrawerMode(mode);
113
+ }
114
+
115
+ return (
116
+ <AdminShell
117
+ variant="ops"
118
+ activeKey={activeNav}
119
+ navItems={monitorNavItems}
120
+ brandTitle="智能运营管理平台"
121
+ brandSubtitle="平台专业版"
122
+ topbar={
123
+ <AdminTopbar
124
+ title="运营监控中心"
125
+ subtitle="晚上好,超级管理员,欢迎回来!"
126
+ searchPlaceholder="搜索功能、数据、报表..."
127
+ userName="管理员"
128
+ extra={
129
+ <Space size={8}>
130
+ <DatePicker />
131
+ <Button onClick={refresh}>刷新</Button>
132
+ <Select<ViewState>
133
+ size="small"
134
+ value={viewState}
135
+ onChange={setViewState}
136
+ options={[
137
+ { value: "ready", label: "正常" },
138
+ { value: "loading", label: "加载" },
139
+ { value: "empty", label: "空态" },
140
+ { value: "error", label: "错误" },
141
+ ]}
142
+ />
143
+ </Space>
144
+ }
145
+ />
146
+ }
147
+ sidebarFooter={
148
+ <>
149
+ <div className="bp-ops-license">
150
+ <strong>平台专业版</strong>
151
+ <span>已授权 356 天</span>
152
+ <Button size="small" type="primary">
153
+ 升级授权
154
+ </Button>
155
+ <i />
156
+ </div>
157
+ </>
158
+ }
159
+ onNavChange={setActiveNav}
160
+ >
161
+ {viewState !== "ready" ? (
162
+ <Panel className="bp-ops-state-panel">
163
+ <QueryState
164
+ loading={viewState === "loading"}
165
+ empty={viewState === "empty"}
166
+ error={viewState === "error" ? "模拟监控接口异常,请点击重试恢复。" : null}
167
+ onRetry={() => setViewState("ready")}
168
+ />
169
+ </Panel>
170
+ ) : (
171
+ <>
172
+ <section className="bp-ops-metrics">
173
+ {opsMetrics.map((metric) => (
174
+ <MetricCard key={metric.id} metric={metric} />
175
+ ))}
176
+ <Panel className="bp-ops-alert-mini">
177
+ <Tag color="red">系统告警数</Tag>
178
+ <strong>128</strong>
179
+ <span>较昨日 ↓ 12.5%</span>
180
+ </Panel>
181
+ <Panel className="bp-ops-alert-mini is-pink">
182
+ <Tag color="magenta">平均响应时间</Tag>
183
+ <strong>386 ms</strong>
184
+ <span>较昨日 ↓ 6.3%</span>
185
+ </Panel>
186
+ </section>
187
+
188
+ <section className="bp-ops-grid">
189
+ <Panel
190
+ title="访问量趋势"
191
+ className="bp-ops-traffic"
192
+ extra={
193
+ <Space size={4}>
194
+ {(["realtime", "7", "30"] as TrafficMode[]).map((mode) => (
195
+ <Button
196
+ key={mode}
197
+ size="small"
198
+ type={trafficMode === mode ? "primary" : "text"}
199
+ onClick={() => setTrafficMode(mode)}
200
+ >
201
+ {mode === "realtime" ? "实时" : mode === "7" ? "近7天" : "近30天"}
202
+ </Button>
203
+ ))}
204
+ </Space>
205
+ }
206
+ >
207
+ <DashboardChart option={trafficOption} height={306} />
208
+ <div className="bp-ops-traffic-summary">
209
+ {[
210
+ ["今日总访问量", "32,568,129", "12.6%"],
211
+ ["今日独立访客", "12,853,529", "9.3%"],
212
+ ["今日页面浏览量", "68,392,681", "10.2%"],
213
+ ["平均访问时长", "00:06:35", "4.1%"],
214
+ ["跳出率", "32.45%", "2.7%"],
215
+ ].map(([label, value, delta]) => (
216
+ <div key={label}>
217
+ <span>{label}</span>
218
+ <strong>{value}</strong>
219
+ <small>较昨日 ↑ {delta}</small>
220
+ </div>
221
+ ))}
222
+ </div>
223
+ </Panel>
224
+ <Panel title="任务执行情况">
225
+ <TaskProgressList items={taskProgressItems} />
226
+ </Panel>
227
+ <Panel title="系统健康度">
228
+ <HealthScore value={92} tone="cyan" />
229
+ </Panel>
230
+ <Panel title="核心系统状态">
231
+ <div className="bp-ops-system-rings">
232
+ {[
233
+ ["CPU使用率", "23%"],
234
+ ["内存使用率", "46%"],
235
+ ["磁盘使用率", "62%"],
236
+ ["网络负载", "32%"],
237
+ ].map(([label, value]) => (
238
+ <div key={label}>
239
+ <i style={{ "--ring-value": value } as React.CSSProperties} />
240
+ <strong>{value}</strong>
241
+ <span>{label}</span>
242
+ </div>
243
+ ))}
244
+ </div>
245
+ </Panel>
246
+ <Panel title="设备在线状态">
247
+ <DashboardChart option={deviceOption} height={230} />
248
+ </Panel>
249
+ <Panel title="告警实时监控" className="bp-ops-alert-list-panel">
250
+ <div className="bp-ops-alert-list">
251
+ {alerts.map(([title, level, status, time, tone]) => (
252
+ <div key={title} className={`bp-ops-alert-row is-${tone}`}>
253
+ <span>{title}</span>
254
+ <Tag color={tone}>{level}</Tag>
255
+ <Tag>{status}</Tag>
256
+ <time>{time}</time>
257
+ </div>
258
+ ))}
259
+ </div>
260
+ </Panel>
261
+ </section>
262
+
263
+ <section className="bp-ops-bottom">
264
+ <Panel title="快捷操作">
265
+ <QuickActionGrid
266
+ actions={quickActions.slice(4, 9)}
267
+ compact
268
+ onAction={(action) => openActionDrawer(action)}
269
+ />
270
+ </Panel>
271
+ <Panel title="平台公告">
272
+ <ActivityList items={activities.slice(0, 4)} />
273
+ </Panel>
274
+ <Panel title="今日数据摘要">
275
+ <div className="bp-ops-digest">
276
+ {[
277
+ ["新增用户", "6,732", "15.3%"],
278
+ ["订单总数", "3,528", "8.1%"],
279
+ ["交易金额", "¥1,268,732", "11.7%"],
280
+ ["转化率", "4.35%", "2.4%"],
281
+ ].map(([label, value, delta]) => (
282
+ <div key={label}>
283
+ <span>{label}</span>
284
+ <strong>{value}</strong>
285
+ <small>较昨日 ↑ {delta}</small>
286
+ </div>
287
+ ))}
288
+ </div>
289
+ </Panel>
290
+ </section>
291
+ </>
292
+ )}
293
+
294
+ <TemplateActionDrawer
295
+ open={Boolean(drawerAction)}
296
+ title={drawerAction ? `${drawerAction.label}` : "新增任务"}
297
+ mode={drawerMode}
298
+ onClose={() => setDrawerAction(null)}
299
+ onSubmit={() => {
300
+ setDrawerAction(null);
301
+ message.success("任务已提交");
302
+ }}
303
+ />
304
+ </AdminShell>
305
+ );
306
+ }
@@ -0,0 +1,10 @@
1
+ import { createReactPage } from "openxiangda/runtime";
2
+
3
+ import App from "./App";
4
+
5
+ const page = createReactPage(App);
6
+
7
+ export const mount = page.mount;
8
+ export const update = page.update;
9
+ export const unmount = page.unmount;
10
+ export default page;
@@ -0,0 +1,14 @@
1
+ import { definePageConfig } from "@/types/app-workspace.types";
2
+
3
+ export default definePageConfig({
4
+ code: "ops_monitor_dashboard",
5
+ name: "蓝紫运营监控中心",
6
+ description: "后台管理蓝紫运营监控中心模板",
7
+ route: { pathKey: "ops_monitor_dashboard" },
8
+ entry: {
9
+ mode: "app-shell",
10
+ hidePlatformNav: true,
11
+ defaultRoute: "monitor",
12
+ },
13
+ menu: { name: "蓝紫运营监控中心" },
14
+ });
@@ -0,0 +1,248 @@
1
+ .bp-ops-state-panel {
2
+ min-height: 440px;
3
+ }
4
+
5
+ .bp-ops-license {
6
+ position: relative;
7
+ display: grid;
8
+ gap: 8px;
9
+ min-height: 164px;
10
+ padding: 16px;
11
+ overflow: hidden;
12
+ border: 1px solid rgba(124, 58, 237, 0.18);
13
+ border-radius: 16px;
14
+ background: linear-gradient(150deg, rgba(255, 255, 255, 0.76), rgba(221, 214, 254, 0.64));
15
+ }
16
+
17
+ .bp-ops-license strong {
18
+ color: #1e1b4b;
19
+ font-size: 14px;
20
+ }
21
+
22
+ .bp-ops-license > span {
23
+ color: #64748b;
24
+ font-size: 13px;
25
+ }
26
+
27
+ .bp-ops-license .ant-btn {
28
+ width: fit-content;
29
+ }
30
+
31
+ .bp-ops-license .ant-btn-primary,
32
+ .bp-ops-license .ant-btn-primary span {
33
+ color: #ffffff;
34
+ }
35
+
36
+ .bp-ops-license i {
37
+ position: absolute;
38
+ right: -20px;
39
+ bottom: -26px;
40
+ width: 118px;
41
+ height: 82px;
42
+ border-radius: 28px;
43
+ background: linear-gradient(135deg, rgba(129, 140, 248, 0.42), rgba(255, 255, 255, 0.58));
44
+ box-shadow: 0 22px 40px rgba(79, 70, 229, 0.2);
45
+ transform: rotate(-10deg);
46
+ }
47
+
48
+ .bp-ops-metrics {
49
+ display: grid;
50
+ grid-template-columns: repeat(4, minmax(0, 1fr)) repeat(2, minmax(150px, 0.75fr));
51
+ gap: 16px;
52
+ }
53
+
54
+ .bp-ops-alert-mini {
55
+ display: grid;
56
+ gap: 9px;
57
+ align-content: center;
58
+ min-height: 132px;
59
+ }
60
+
61
+ .bp-ops-alert-mini strong {
62
+ color: #111827;
63
+ font-size: 26px;
64
+ }
65
+
66
+ .bp-ops-alert-mini span {
67
+ color: #10b981;
68
+ font-size: 12px;
69
+ }
70
+
71
+ .bp-ops-alert-mini.is-pink {
72
+ background: linear-gradient(145deg, rgba(255, 255, 255, 0.88), rgba(252, 231, 243, 0.78));
73
+ }
74
+
75
+ .bp-ops-grid {
76
+ display: grid;
77
+ grid-template-columns: minmax(0, 1.7fr) minmax(300px, 0.75fr) minmax(300px, 0.78fr);
78
+ gap: 16px;
79
+ }
80
+
81
+ .bp-ops-traffic {
82
+ grid-row: span 2;
83
+ }
84
+
85
+ .bp-ops-traffic-summary {
86
+ display: grid;
87
+ grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
88
+ gap: 10px;
89
+ padding-top: 12px;
90
+ border-top: 1px solid #e5eaf2;
91
+ }
92
+
93
+ .bp-ops-traffic-summary div {
94
+ min-width: 0;
95
+ padding: 0 10px 8px;
96
+ border-bottom: 1px solid #e5eaf2;
97
+ }
98
+
99
+ .bp-ops-traffic-summary span,
100
+ .bp-ops-traffic-summary small,
101
+ .bp-ops-digest span,
102
+ .bp-ops-digest small {
103
+ display: block;
104
+ overflow: hidden;
105
+ text-overflow: ellipsis;
106
+ white-space: nowrap;
107
+ }
108
+
109
+ .bp-ops-traffic-summary span,
110
+ .bp-ops-digest span {
111
+ color: #64748b;
112
+ font-size: 12px;
113
+ }
114
+
115
+ .bp-ops-traffic-summary strong,
116
+ .bp-ops-digest strong {
117
+ display: block;
118
+ margin: 6px 0;
119
+ color: #1e3a8a;
120
+ font-size: 20px;
121
+ line-height: 1.05;
122
+ }
123
+
124
+ .bp-ops-traffic-summary small,
125
+ .bp-ops-digest small {
126
+ color: #10b981;
127
+ font-size: 12px;
128
+ }
129
+
130
+ .bp-ops-system-rings {
131
+ display: grid;
132
+ grid-template-columns: repeat(4, minmax(0, 1fr));
133
+ gap: 12px;
134
+ }
135
+
136
+ .bp-ops-system-rings div {
137
+ display: grid;
138
+ justify-items: center;
139
+ gap: 8px;
140
+ }
141
+
142
+ .bp-ops-system-rings i {
143
+ display: grid;
144
+ width: 72px;
145
+ height: 72px;
146
+ place-items: center;
147
+ border-radius: 50%;
148
+ background:
149
+ radial-gradient(circle at center, #ffffff 58%, transparent 60%),
150
+ conic-gradient(#4f46e5 var(--ring-value), #dbe4f0 0);
151
+ }
152
+
153
+ .bp-ops-system-rings strong {
154
+ color: #1e3a8a;
155
+ font-size: 17px;
156
+ }
157
+
158
+ .bp-ops-system-rings span {
159
+ color: #64748b;
160
+ font-size: 12px;
161
+ text-align: center;
162
+ }
163
+
164
+ .bp-ops-alert-list-panel {
165
+ grid-column: span 1;
166
+ }
167
+
168
+ .bp-ops-alert-list {
169
+ display: grid;
170
+ gap: 9px;
171
+ }
172
+
173
+ .bp-ops-alert-row {
174
+ display: grid;
175
+ grid-template-columns: minmax(0, 1fr) 58px 64px 60px;
176
+ gap: 8px;
177
+ align-items: center;
178
+ padding: 9px 0;
179
+ border-bottom: 1px solid #edf2f7;
180
+ color: #475569;
181
+ font-size: 13px;
182
+ }
183
+
184
+ .bp-ops-alert-row:last-child {
185
+ border-bottom: 0;
186
+ }
187
+
188
+ .bp-ops-alert-row time {
189
+ color: #94a3b8;
190
+ font-size: 12px;
191
+ text-align: right;
192
+ }
193
+
194
+ .bp-ops-bottom {
195
+ display: grid;
196
+ grid-template-columns: minmax(280px, 0.95fr) minmax(0, 1.3fr) minmax(320px, 1fr);
197
+ gap: 16px;
198
+ }
199
+
200
+ .bp-ops-digest {
201
+ display: grid;
202
+ grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
203
+ gap: 10px;
204
+ }
205
+
206
+ .bp-ops-digest div {
207
+ min-width: 0;
208
+ padding: 0 10px 8px;
209
+ border-bottom: 1px solid #e5eaf2;
210
+ }
211
+
212
+ @media (max-width: 1280px) {
213
+ .bp-ops-metrics {
214
+ grid-template-columns: repeat(3, minmax(0, 1fr));
215
+ }
216
+
217
+ .bp-ops-grid,
218
+ .bp-ops-bottom {
219
+ grid-template-columns: 1fr 1fr;
220
+ }
221
+
222
+ .bp-ops-traffic {
223
+ grid-column: span 2;
224
+ }
225
+ }
226
+
227
+ @media (max-width: 960px) {
228
+ .bp-ops-metrics,
229
+ .bp-ops-grid,
230
+ .bp-ops-bottom,
231
+ .bp-ops-traffic-summary,
232
+ .bp-ops-system-rings,
233
+ .bp-ops-digest {
234
+ grid-template-columns: 1fr;
235
+ }
236
+
237
+ .bp-ops-traffic {
238
+ grid-column: auto;
239
+ }
240
+
241
+ .bp-ops-alert-row {
242
+ grid-template-columns: 1fr;
243
+ }
244
+
245
+ .bp-ops-alert-row time {
246
+ text-align: left;
247
+ }
248
+ }
@@ -0,0 +1,8 @@
1
+ import "@/shared/components/admin-ui-templates/styles.css";
2
+ import "./styles.css";
3
+
4
+ import { WorkOrderListDrawerPage } from "./WorkOrderListDrawerPage";
5
+
6
+ export default function App() {
7
+ return <WorkOrderListDrawerPage />;
8
+ }