android-midscene-automation 0.1.19 → 0.1.21
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/CHANGELOG.md +25 -0
- package/README.md +25 -0
- package/package.json +9 -1
- package/server/appium-recorder/appium-runner.ts +41 -20
- package/server/appium-recorder/repository.ts +27 -6
- package/src/appium-recorder/AppiumPage.vue +77 -48
- package/src/appium-recorder/components/FlowStepEditor.vue +0 -8
- package/src/appium-recorder/components/NestedConditionBranches.vue +373 -0
- package/src/appium-recorder/components/RecordedSteps.vue +607 -23
- package/src/appium-recorder/flow-copy.ts +193 -0
- package/src/appium-recorder/flow-layout.ts +88 -0
- package/src/style.css +163 -34
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import type { AppiumRecordedStep } from './types';
|
|
2
|
+
|
|
3
|
+
export type FlowBranch = 'yes' | 'no';
|
|
4
|
+
|
|
5
|
+
export type FlowClipboard = {
|
|
6
|
+
steps: AppiumRecordedStep[];
|
|
7
|
+
rootIds: string[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type PasteTarget = {
|
|
11
|
+
afterIndex: number;
|
|
12
|
+
branch?: FlowBranch;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const targetKeys = [
|
|
16
|
+
'yesTargetId',
|
|
17
|
+
'noTargetId',
|
|
18
|
+
'successTargetId',
|
|
19
|
+
'failureTargetId',
|
|
20
|
+
] as const;
|
|
21
|
+
|
|
22
|
+
function clone<T>(value: T): T {
|
|
23
|
+
return structuredClone(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function scopeKey(step: AppiumRecordedStep) {
|
|
27
|
+
return step.flow?.parentConditionId
|
|
28
|
+
? `${step.flow.parentConditionId}:${step.flow.parentBranch || ''}`
|
|
29
|
+
: 'main';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function collectDescendantIds(steps: AppiumRecordedStep[], rootIds: Iterable<string>) {
|
|
33
|
+
const ids = new Set(rootIds);
|
|
34
|
+
let changed = true;
|
|
35
|
+
while (changed) {
|
|
36
|
+
changed = false;
|
|
37
|
+
for (const step of steps) {
|
|
38
|
+
if (step.flow?.parentConditionId && ids.has(step.flow.parentConditionId) && !ids.has(step.id)) {
|
|
39
|
+
ids.add(step.id);
|
|
40
|
+
changed = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return ids;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function setFlowTarget(step: AppiumRecordedStep, key: typeof targetKeys[number], targetId: string) {
|
|
48
|
+
const flow = { ...(step.flow || {}) };
|
|
49
|
+
if (targetId) flow[key] = targetId;
|
|
50
|
+
else delete flow[key];
|
|
51
|
+
step.flow = Object.keys(flow).length ? flow : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function wireContinuation(step: AppiumRecordedStep, targetId: string) {
|
|
55
|
+
setFlowTarget(step, 'successTargetId', targetId);
|
|
56
|
+
if (step.flow?.nodeKind !== 'condition' || !targetId) return;
|
|
57
|
+
if (!step.flow.yesTargetId) setFlowTarget(step, 'yesTargetId', targetId);
|
|
58
|
+
if (!step.flow.noTargetId) setFlowTarget(step, 'noTargetId', targetId);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function createFlowClipboard(steps: AppiumRecordedStep[], indexes: number[]): FlowClipboard {
|
|
62
|
+
const selectedIndexes = [...new Set(indexes)].sort((left, right) => left - right);
|
|
63
|
+
const selectedSteps = selectedIndexes.map((index) => steps[index]).filter(Boolean);
|
|
64
|
+
const selectedIds = new Set(selectedSteps.map((step) => step.id));
|
|
65
|
+
const roots = selectedSteps.filter((step) => {
|
|
66
|
+
let parentId = step.flow?.parentConditionId;
|
|
67
|
+
while (parentId) {
|
|
68
|
+
if (selectedIds.has(parentId)) return false;
|
|
69
|
+
parentId = steps.find((item) => item.id === parentId)?.flow?.parentConditionId;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
});
|
|
73
|
+
if (!roots.length) throw new Error('请选择要复制的节点');
|
|
74
|
+
const isDisconnected = roots.some((step, index) => {
|
|
75
|
+
if (!index) return false;
|
|
76
|
+
const previous = roots[index - 1];
|
|
77
|
+
if (scopeKey(previous) !== scopeKey(step)) {
|
|
78
|
+
return previous.flow?.successTargetId !== step.id;
|
|
79
|
+
}
|
|
80
|
+
const siblings = steps.filter((item) => scopeKey(item) === scopeKey(step));
|
|
81
|
+
return siblings.findIndex((item) => item.id === step.id)
|
|
82
|
+
!== siblings.findIndex((item) => item.id === previous.id) + 1;
|
|
83
|
+
});
|
|
84
|
+
if (isDisconnected) {
|
|
85
|
+
throw new Error('批量复制只能选择连续节点');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const rootIds = roots.map((step) => step.id);
|
|
89
|
+
const copiedIds = collectDescendantIds(steps, rootIds);
|
|
90
|
+
const copiedSteps = steps.filter((step) => copiedIds.has(step.id));
|
|
91
|
+
if (copiedSteps.some((step) => step.type === 'launchApp')) {
|
|
92
|
+
throw new Error('启动 APP 节点不能复制');
|
|
93
|
+
}
|
|
94
|
+
return { steps: clone(copiedSteps), rootIds };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function pasteFlowClipboard(
|
|
98
|
+
steps: AppiumRecordedStep[],
|
|
99
|
+
clipboard: FlowClipboard,
|
|
100
|
+
target: PasteTarget,
|
|
101
|
+
createId: () => string = () => `step_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`,
|
|
102
|
+
) {
|
|
103
|
+
if (!clipboard.steps.length || !clipboard.rootIds.length) throw new Error('复制板中没有节点');
|
|
104
|
+
|
|
105
|
+
const idMap = new Map(clipboard.steps.map((step) => [step.id, createId()]));
|
|
106
|
+
const rootIdSet = new Set(clipboard.rootIds);
|
|
107
|
+
const condition = target.branch ? steps[target.afterIndex] : undefined;
|
|
108
|
+
if (target.branch && (!condition || condition.flow?.nodeKind !== 'condition')) {
|
|
109
|
+
throw new Error('目标分支不存在');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const copies = clipboard.steps.map((source) => {
|
|
113
|
+
const step = clone(source);
|
|
114
|
+
step.id = idMap.get(source.id) || createId();
|
|
115
|
+
const flow = { ...(step.flow || {}) };
|
|
116
|
+
for (const key of targetKeys) {
|
|
117
|
+
const mappedId = flow[key] ? idMap.get(flow[key] || '') : '';
|
|
118
|
+
if (mappedId) flow[key] = mappedId;
|
|
119
|
+
else delete flow[key];
|
|
120
|
+
}
|
|
121
|
+
if (flow.parentConditionId) {
|
|
122
|
+
const mappedParentId = idMap.get(flow.parentConditionId);
|
|
123
|
+
if (mappedParentId) flow.parentConditionId = mappedParentId;
|
|
124
|
+
else {
|
|
125
|
+
delete flow.parentConditionId;
|
|
126
|
+
delete flow.parentBranch;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (rootIdSet.has(source.id)) {
|
|
130
|
+
if (target.branch && condition) {
|
|
131
|
+
flow.parentConditionId = condition.id;
|
|
132
|
+
flow.parentBranch = target.branch;
|
|
133
|
+
} else {
|
|
134
|
+
delete flow.parentConditionId;
|
|
135
|
+
delete flow.parentBranch;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
step.flow = Object.keys(flow).length ? flow : undefined;
|
|
139
|
+
return step;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const copiedBySourceId = new Map(clipboard.steps.map((step, index) => [step.id, copies[index]]));
|
|
143
|
+
const copiedRoots = clipboard.rootIds
|
|
144
|
+
.map((id) => copiedBySourceId.get(id))
|
|
145
|
+
.filter((step): step is AppiumRecordedStep => Boolean(step));
|
|
146
|
+
const firstRoot = copiedRoots[0];
|
|
147
|
+
const lastRoot = copiedRoots[copiedRoots.length - 1];
|
|
148
|
+
if (!firstRoot || !lastRoot) throw new Error('复制节点数据无效');
|
|
149
|
+
|
|
150
|
+
const nextSteps = [...steps];
|
|
151
|
+
let insertAfterIndex = target.afterIndex;
|
|
152
|
+
let continuationId = '';
|
|
153
|
+
|
|
154
|
+
if (target.branch && condition) {
|
|
155
|
+
const branchRoots = steps.filter((step) => (
|
|
156
|
+
step.flow?.parentConditionId === condition.id
|
|
157
|
+
&& step.flow.parentBranch === target.branch
|
|
158
|
+
));
|
|
159
|
+
if (branchRoots.length) {
|
|
160
|
+
const ownedIds = collectDescendantIds(steps, branchRoots.map((step) => step.id));
|
|
161
|
+
insertAfterIndex = Math.max(...steps.flatMap((step, index) => (ownedIds.has(step.id) ? [index] : [])));
|
|
162
|
+
const lastExistingRoot = branchRoots[branchRoots.length - 1];
|
|
163
|
+
continuationId = lastExistingRoot.flow?.successTargetId || condition.flow?.successTargetId || '';
|
|
164
|
+
const lastExistingIndex = nextSteps.findIndex((step) => step.id === lastExistingRoot.id);
|
|
165
|
+
const updatedLastExisting = clone(nextSteps[lastExistingIndex]);
|
|
166
|
+
setFlowTarget(updatedLastExisting, 'successTargetId', firstRoot.id);
|
|
167
|
+
nextSteps[lastExistingIndex] = updatedLastExisting;
|
|
168
|
+
} else {
|
|
169
|
+
const targetKey = target.branch === 'yes' ? 'yesTargetId' : 'noTargetId';
|
|
170
|
+
const currentTargetId = condition.flow?.[targetKey] || '';
|
|
171
|
+
const currentTarget = steps.find((step) => step.id === currentTargetId);
|
|
172
|
+
continuationId = currentTarget && !currentTarget.flow?.parentConditionId
|
|
173
|
+
? currentTargetId
|
|
174
|
+
: condition.flow?.successTargetId || '';
|
|
175
|
+
const updatedCondition = clone(nextSteps[target.afterIndex]);
|
|
176
|
+
setFlowTarget(updatedCondition, targetKey, firstRoot.id);
|
|
177
|
+
nextSteps[target.afterIndex] = updatedCondition;
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
const previous = target.afterIndex >= 0 ? nextSteps[target.afterIndex] : undefined;
|
|
181
|
+
const nextMainStep = steps.slice(target.afterIndex + 1).find((step) => !step.flow?.parentConditionId);
|
|
182
|
+
continuationId = previous?.flow?.successTargetId || nextMainStep?.id || '';
|
|
183
|
+
if (previous?.flow?.successTargetId) {
|
|
184
|
+
const updatedPrevious = clone(previous);
|
|
185
|
+
setFlowTarget(updatedPrevious, 'successTargetId', firstRoot.id);
|
|
186
|
+
nextSteps[target.afterIndex] = updatedPrevious;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
wireContinuation(lastRoot, continuationId);
|
|
191
|
+
nextSteps.splice(insertAfterIndex + 1, 0, ...copies);
|
|
192
|
+
return nextSteps;
|
|
193
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { AppiumRecordedStep } from './types';
|
|
2
|
+
|
|
3
|
+
export const FLOW_NODE_WIDTH = 420;
|
|
4
|
+
export const FLOW_BRANCH_GAP = 16;
|
|
5
|
+
|
|
6
|
+
export type ConditionLayout = {
|
|
7
|
+
yesWidth: number;
|
|
8
|
+
noWidth: number;
|
|
9
|
+
totalWidth: number;
|
|
10
|
+
yesAxis: number;
|
|
11
|
+
noAxis: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ConditionPlacement = {
|
|
15
|
+
left: number;
|
|
16
|
+
startAxis: number;
|
|
17
|
+
yesAxis: number;
|
|
18
|
+
noAxis: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function placeConditionLayout(
|
|
22
|
+
layout: ConditionLayout,
|
|
23
|
+
canvasWidth: number,
|
|
24
|
+
parentAxis: number,
|
|
25
|
+
): ConditionPlacement {
|
|
26
|
+
const parentCenter = (parentAxis / 100) * canvasWidth;
|
|
27
|
+
const left = Math.min(
|
|
28
|
+
Math.max(parentCenter - layout.totalWidth / 2, 0),
|
|
29
|
+
Math.max(canvasWidth - layout.totalWidth, 0),
|
|
30
|
+
);
|
|
31
|
+
const yesCenter = left + layout.yesWidth / 2;
|
|
32
|
+
const noCenter = left + layout.yesWidth + FLOW_BRANCH_GAP + layout.noWidth / 2;
|
|
33
|
+
return {
|
|
34
|
+
left,
|
|
35
|
+
startAxis: ((parentCenter - left) / layout.totalWidth) * 100,
|
|
36
|
+
yesAxis: (yesCenter / canvasWidth) * 100,
|
|
37
|
+
noAxis: (noCenter / canvasWidth) * 100,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function buildConditionLayouts(steps: AppiumRecordedStep[]) {
|
|
42
|
+
const layouts = new Map<string, ConditionLayout>();
|
|
43
|
+
const visiting = new Set<string>();
|
|
44
|
+
|
|
45
|
+
function conditionLayout(conditionId: string): ConditionLayout {
|
|
46
|
+
const cached = layouts.get(conditionId);
|
|
47
|
+
if (cached) return cached;
|
|
48
|
+
if (visiting.has(conditionId)) {
|
|
49
|
+
return {
|
|
50
|
+
yesWidth: FLOW_NODE_WIDTH,
|
|
51
|
+
noWidth: FLOW_NODE_WIDTH,
|
|
52
|
+
totalWidth: FLOW_NODE_WIDTH * 2 + FLOW_BRANCH_GAP,
|
|
53
|
+
yesAxis: 25,
|
|
54
|
+
noAxis: 75,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
visiting.add(conditionId);
|
|
59
|
+
const branchWidth = (branch: 'yes' | 'no') => Math.max(
|
|
60
|
+
FLOW_NODE_WIDTH,
|
|
61
|
+
...steps
|
|
62
|
+
.filter((step) => (
|
|
63
|
+
step.flow?.parentConditionId === conditionId
|
|
64
|
+
&& step.flow.parentBranch === branch
|
|
65
|
+
&& step.flow.nodeKind === 'condition'
|
|
66
|
+
))
|
|
67
|
+
.map((step) => conditionLayout(step.id).totalWidth),
|
|
68
|
+
);
|
|
69
|
+
const yesWidth = branchWidth('yes');
|
|
70
|
+
const noWidth = branchWidth('no');
|
|
71
|
+
const totalWidth = yesWidth + FLOW_BRANCH_GAP + noWidth;
|
|
72
|
+
const layout = {
|
|
73
|
+
yesWidth,
|
|
74
|
+
noWidth,
|
|
75
|
+
totalWidth,
|
|
76
|
+
yesAxis: (yesWidth / 2 / totalWidth) * 100,
|
|
77
|
+
noAxis: ((yesWidth + FLOW_BRANCH_GAP + noWidth / 2) / totalWidth) * 100,
|
|
78
|
+
};
|
|
79
|
+
visiting.delete(conditionId);
|
|
80
|
+
layouts.set(conditionId, layout);
|
|
81
|
+
return layout;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
steps
|
|
85
|
+
.filter((step) => step.flow?.nodeKind === 'condition')
|
|
86
|
+
.forEach((step) => conditionLayout(step.id));
|
|
87
|
+
return layouts;
|
|
88
|
+
}
|
package/src/style.css
CHANGED
|
@@ -192,7 +192,7 @@ select {
|
|
|
192
192
|
.appium-recorder-layout {
|
|
193
193
|
display: grid;
|
|
194
194
|
flex: 1 1 auto;
|
|
195
|
-
grid-template-columns: minmax(0, 3fr) minmax(320px,
|
|
195
|
+
grid-template-columns: minmax(0, 3fr) minmax(320px, 2.8fr) minmax(0, 4.2fr);
|
|
196
196
|
gap: 12px;
|
|
197
197
|
align-items: stretch;
|
|
198
198
|
height: auto;
|
|
@@ -662,10 +662,22 @@ select {
|
|
|
662
662
|
|
|
663
663
|
.appium-flow-toolbar {
|
|
664
664
|
display: flex;
|
|
665
|
+
align-items: center;
|
|
665
666
|
justify-content: flex-end;
|
|
667
|
+
gap: 6px;
|
|
666
668
|
margin-bottom: 6px;
|
|
667
669
|
}
|
|
668
670
|
|
|
671
|
+
.appium-flow-toolbar .el-button + .el-button {
|
|
672
|
+
margin-left: 0;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.appium-flow-toolbar__status {
|
|
676
|
+
margin-right: 2px;
|
|
677
|
+
color: #64748b;
|
|
678
|
+
font-size: 12px;
|
|
679
|
+
}
|
|
680
|
+
|
|
669
681
|
.appium-flow-canvas {
|
|
670
682
|
position: relative;
|
|
671
683
|
height: 460px;
|
|
@@ -695,7 +707,8 @@ select {
|
|
|
695
707
|
display: grid;
|
|
696
708
|
gap: 8px;
|
|
697
709
|
align-content: start;
|
|
698
|
-
width: max
|
|
710
|
+
width: max-content;
|
|
711
|
+
min-width: max(980px, 100%);
|
|
699
712
|
min-width: 0;
|
|
700
713
|
padding: 10px 12px 14px;
|
|
701
714
|
transform-origin: 0 0;
|
|
@@ -725,7 +738,8 @@ select {
|
|
|
725
738
|
}
|
|
726
739
|
|
|
727
740
|
.appium-flow-content--overview {
|
|
728
|
-
width:
|
|
741
|
+
width: max-content;
|
|
742
|
+
min-width: max(980px, 100%);
|
|
729
743
|
margin: 0 auto;
|
|
730
744
|
transform-origin: 0 0;
|
|
731
745
|
}
|
|
@@ -836,8 +850,7 @@ select {
|
|
|
836
850
|
|
|
837
851
|
.appium-flow-node__toggle {
|
|
838
852
|
display: grid;
|
|
839
|
-
grid-template-columns:
|
|
840
|
-
gap: 6px;
|
|
853
|
+
grid-template-columns: minmax(0, 1fr);
|
|
841
854
|
align-items: center;
|
|
842
855
|
min-width: 0;
|
|
843
856
|
padding: 0;
|
|
@@ -852,7 +865,8 @@ select {
|
|
|
852
865
|
.appium-flow-item > .appium-flow-node,
|
|
853
866
|
.appium-flow-item > .appium-flow-editor {
|
|
854
867
|
box-sizing: border-box;
|
|
855
|
-
width:
|
|
868
|
+
width: 100%;
|
|
869
|
+
max-width: 420px;
|
|
856
870
|
justify-self: center;
|
|
857
871
|
left: calc(var(--flow-axis) - 50%);
|
|
858
872
|
}
|
|
@@ -872,16 +886,14 @@ select {
|
|
|
872
886
|
border-color: #409eff;
|
|
873
887
|
}
|
|
874
888
|
|
|
875
|
-
.appium-flow-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
border-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
font-size: 11px;
|
|
884
|
-
font-weight: 700;
|
|
889
|
+
.appium-flow-node--copying {
|
|
890
|
+
cursor: copy;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.appium-flow-node--selected {
|
|
894
|
+
border-color: #337ecc;
|
|
895
|
+
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.32);
|
|
896
|
+
background: #d9ecff;
|
|
885
897
|
}
|
|
886
898
|
|
|
887
899
|
.appium-flow-node__body {
|
|
@@ -931,17 +943,36 @@ select {
|
|
|
931
943
|
position: relative;
|
|
932
944
|
z-index: 1;
|
|
933
945
|
display: grid;
|
|
934
|
-
grid-template-columns: repeat(2, minmax(
|
|
935
|
-
gap:
|
|
946
|
+
grid-template-columns: repeat(2, minmax(420px, 1fr));
|
|
947
|
+
column-gap: 16px;
|
|
948
|
+
width: max-content;
|
|
949
|
+
min-width: 100%;
|
|
950
|
+
justify-self: center;
|
|
936
951
|
margin-left: 0;
|
|
937
952
|
margin-right: 0;
|
|
938
953
|
padding-top: 30px;
|
|
939
954
|
}
|
|
940
955
|
|
|
956
|
+
.appium-flow-nested-condition {
|
|
957
|
+
position: relative;
|
|
958
|
+
z-index: 1;
|
|
959
|
+
width: max-content;
|
|
960
|
+
min-width: 856px;
|
|
961
|
+
justify-self: center;
|
|
962
|
+
background:
|
|
963
|
+
radial-gradient(circle at 1px 1px, #e7edf6 1px, transparent 0) 0 0 / 18px 18px,
|
|
964
|
+
#fff;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
.appium-flow-nested-condition > .appium-flow-branches {
|
|
968
|
+
width: 100%;
|
|
969
|
+
}
|
|
970
|
+
|
|
941
971
|
.appium-flow-item--condition > .appium-flow-editor {
|
|
942
972
|
order: 1;
|
|
943
973
|
box-sizing: border-box;
|
|
944
|
-
width:
|
|
974
|
+
width: 100%;
|
|
975
|
+
max-width: 420px;
|
|
945
976
|
justify-self: center;
|
|
946
977
|
}
|
|
947
978
|
|
|
@@ -978,8 +1009,9 @@ select {
|
|
|
978
1009
|
align-content: start;
|
|
979
1010
|
justify-self: center;
|
|
980
1011
|
box-sizing: border-box;
|
|
981
|
-
width:
|
|
982
|
-
|
|
1012
|
+
width: 100%;
|
|
1013
|
+
max-width: none;
|
|
1014
|
+
min-width: 420px;
|
|
983
1015
|
padding: 0;
|
|
984
1016
|
color: #64748b;
|
|
985
1017
|
font-size: 11px;
|
|
@@ -1033,14 +1065,23 @@ select {
|
|
|
1033
1065
|
gap: 10px;
|
|
1034
1066
|
justify-self: center;
|
|
1035
1067
|
width: 100%;
|
|
1036
|
-
|
|
1068
|
+
max-width: none;
|
|
1069
|
+
min-width: 420px;
|
|
1037
1070
|
}
|
|
1038
1071
|
|
|
1039
1072
|
.appium-flow-branch-step-group {
|
|
1040
1073
|
display: grid;
|
|
1041
1074
|
gap: 6px;
|
|
1042
1075
|
width: 100%;
|
|
1043
|
-
|
|
1076
|
+
max-width: none;
|
|
1077
|
+
min-width: 420px;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
.appium-flow-branch-step-group > .appium-flow-node,
|
|
1081
|
+
.appium-flow-branch-step-group > .appium-flow-editor {
|
|
1082
|
+
box-sizing: border-box;
|
|
1083
|
+
width: 420px;
|
|
1084
|
+
justify-self: center;
|
|
1044
1085
|
}
|
|
1045
1086
|
|
|
1046
1087
|
.appium-flow-branch-step {
|
|
@@ -1051,6 +1092,7 @@ select {
|
|
|
1051
1092
|
gap: 6px;
|
|
1052
1093
|
align-items: center;
|
|
1053
1094
|
width: 100%;
|
|
1095
|
+
max-width: 420px;
|
|
1054
1096
|
min-width: 0;
|
|
1055
1097
|
padding: 6px 8px;
|
|
1056
1098
|
border: 1px solid #d8e0ea;
|
|
@@ -1079,6 +1121,19 @@ select {
|
|
|
1079
1121
|
justify-content: center;
|
|
1080
1122
|
}
|
|
1081
1123
|
|
|
1124
|
+
.appium-flow-branch:has(
|
|
1125
|
+
.appium-flow-branch-step-group:last-child > .appium-flow-nested-condition
|
|
1126
|
+
) > .appium-flow-branch__actions {
|
|
1127
|
+
background: #fff;
|
|
1128
|
+
box-shadow: 0 -10px 0 #fff;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
.appium-flow-branch:has(
|
|
1132
|
+
.appium-flow-branch-step-group:last-child > .appium-flow-nested-condition
|
|
1133
|
+
) > .appium-flow-branch__actions > .el-dropdown {
|
|
1134
|
+
display: none;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1082
1137
|
.appium-flow-branch__connect {
|
|
1083
1138
|
height: 24px;
|
|
1084
1139
|
padding: 0 8px;
|
|
@@ -1140,11 +1195,11 @@ select {
|
|
|
1140
1195
|
stroke: var(--appium-flow-line-color);
|
|
1141
1196
|
}
|
|
1142
1197
|
|
|
1143
|
-
.appium-flow-branch--yes .appium-flow-branch-step {
|
|
1198
|
+
.appium-flow-branch--yes .appium-flow-branch-step:not(.appium-flow-node--selected) {
|
|
1144
1199
|
border-color: #b3e19d;
|
|
1145
1200
|
}
|
|
1146
1201
|
|
|
1147
|
-
.appium-flow-branch--no .appium-flow-branch-step {
|
|
1202
|
+
.appium-flow-branch--no .appium-flow-branch-step:not(.appium-flow-node--selected) {
|
|
1148
1203
|
border-color: #fab6b6;
|
|
1149
1204
|
}
|
|
1150
1205
|
|
|
@@ -1164,13 +1219,6 @@ select {
|
|
|
1164
1219
|
gap: 8px;
|
|
1165
1220
|
}
|
|
1166
1221
|
|
|
1167
|
-
.appium-flow-editor__actions {
|
|
1168
|
-
display: flex;
|
|
1169
|
-
flex-wrap: wrap;
|
|
1170
|
-
gap: 8px;
|
|
1171
|
-
justify-content: flex-end;
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
1222
|
.appium-flow-insert {
|
|
1175
1223
|
position: relative;
|
|
1176
1224
|
z-index: 1;
|
|
@@ -1246,8 +1294,78 @@ select {
|
|
|
1246
1294
|
}
|
|
1247
1295
|
|
|
1248
1296
|
.appium-replay-output--dialog {
|
|
1249
|
-
|
|
1250
|
-
|
|
1297
|
+
box-sizing: border-box;
|
|
1298
|
+
height: 100%;
|
|
1299
|
+
min-height: 0;
|
|
1300
|
+
max-height: none;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
.appium-replay-dialog.el-dialog {
|
|
1304
|
+
display: flex;
|
|
1305
|
+
width: min(820px, calc(100vw - 32px)) !important;
|
|
1306
|
+
height: min(620px, calc(100vh - 64px));
|
|
1307
|
+
min-width: 420px;
|
|
1308
|
+
min-height: 280px;
|
|
1309
|
+
max-width: calc(100vw - 32px);
|
|
1310
|
+
max-height: calc(100vh - 32px);
|
|
1311
|
+
flex-direction: column;
|
|
1312
|
+
overflow: hidden;
|
|
1313
|
+
resize: both;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
.appium-replay-dialog > .el-dialog__header,
|
|
1317
|
+
.appium-replay-dialog > .el-dialog__footer {
|
|
1318
|
+
flex: 0 0 auto;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
.appium-replay-dialog > .el-dialog__body {
|
|
1322
|
+
flex: 1 1 auto;
|
|
1323
|
+
min-height: 0;
|
|
1324
|
+
overflow: hidden;
|
|
1325
|
+
padding-top: 8px;
|
|
1326
|
+
padding-bottom: 8px;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
.appium-replay-dialog .appium-replay-output {
|
|
1330
|
+
border-color: #263244;
|
|
1331
|
+
background: #101722;
|
|
1332
|
+
color: #d7e0ea;
|
|
1333
|
+
scrollbar-color: #526174 #101722;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
.appium-replay-dialog .appium-replay-output::-webkit-scrollbar {
|
|
1337
|
+
width: 10px;
|
|
1338
|
+
height: 10px;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
.appium-replay-dialog .appium-replay-output::-webkit-scrollbar-track {
|
|
1342
|
+
background: #101722;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
.appium-replay-dialog .appium-replay-output::-webkit-scrollbar-thumb {
|
|
1346
|
+
border: 2px solid #101722;
|
|
1347
|
+
border-radius: 6px;
|
|
1348
|
+
background: #526174;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
.appium-replay-fab {
|
|
1352
|
+
position: fixed;
|
|
1353
|
+
right: 28px;
|
|
1354
|
+
bottom: 28px;
|
|
1355
|
+
z-index: 50;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
.appium-replay-fab .el-button {
|
|
1359
|
+
width: 52px;
|
|
1360
|
+
height: 52px;
|
|
1361
|
+
box-shadow: 0 8px 24px rgba(64, 158, 255, 0.28);
|
|
1362
|
+
font-size: 20px;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
.appium-replay-fab__button--running {
|
|
1366
|
+
box-shadow:
|
|
1367
|
+
0 0 0 5px rgba(230, 162, 60, 0.18),
|
|
1368
|
+
0 8px 24px rgba(64, 158, 255, 0.28) !important;
|
|
1251
1369
|
}
|
|
1252
1370
|
|
|
1253
1371
|
.appium-navigation-dialog {
|
|
@@ -2628,6 +2746,17 @@ select {
|
|
|
2628
2746
|
}
|
|
2629
2747
|
}
|
|
2630
2748
|
|
|
2749
|
+
@media (max-width: 520px) {
|
|
2750
|
+
.appium-replay-dialog.el-dialog {
|
|
2751
|
+
min-width: calc(100vw - 24px);
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
.appium-replay-fab {
|
|
2755
|
+
right: 16px;
|
|
2756
|
+
bottom: 16px;
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2631
2760
|
@media (max-width: 1200px) {
|
|
2632
2761
|
.layout {
|
|
2633
2762
|
grid-template-columns: 1fr;
|