@reconcrap/boss-recommend-mcp 2.1.22 → 2.1.24
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/README.md +5 -0
- package/bin/boss-recommend-mcp.js +4 -4
- package/package.json +14 -8
- package/scripts/install-macos.sh +280 -280
- package/scripts/postinstall.cjs +44 -44
- package/skills/boss-chat/README.md +43 -42
- package/skills/boss-chat/SKILL.md +107 -106
- package/skills/boss-recommend-pipeline/README.md +13 -13
- package/skills/boss-recommend-pipeline/SKILL.md +47 -47
- package/skills/boss-recruit-pipeline/README.md +19 -19
- package/skills/boss-recruit-pipeline/SKILL.md +89 -89
- package/src/chat-mcp.js +301 -127
- package/src/core/boss-cards/index.js +199 -199
- package/src/core/browser/index.js +291 -114
- package/src/core/capture/index.js +2930 -1201
- package/src/core/cv-acquisition/index.js +512 -238
- package/src/core/cv-capture-target/index.js +513 -299
- package/src/core/greet-quota/index.js +71 -71
- package/src/core/infinite-list/index.js +11 -2
- package/src/core/reporting/legacy-csv.js +12 -12
- package/src/core/run/detached-launcher.js +305 -0
- package/src/core/run/index.js +112 -42
- package/src/core/run/timing.js +33 -33
- package/src/core/run/windows-detached-worker.ps1 +106 -0
- package/src/core/screening/index.js +2135 -2135
- package/src/core/self-heal/index.js +989 -973
- package/src/core/self-heal/viewport.js +1505 -564
- package/src/detached-worker.js +99 -99
- package/src/domains/chat/action-journal.js +443 -0
- package/src/domains/chat/cards.js +137 -137
- package/src/domains/chat/constants.js +9 -9
- package/src/domains/chat/detail.js +1684 -401
- package/src/domains/chat/index.js +8 -7
- package/src/domains/chat/jobs.js +620 -620
- package/src/domains/chat/page-guard.js +157 -122
- package/src/domains/chat/roots.js +56 -56
- package/src/domains/chat/run-service.js +1801 -760
- package/src/domains/common/account-rights-panel.js +314 -314
- package/src/domains/common/recovery-settle.js +159 -159
- package/src/domains/recommend/actions.js +515 -472
- package/src/domains/recommend/cards.js +243 -243
- package/src/domains/recommend/colleague-contact.js +333 -333
- package/src/domains/recommend/constants.js +92 -92
- package/src/domains/recommend/detail.js +12 -3
- package/src/domains/recommend/filters.js +611 -611
- package/src/domains/recommend/index.js +9 -9
- package/src/domains/recommend/jobs.js +542 -542
- package/src/domains/recommend/location.js +736 -736
- package/src/domains/recommend/refresh.js +410 -329
- package/src/domains/recommend/roots.js +80 -80
- package/src/domains/recommend/run-service.js +1783 -592
- package/src/domains/recommend/scopes.js +246 -246
- package/src/domains/recruit/actions.js +277 -277
- package/src/domains/recruit/cards.js +74 -74
- package/src/domains/recruit/constants.js +236 -236
- package/src/domains/recruit/detail.js +588 -588
- package/src/domains/recruit/index.js +9 -9
- package/src/domains/recruit/instruction-parser.js +866 -866
- package/src/domains/recruit/refresh.js +45 -45
- package/src/domains/recruit/roots.js +68 -68
- package/src/domains/recruit/run-service.js +1817 -1620
- package/src/domains/recruit/search.js +3229 -3229
- package/src/index.js +124 -5
- package/src/parser.js +1296 -1296
- package/src/recommend-mcp.js +515 -80
- package/src/recommend-scheduler.js +66 -0
|
@@ -8,60 +8,60 @@ import {
|
|
|
8
8
|
getOuterHTML,
|
|
9
9
|
pressKey,
|
|
10
10
|
querySelectorAll,
|
|
11
|
-
sleep,
|
|
12
|
-
waitForSelector
|
|
13
|
-
} from "../../core/browser/index.js";
|
|
14
|
-
import { htmlToText, normalizeText } from "../../core/screening/index.js";
|
|
15
|
-
import {
|
|
16
|
-
RECOMMEND_ACTIVITY_GROUP,
|
|
17
|
-
RECOMMEND_ACTIVITY_GROUP_HEADING,
|
|
18
|
-
RECOMMEND_ACTIVITY_LEVELS,
|
|
19
|
-
RECOMMEND_CARD_SELECTOR,
|
|
20
|
-
RECOMMEND_FILTER_GROUP_ORDER,
|
|
21
|
-
RECOMMEND_FILTER_SELECTORS
|
|
22
|
-
} from "./constants.js";
|
|
23
|
-
|
|
11
|
+
sleep,
|
|
12
|
+
waitForSelector
|
|
13
|
+
} from "../../core/browser/index.js";
|
|
14
|
+
import { htmlToText, normalizeText } from "../../core/screening/index.js";
|
|
15
|
+
import {
|
|
16
|
+
RECOMMEND_ACTIVITY_GROUP,
|
|
17
|
+
RECOMMEND_ACTIVITY_GROUP_HEADING,
|
|
18
|
+
RECOMMEND_ACTIVITY_LEVELS,
|
|
19
|
+
RECOMMEND_CARD_SELECTOR,
|
|
20
|
+
RECOMMEND_FILTER_GROUP_ORDER,
|
|
21
|
+
RECOMMEND_FILTER_SELECTORS
|
|
22
|
+
} from "./constants.js";
|
|
23
|
+
|
|
24
24
|
const SKIP_OPTION_LABELS = new Set(["不限", "全部", "all"]);
|
|
25
25
|
|
|
26
26
|
export function normalizeFilterOptionLabel(label) {
|
|
27
27
|
return normalizeText(label).replace(/\s+/g, "");
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export function isSafeFilterOptionLabel(label) {
|
|
31
|
-
const normalized = normalizeFilterOptionLabel(label);
|
|
32
|
-
return Boolean(normalized) && !SKIP_OPTION_LABELS.has(normalized.toLowerCase());
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function isSelectableFilterOptionLabel(label, { allowUnlimited = false } = {}) {
|
|
36
|
-
const normalized = normalizeFilterOptionLabel(label);
|
|
37
|
-
if (!normalized) return false;
|
|
38
|
-
return allowUnlimited || !SKIP_OPTION_LABELS.has(normalized.toLowerCase());
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function normalizeActivityGroupText(text) {
|
|
42
|
-
return normalizeFilterOptionLabel(text)
|
|
43
|
-
.replace(/【/g, "[")
|
|
44
|
-
.replace(/】/g, "]");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function isRecommendActivityGroupText(text) {
|
|
48
|
-
const normalized = normalizeActivityGroupText(text);
|
|
49
|
-
const heading = normalizeActivityGroupText(RECOMMEND_ACTIVITY_GROUP_HEADING);
|
|
50
|
-
const exactOptionCount = RECOMMEND_ACTIVITY_LEVELS.filter((label) => (
|
|
51
|
-
normalized.includes(normalizeFilterOptionLabel(label))
|
|
52
|
-
)).length;
|
|
53
|
-
const hasUnlimited = normalized.includes(normalizeFilterOptionLabel("不限"));
|
|
54
|
-
return (
|
|
55
|
-
(normalized.startsWith(heading) && exactOptionCount >= 2 && hasUnlimited)
|
|
56
|
-
|| (exactOptionCount === RECOMMEND_ACTIVITY_LEVELS.length && hasUnlimited)
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function isActiveOption(attributes = {}, outerHTML = "") {
|
|
61
|
-
const className = attributes.class || "";
|
|
62
|
-
return /\bactive\b/.test(className) || /\bactive\b/.test(String(outerHTML || "").split(">")[0] || "");
|
|
63
|
-
}
|
|
64
|
-
|
|
30
|
+
export function isSafeFilterOptionLabel(label) {
|
|
31
|
+
const normalized = normalizeFilterOptionLabel(label);
|
|
32
|
+
return Boolean(normalized) && !SKIP_OPTION_LABELS.has(normalized.toLowerCase());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isSelectableFilterOptionLabel(label, { allowUnlimited = false } = {}) {
|
|
36
|
+
const normalized = normalizeFilterOptionLabel(label);
|
|
37
|
+
if (!normalized) return false;
|
|
38
|
+
return allowUnlimited || !SKIP_OPTION_LABELS.has(normalized.toLowerCase());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function normalizeActivityGroupText(text) {
|
|
42
|
+
return normalizeFilterOptionLabel(text)
|
|
43
|
+
.replace(/【/g, "[")
|
|
44
|
+
.replace(/】/g, "]");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isRecommendActivityGroupText(text) {
|
|
48
|
+
const normalized = normalizeActivityGroupText(text);
|
|
49
|
+
const heading = normalizeActivityGroupText(RECOMMEND_ACTIVITY_GROUP_HEADING);
|
|
50
|
+
const exactOptionCount = RECOMMEND_ACTIVITY_LEVELS.filter((label) => (
|
|
51
|
+
normalized.includes(normalizeFilterOptionLabel(label))
|
|
52
|
+
)).length;
|
|
53
|
+
const hasUnlimited = normalized.includes(normalizeFilterOptionLabel("不限"));
|
|
54
|
+
return (
|
|
55
|
+
(normalized.startsWith(heading) && exactOptionCount >= 2 && hasUnlimited)
|
|
56
|
+
|| (exactOptionCount === RECOMMEND_ACTIVITY_LEVELS.length && hasUnlimited)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isActiveOption(attributes = {}, outerHTML = "") {
|
|
61
|
+
const className = attributes.class || "";
|
|
62
|
+
return /\bactive\b/.test(className) || /\bactive\b/.test(String(outerHTML || "").split(">")[0] || "");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
65
|
export function chooseFirstSafeFilterOption(options = [], groupOrder = RECOMMEND_FILTER_GROUP_ORDER) {
|
|
66
66
|
for (const group of groupOrder) {
|
|
67
67
|
const option = options.find((item) => (
|
|
@@ -71,45 +71,45 @@ export function chooseFirstSafeFilterOption(options = [], groupOrder = RECOMMEND
|
|
|
71
71
|
));
|
|
72
72
|
if (option) return option;
|
|
73
73
|
}
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function chooseFilterOptionByLabels(options = [], {
|
|
78
|
-
group = "",
|
|
79
|
-
labels = [],
|
|
80
|
-
allowUnlimited = false
|
|
81
|
-
} = {}) {
|
|
82
|
-
const normalizedGroup = normalizeText(group);
|
|
83
|
-
const normalizedLabels = labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
84
|
-
for (const label of normalizedLabels) {
|
|
85
|
-
const option = options.find((item) => (
|
|
86
|
-
(!normalizedGroup || item.group === normalizedGroup)
|
|
87
|
-
&& !item.active
|
|
88
|
-
&& normalizeFilterOptionLabel(item.label) === label
|
|
89
|
-
&& isSelectableFilterOptionLabel(item.label, { allowUnlimited })
|
|
90
|
-
));
|
|
91
|
-
if (option) return option;
|
|
92
|
-
}
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function chooseFilterOptionsByLabels(options = [], {
|
|
97
|
-
group = "",
|
|
98
|
-
labels = [],
|
|
99
|
-
allowUnlimited = false
|
|
100
|
-
} = {}) {
|
|
101
|
-
const normalizedGroup = normalizeText(group);
|
|
102
|
-
const normalizedLabels = labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
103
|
-
return normalizedLabels.map((label) => {
|
|
104
|
-
const option = options.find((item) => (
|
|
105
|
-
(!normalizedGroup || item.group === normalizedGroup)
|
|
106
|
-
&& normalizeFilterOptionLabel(item.label) === label
|
|
107
|
-
&& isSelectableFilterOptionLabel(item.label, { allowUnlimited })
|
|
108
|
-
));
|
|
109
|
-
return {
|
|
110
|
-
label,
|
|
111
|
-
option: option || null
|
|
112
|
-
};
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function chooseFilterOptionByLabels(options = [], {
|
|
78
|
+
group = "",
|
|
79
|
+
labels = [],
|
|
80
|
+
allowUnlimited = false
|
|
81
|
+
} = {}) {
|
|
82
|
+
const normalizedGroup = normalizeText(group);
|
|
83
|
+
const normalizedLabels = labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
84
|
+
for (const label of normalizedLabels) {
|
|
85
|
+
const option = options.find((item) => (
|
|
86
|
+
(!normalizedGroup || item.group === normalizedGroup)
|
|
87
|
+
&& !item.active
|
|
88
|
+
&& normalizeFilterOptionLabel(item.label) === label
|
|
89
|
+
&& isSelectableFilterOptionLabel(item.label, { allowUnlimited })
|
|
90
|
+
));
|
|
91
|
+
if (option) return option;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function chooseFilterOptionsByLabels(options = [], {
|
|
97
|
+
group = "",
|
|
98
|
+
labels = [],
|
|
99
|
+
allowUnlimited = false
|
|
100
|
+
} = {}) {
|
|
101
|
+
const normalizedGroup = normalizeText(group);
|
|
102
|
+
const normalizedLabels = labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
103
|
+
return normalizedLabels.map((label) => {
|
|
104
|
+
const option = options.find((item) => (
|
|
105
|
+
(!normalizedGroup || item.group === normalizedGroup)
|
|
106
|
+
&& normalizeFilterOptionLabel(item.label) === label
|
|
107
|
+
&& isSelectableFilterOptionLabel(item.label, { allowUnlimited })
|
|
108
|
+
));
|
|
109
|
+
return {
|
|
110
|
+
label,
|
|
111
|
+
option: option || null
|
|
112
|
+
};
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -185,12 +185,12 @@ async function findFilterTriggerCandidates(client, frameNodeId) {
|
|
|
185
185
|
return candidates;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
export async function openFilterPanel(client, frameNodeId) {
|
|
189
|
-
let triggerCandidates = await findFilterTriggerCandidates(client, frameNodeId);
|
|
190
|
-
if (!triggerCandidates.length) {
|
|
191
|
-
const error = new Error("Recommend filter trigger was not found");
|
|
192
|
-
error.code = "RECOMMEND_FILTER_TRIGGER_UNAVAILABLE";
|
|
193
|
-
throw error;
|
|
188
|
+
export async function openFilterPanel(client, frameNodeId) {
|
|
189
|
+
let triggerCandidates = await findFilterTriggerCandidates(client, frameNodeId);
|
|
190
|
+
if (!triggerCandidates.length) {
|
|
191
|
+
const error = new Error("Recommend filter trigger was not found");
|
|
192
|
+
error.code = "RECOMMEND_FILTER_TRIGGER_UNAVAILABLE";
|
|
193
|
+
throw error;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
const preOpenDismissalAttempts = await dismissRecommendControlOverlays(client);
|
|
@@ -261,76 +261,76 @@ async function readOptionNode(client, group, nodeId) {
|
|
|
261
261
|
attributes: {
|
|
262
262
|
class: attributes.class || "",
|
|
263
263
|
value: attributes.value || "",
|
|
264
|
-
type: attributes.type || ""
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function uniqueNodeIds(nodeIds = []) {
|
|
270
|
-
return [...new Set(nodeIds.filter((nodeId) => Number(nodeId) > 0))];
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
async function nodeMatchesActivityGroup(client, nodeId) {
|
|
274
|
-
const outerHTML = await getOuterHTML(client, nodeId);
|
|
275
|
-
return isRecommendActivityGroupText(htmlToText(outerHTML));
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export async function resolveRecommendFilterGroupNodeIds(client, frameNodeId, group) {
|
|
279
|
-
const groupSelector = RECOMMEND_FILTER_SELECTORS.groups[group];
|
|
280
|
-
if (!groupSelector) return [];
|
|
281
|
-
if (group !== RECOMMEND_ACTIVITY_GROUP) {
|
|
282
|
-
return querySelectorAll(client, frameNodeId, groupSelector);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const selectorCandidates = uniqueNodeIds(await querySelectorAll(client, frameNodeId, groupSelector));
|
|
286
|
-
const semanticMatches = [];
|
|
287
|
-
for (const nodeId of selectorCandidates) {
|
|
288
|
-
if (await nodeMatchesActivityGroup(client, nodeId)) semanticMatches.push(nodeId);
|
|
289
|
-
}
|
|
290
|
-
if (semanticMatches.length) return uniqueNodeIds(semanticMatches);
|
|
291
|
-
|
|
292
|
-
const broadCandidates = uniqueNodeIds(await querySelectorAll(
|
|
293
|
-
client,
|
|
294
|
-
frameNodeId,
|
|
295
|
-
RECOMMEND_FILTER_SELECTORS.checkBox
|
|
296
|
-
));
|
|
297
|
-
for (const nodeId of broadCandidates) {
|
|
298
|
-
if (selectorCandidates.includes(nodeId)) continue;
|
|
299
|
-
try {
|
|
300
|
-
if (await nodeMatchesActivityGroup(client, nodeId)) semanticMatches.push(nodeId);
|
|
301
|
-
} catch {
|
|
302
|
-
// An unrelated stale filter row does not make the activity control visible.
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
if (semanticMatches.length) return uniqueNodeIds(semanticMatches);
|
|
306
|
-
if (selectorCandidates.length) {
|
|
307
|
-
throw new Error("Recommend activity filter control was visible but its semantic row could not be verified");
|
|
308
|
-
}
|
|
309
|
-
return [];
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
export async function listFilterOptions(client, frameNodeId, {
|
|
313
|
-
groupOrder = RECOMMEND_FILTER_GROUP_ORDER
|
|
314
|
-
} = {}) {
|
|
315
|
-
const options = [];
|
|
316
|
-
for (const group of groupOrder) {
|
|
317
|
-
const groupNodeIds = await resolveRecommendFilterGroupNodeIds(client, frameNodeId, group);
|
|
318
|
-
let optionCount = 0;
|
|
319
|
-
for (const groupNodeId of groupNodeIds) {
|
|
320
|
-
const optionNodeIds = await querySelectorAll(client, groupNodeId, RECOMMEND_FILTER_SELECTORS.option);
|
|
321
|
-
for (const optionNodeId of optionNodeIds) {
|
|
322
|
-
options.push(await readOptionNode(client, group, optionNodeId));
|
|
323
|
-
optionCount += 1;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
if (group === RECOMMEND_ACTIVITY_GROUP && groupNodeIds.length && optionCount === 0) {
|
|
327
|
-
throw new Error("Recommend activity filter control was visible but its options could not be read");
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return options;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
async function clickFirstAvailableNode(client, nodeIds) {
|
|
264
|
+
type: attributes.type || ""
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function uniqueNodeIds(nodeIds = []) {
|
|
270
|
+
return [...new Set(nodeIds.filter((nodeId) => Number(nodeId) > 0))];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function nodeMatchesActivityGroup(client, nodeId) {
|
|
274
|
+
const outerHTML = await getOuterHTML(client, nodeId);
|
|
275
|
+
return isRecommendActivityGroupText(htmlToText(outerHTML));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export async function resolveRecommendFilterGroupNodeIds(client, frameNodeId, group) {
|
|
279
|
+
const groupSelector = RECOMMEND_FILTER_SELECTORS.groups[group];
|
|
280
|
+
if (!groupSelector) return [];
|
|
281
|
+
if (group !== RECOMMEND_ACTIVITY_GROUP) {
|
|
282
|
+
return querySelectorAll(client, frameNodeId, groupSelector);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const selectorCandidates = uniqueNodeIds(await querySelectorAll(client, frameNodeId, groupSelector));
|
|
286
|
+
const semanticMatches = [];
|
|
287
|
+
for (const nodeId of selectorCandidates) {
|
|
288
|
+
if (await nodeMatchesActivityGroup(client, nodeId)) semanticMatches.push(nodeId);
|
|
289
|
+
}
|
|
290
|
+
if (semanticMatches.length) return uniqueNodeIds(semanticMatches);
|
|
291
|
+
|
|
292
|
+
const broadCandidates = uniqueNodeIds(await querySelectorAll(
|
|
293
|
+
client,
|
|
294
|
+
frameNodeId,
|
|
295
|
+
RECOMMEND_FILTER_SELECTORS.checkBox
|
|
296
|
+
));
|
|
297
|
+
for (const nodeId of broadCandidates) {
|
|
298
|
+
if (selectorCandidates.includes(nodeId)) continue;
|
|
299
|
+
try {
|
|
300
|
+
if (await nodeMatchesActivityGroup(client, nodeId)) semanticMatches.push(nodeId);
|
|
301
|
+
} catch {
|
|
302
|
+
// An unrelated stale filter row does not make the activity control visible.
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (semanticMatches.length) return uniqueNodeIds(semanticMatches);
|
|
306
|
+
if (selectorCandidates.length) {
|
|
307
|
+
throw new Error("Recommend activity filter control was visible but its semantic row could not be verified");
|
|
308
|
+
}
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export async function listFilterOptions(client, frameNodeId, {
|
|
313
|
+
groupOrder = RECOMMEND_FILTER_GROUP_ORDER
|
|
314
|
+
} = {}) {
|
|
315
|
+
const options = [];
|
|
316
|
+
for (const group of groupOrder) {
|
|
317
|
+
const groupNodeIds = await resolveRecommendFilterGroupNodeIds(client, frameNodeId, group);
|
|
318
|
+
let optionCount = 0;
|
|
319
|
+
for (const groupNodeId of groupNodeIds) {
|
|
320
|
+
const optionNodeIds = await querySelectorAll(client, groupNodeId, RECOMMEND_FILTER_SELECTORS.option);
|
|
321
|
+
for (const optionNodeId of optionNodeIds) {
|
|
322
|
+
options.push(await readOptionNode(client, group, optionNodeId));
|
|
323
|
+
optionCount += 1;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (group === RECOMMEND_ACTIVITY_GROUP && groupNodeIds.length && optionCount === 0) {
|
|
327
|
+
throw new Error("Recommend activity filter control was visible but its options could not be read");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return options;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async function clickFirstAvailableNode(client, nodeIds) {
|
|
334
334
|
const errors = [];
|
|
335
335
|
for (const nodeId of nodeIds) {
|
|
336
336
|
try {
|
|
@@ -420,86 +420,86 @@ export async function selectFirstSafeFilterOption(client, frameNodeId, {
|
|
|
420
420
|
node_id: option.node_id
|
|
421
421
|
}))
|
|
422
422
|
};
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
export async function selectFilterOption(client, frameNodeId, {
|
|
426
|
-
group = "",
|
|
427
|
-
labels = [],
|
|
428
|
-
groupOrder = RECOMMEND_FILTER_GROUP_ORDER,
|
|
429
|
-
allowUnlimited = false
|
|
430
|
-
} = {}) {
|
|
431
|
-
const options = await listFilterOptions(client, frameNodeId, { groupOrder });
|
|
432
|
-
const alreadyActive = labels.length
|
|
433
|
-
? options.find((option) => (
|
|
434
|
-
(!group || option.group === group)
|
|
435
|
-
&& labels.some((label) => (
|
|
436
|
-
normalizeFilterOptionLabel(option.label) === normalizeFilterOptionLabel(label)
|
|
437
|
-
))
|
|
438
|
-
&& option.active
|
|
439
|
-
&& isSelectableFilterOptionLabel(option.label, { allowUnlimited })
|
|
440
|
-
))
|
|
441
|
-
: null;
|
|
442
|
-
if (alreadyActive) {
|
|
443
|
-
return {
|
|
444
|
-
selected_option: {
|
|
445
|
-
group: alreadyActive.group,
|
|
446
|
-
label: alreadyActive.label,
|
|
447
|
-
node_id: alreadyActive.node_id,
|
|
448
|
-
was_active: true,
|
|
449
|
-
clicked: false,
|
|
450
|
-
requested_group: group || null,
|
|
451
|
-
requested_labels: labels
|
|
452
|
-
},
|
|
453
|
-
selected_options: [],
|
|
454
|
-
option_box: null,
|
|
455
|
-
unavailable: false,
|
|
456
|
-
unavailable_groups: [],
|
|
457
|
-
discovered_options: options.map((option) => ({
|
|
458
|
-
group: option.group,
|
|
459
|
-
label: option.label,
|
|
460
|
-
active: option.active,
|
|
461
|
-
node_id: option.node_id
|
|
462
|
-
}))
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
const selected = labels.length
|
|
466
|
-
? chooseFilterOptionByLabels(options, { group, labels, allowUnlimited })
|
|
467
|
-
: chooseFirstSafeFilterOption(options, groupOrder);
|
|
468
|
-
|
|
469
|
-
if (!selected) {
|
|
470
|
-
const requestedLabels = labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
471
|
-
const groupOptions = options.filter((option) => !group || option.group === group);
|
|
472
|
-
const unavailableDefault = (
|
|
473
|
-
group === RECOMMEND_ACTIVITY_GROUP
|
|
474
|
-
&& allowUnlimited
|
|
475
|
-
&& requestedLabels.length === 1
|
|
476
|
-
&& requestedLabels[0] === normalizeFilterOptionLabel("不限")
|
|
477
|
-
&& groupOptions.length === 0
|
|
478
|
-
);
|
|
479
|
-
if (unavailableDefault) {
|
|
480
|
-
return {
|
|
481
|
-
selected_option: null,
|
|
482
|
-
selected_options: [],
|
|
483
|
-
option_box: null,
|
|
484
|
-
unavailable: true,
|
|
485
|
-
unavailable_groups: [{
|
|
486
|
-
group,
|
|
487
|
-
requested_labels: labels,
|
|
488
|
-
reason: "activity_control_unavailable_default"
|
|
489
|
-
}],
|
|
490
|
-
discovered_options: options.map((option) => ({
|
|
491
|
-
group: option.group,
|
|
492
|
-
label: option.label,
|
|
493
|
-
active: option.active,
|
|
494
|
-
node_id: option.node_id
|
|
495
|
-
}))
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
const target = labels.length
|
|
499
|
-
? `${group || "any group"} / ${labels.join(", ")}`
|
|
500
|
-
: "first safe non-active option";
|
|
501
|
-
throw new Error(`No matching recommend filter option was found for ${target}`);
|
|
502
|
-
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export async function selectFilterOption(client, frameNodeId, {
|
|
426
|
+
group = "",
|
|
427
|
+
labels = [],
|
|
428
|
+
groupOrder = RECOMMEND_FILTER_GROUP_ORDER,
|
|
429
|
+
allowUnlimited = false
|
|
430
|
+
} = {}) {
|
|
431
|
+
const options = await listFilterOptions(client, frameNodeId, { groupOrder });
|
|
432
|
+
const alreadyActive = labels.length
|
|
433
|
+
? options.find((option) => (
|
|
434
|
+
(!group || option.group === group)
|
|
435
|
+
&& labels.some((label) => (
|
|
436
|
+
normalizeFilterOptionLabel(option.label) === normalizeFilterOptionLabel(label)
|
|
437
|
+
))
|
|
438
|
+
&& option.active
|
|
439
|
+
&& isSelectableFilterOptionLabel(option.label, { allowUnlimited })
|
|
440
|
+
))
|
|
441
|
+
: null;
|
|
442
|
+
if (alreadyActive) {
|
|
443
|
+
return {
|
|
444
|
+
selected_option: {
|
|
445
|
+
group: alreadyActive.group,
|
|
446
|
+
label: alreadyActive.label,
|
|
447
|
+
node_id: alreadyActive.node_id,
|
|
448
|
+
was_active: true,
|
|
449
|
+
clicked: false,
|
|
450
|
+
requested_group: group || null,
|
|
451
|
+
requested_labels: labels
|
|
452
|
+
},
|
|
453
|
+
selected_options: [],
|
|
454
|
+
option_box: null,
|
|
455
|
+
unavailable: false,
|
|
456
|
+
unavailable_groups: [],
|
|
457
|
+
discovered_options: options.map((option) => ({
|
|
458
|
+
group: option.group,
|
|
459
|
+
label: option.label,
|
|
460
|
+
active: option.active,
|
|
461
|
+
node_id: option.node_id
|
|
462
|
+
}))
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
const selected = labels.length
|
|
466
|
+
? chooseFilterOptionByLabels(options, { group, labels, allowUnlimited })
|
|
467
|
+
: chooseFirstSafeFilterOption(options, groupOrder);
|
|
468
|
+
|
|
469
|
+
if (!selected) {
|
|
470
|
+
const requestedLabels = labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
471
|
+
const groupOptions = options.filter((option) => !group || option.group === group);
|
|
472
|
+
const unavailableDefault = (
|
|
473
|
+
group === RECOMMEND_ACTIVITY_GROUP
|
|
474
|
+
&& allowUnlimited
|
|
475
|
+
&& requestedLabels.length === 1
|
|
476
|
+
&& requestedLabels[0] === normalizeFilterOptionLabel("不限")
|
|
477
|
+
&& groupOptions.length === 0
|
|
478
|
+
);
|
|
479
|
+
if (unavailableDefault) {
|
|
480
|
+
return {
|
|
481
|
+
selected_option: null,
|
|
482
|
+
selected_options: [],
|
|
483
|
+
option_box: null,
|
|
484
|
+
unavailable: true,
|
|
485
|
+
unavailable_groups: [{
|
|
486
|
+
group,
|
|
487
|
+
requested_labels: labels,
|
|
488
|
+
reason: "activity_control_unavailable_default"
|
|
489
|
+
}],
|
|
490
|
+
discovered_options: options.map((option) => ({
|
|
491
|
+
group: option.group,
|
|
492
|
+
label: option.label,
|
|
493
|
+
active: option.active,
|
|
494
|
+
node_id: option.node_id
|
|
495
|
+
}))
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
const target = labels.length
|
|
499
|
+
? `${group || "any group"} / ${labels.join(", ")}`
|
|
500
|
+
: "first safe non-active option";
|
|
501
|
+
throw new Error(`No matching recommend filter option was found for ${target}`);
|
|
502
|
+
}
|
|
503
503
|
|
|
504
504
|
const box = await clickNodeCenter(client, selected.node_id, {
|
|
505
505
|
...DETERMINISTIC_CLICK_OPTIONS,
|
|
@@ -508,45 +508,45 @@ export async function selectFilterOption(client, frameNodeId, {
|
|
|
508
508
|
await sleep(300);
|
|
509
509
|
|
|
510
510
|
return {
|
|
511
|
-
selected_option: {
|
|
512
|
-
group: selected.group,
|
|
513
|
-
label: selected.label,
|
|
514
|
-
node_id: selected.node_id,
|
|
515
|
-
was_active: selected.active,
|
|
516
|
-
clicked: true,
|
|
517
|
-
requested_group: group || null,
|
|
518
|
-
requested_labels: labels
|
|
519
|
-
},
|
|
520
|
-
option_box: box,
|
|
521
|
-
unavailable: false,
|
|
522
|
-
unavailable_groups: [],
|
|
523
|
-
discovered_options: options.map((option) => ({
|
|
524
|
-
group: option.group,
|
|
525
|
-
label: option.label,
|
|
526
|
-
active: option.active,
|
|
527
|
-
node_id: option.node_id
|
|
511
|
+
selected_option: {
|
|
512
|
+
group: selected.group,
|
|
513
|
+
label: selected.label,
|
|
514
|
+
node_id: selected.node_id,
|
|
515
|
+
was_active: selected.active,
|
|
516
|
+
clicked: true,
|
|
517
|
+
requested_group: group || null,
|
|
518
|
+
requested_labels: labels
|
|
519
|
+
},
|
|
520
|
+
option_box: box,
|
|
521
|
+
unavailable: false,
|
|
522
|
+
unavailable_groups: [],
|
|
523
|
+
discovered_options: options.map((option) => ({
|
|
524
|
+
group: option.group,
|
|
525
|
+
label: option.label,
|
|
526
|
+
active: option.active,
|
|
527
|
+
node_id: option.node_id
|
|
528
528
|
}))
|
|
529
529
|
};
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
export async function selectFilterOptions(client, frameNodeId, {
|
|
533
|
-
group = "",
|
|
534
|
-
labels = [],
|
|
535
|
-
groupOrder = RECOMMEND_FILTER_GROUP_ORDER,
|
|
536
|
-
allowUnlimited = false
|
|
537
|
-
} = {}) {
|
|
538
|
-
if (!labels.length) {
|
|
539
|
-
return selectFilterOption(client, frameNodeId, {
|
|
540
|
-
group,
|
|
541
|
-
labels,
|
|
542
|
-
groupOrder,
|
|
543
|
-
allowUnlimited
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
const selectedOptions = [];
|
|
548
|
-
const missingLabels = [];
|
|
549
|
-
let discoveredOptions = [];
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export async function selectFilterOptions(client, frameNodeId, {
|
|
533
|
+
group = "",
|
|
534
|
+
labels = [],
|
|
535
|
+
groupOrder = RECOMMEND_FILTER_GROUP_ORDER,
|
|
536
|
+
allowUnlimited = false
|
|
537
|
+
} = {}) {
|
|
538
|
+
if (!labels.length) {
|
|
539
|
+
return selectFilterOption(client, frameNodeId, {
|
|
540
|
+
group,
|
|
541
|
+
labels,
|
|
542
|
+
groupOrder,
|
|
543
|
+
allowUnlimited
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const selectedOptions = [];
|
|
548
|
+
const missingLabels = [];
|
|
549
|
+
let discoveredOptions = [];
|
|
550
550
|
|
|
551
551
|
for (const label of labels) {
|
|
552
552
|
if (await getFilterPanelCount(client, frameNodeId) === 0) {
|
|
@@ -555,26 +555,26 @@ export async function selectFilterOptions(client, frameNodeId, {
|
|
|
555
555
|
|
|
556
556
|
const options = await listFilterOptions(client, frameNodeId, { groupOrder });
|
|
557
557
|
discoveredOptions = options.map((option) => ({
|
|
558
|
-
group: option.group,
|
|
559
|
-
label: option.label,
|
|
560
|
-
active: option.active,
|
|
561
|
-
node_id: option.node_id
|
|
562
|
-
}));
|
|
563
|
-
const selected = chooseFilterOptionByLabels(options, {
|
|
564
|
-
group,
|
|
565
|
-
labels: [label],
|
|
566
|
-
allowUnlimited
|
|
567
|
-
});
|
|
568
|
-
const alreadyActive = options.find((option) => (
|
|
569
|
-
(!group || option.group === group)
|
|
570
|
-
&& normalizeFilterOptionLabel(option.label) === normalizeFilterOptionLabel(label)
|
|
571
|
-
&& option.active
|
|
572
|
-
&& isSelectableFilterOptionLabel(option.label, { allowUnlimited })
|
|
573
|
-
));
|
|
574
|
-
|
|
575
|
-
if (alreadyActive) {
|
|
576
|
-
selectedOptions.push({
|
|
577
|
-
group: alreadyActive.group,
|
|
558
|
+
group: option.group,
|
|
559
|
+
label: option.label,
|
|
560
|
+
active: option.active,
|
|
561
|
+
node_id: option.node_id
|
|
562
|
+
}));
|
|
563
|
+
const selected = chooseFilterOptionByLabels(options, {
|
|
564
|
+
group,
|
|
565
|
+
labels: [label],
|
|
566
|
+
allowUnlimited
|
|
567
|
+
});
|
|
568
|
+
const alreadyActive = options.find((option) => (
|
|
569
|
+
(!group || option.group === group)
|
|
570
|
+
&& normalizeFilterOptionLabel(option.label) === normalizeFilterOptionLabel(label)
|
|
571
|
+
&& option.active
|
|
572
|
+
&& isSelectableFilterOptionLabel(option.label, { allowUnlimited })
|
|
573
|
+
));
|
|
574
|
+
|
|
575
|
+
if (alreadyActive) {
|
|
576
|
+
selectedOptions.push({
|
|
577
|
+
group: alreadyActive.group,
|
|
578
578
|
label: alreadyActive.label,
|
|
579
579
|
node_id: alreadyActive.node_id,
|
|
580
580
|
was_active: true,
|
|
@@ -601,113 +601,113 @@ export async function selectFilterOptions(client, frameNodeId, {
|
|
|
601
601
|
clicked: true,
|
|
602
602
|
requested_group: group || null,
|
|
603
603
|
option_box: box
|
|
604
|
-
});
|
|
605
|
-
await sleep(450);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (missingLabels.length) {
|
|
609
|
-
const groupOptions = discoveredOptions.filter((option) => !group || option.group === group);
|
|
610
|
-
const unavailableDefault = (
|
|
611
|
-
group === RECOMMEND_ACTIVITY_GROUP
|
|
612
|
-
&& allowUnlimited
|
|
613
|
-
&& missingLabels.length === 1
|
|
614
|
-
&& normalizeFilterOptionLabel(missingLabels[0]) === normalizeFilterOptionLabel("不限")
|
|
615
|
-
&& groupOptions.length === 0
|
|
616
|
-
);
|
|
617
|
-
if (unavailableDefault) {
|
|
618
|
-
return {
|
|
619
|
-
selected_option: null,
|
|
620
|
-
selected_options: [],
|
|
621
|
-
option_box: null,
|
|
622
|
-
unavailable: true,
|
|
623
|
-
unavailable_groups: [{
|
|
624
|
-
group,
|
|
625
|
-
requested_labels: labels,
|
|
626
|
-
reason: "activity_control_unavailable_default"
|
|
627
|
-
}],
|
|
628
|
-
discovered_options: discoveredOptions
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
throw new Error(`No matching recommend filter options were found for ${group || "any group"} / ${missingLabels.join(", ")}`);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
return {
|
|
635
|
-
selected_option: selectedOptions[0] || null,
|
|
604
|
+
});
|
|
605
|
+
await sleep(450);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (missingLabels.length) {
|
|
609
|
+
const groupOptions = discoveredOptions.filter((option) => !group || option.group === group);
|
|
610
|
+
const unavailableDefault = (
|
|
611
|
+
group === RECOMMEND_ACTIVITY_GROUP
|
|
612
|
+
&& allowUnlimited
|
|
613
|
+
&& missingLabels.length === 1
|
|
614
|
+
&& normalizeFilterOptionLabel(missingLabels[0]) === normalizeFilterOptionLabel("不限")
|
|
615
|
+
&& groupOptions.length === 0
|
|
616
|
+
);
|
|
617
|
+
if (unavailableDefault) {
|
|
618
|
+
return {
|
|
619
|
+
selected_option: null,
|
|
620
|
+
selected_options: [],
|
|
621
|
+
option_box: null,
|
|
622
|
+
unavailable: true,
|
|
623
|
+
unavailable_groups: [{
|
|
624
|
+
group,
|
|
625
|
+
requested_labels: labels,
|
|
626
|
+
reason: "activity_control_unavailable_default"
|
|
627
|
+
}],
|
|
628
|
+
discovered_options: discoveredOptions
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
throw new Error(`No matching recommend filter options were found for ${group || "any group"} / ${missingLabels.join(", ")}`);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return {
|
|
635
|
+
selected_option: selectedOptions[0] || null,
|
|
636
636
|
selected_options: selectedOptions.map((option) => ({
|
|
637
637
|
group: option.group,
|
|
638
638
|
label: option.label,
|
|
639
639
|
node_id: option.node_id,
|
|
640
640
|
was_active: option.was_active,
|
|
641
|
-
clicked: option.clicked,
|
|
642
|
-
requested_group: option.requested_group,
|
|
643
|
-
requested_labels: labels
|
|
644
|
-
})),
|
|
645
|
-
option_box: selectedOptions.find((option) => option.option_box)?.option_box || null,
|
|
646
|
-
unavailable: false,
|
|
647
|
-
unavailable_groups: [],
|
|
648
|
-
discovered_options: discoveredOptions
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
export async function selectFilterGroups(client, frameNodeId, {
|
|
653
|
-
filterGroups = [],
|
|
654
|
-
groupOrder = RECOMMEND_FILTER_GROUP_ORDER
|
|
655
|
-
} = {}) {
|
|
656
|
-
const selectedOptions = [];
|
|
657
|
-
const discoveredOptions = [];
|
|
658
|
-
const unavailableGroups = [];
|
|
659
|
-
const groups = filterGroups.filter((item) => item && (item.group || item.labels?.length));
|
|
660
|
-
if (!groups.length) {
|
|
661
|
-
return selectFilterOption(client, frameNodeId, { groupOrder });
|
|
662
|
-
}
|
|
663
|
-
|
|
641
|
+
clicked: option.clicked,
|
|
642
|
+
requested_group: option.requested_group,
|
|
643
|
+
requested_labels: labels
|
|
644
|
+
})),
|
|
645
|
+
option_box: selectedOptions.find((option) => option.option_box)?.option_box || null,
|
|
646
|
+
unavailable: false,
|
|
647
|
+
unavailable_groups: [],
|
|
648
|
+
discovered_options: discoveredOptions
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
export async function selectFilterGroups(client, frameNodeId, {
|
|
653
|
+
filterGroups = [],
|
|
654
|
+
groupOrder = RECOMMEND_FILTER_GROUP_ORDER
|
|
655
|
+
} = {}) {
|
|
656
|
+
const selectedOptions = [];
|
|
657
|
+
const discoveredOptions = [];
|
|
658
|
+
const unavailableGroups = [];
|
|
659
|
+
const groups = filterGroups.filter((item) => item && (item.group || item.labels?.length));
|
|
660
|
+
if (!groups.length) {
|
|
661
|
+
return selectFilterOption(client, frameNodeId, { groupOrder });
|
|
662
|
+
}
|
|
663
|
+
|
|
664
664
|
for (const spec of groups) {
|
|
665
|
-
const labels = Array.isArray(spec.labels) ? spec.labels : [];
|
|
666
|
-
const selection = spec.selectAllLabels === false
|
|
667
|
-
? await selectFilterOption(client, frameNodeId, {
|
|
668
|
-
group: spec.group || "",
|
|
669
|
-
labels,
|
|
670
|
-
groupOrder,
|
|
671
|
-
allowUnlimited: spec.allowUnlimited === true
|
|
672
|
-
})
|
|
673
|
-
: await selectFilterOptions(client, frameNodeId, {
|
|
674
|
-
group: spec.group || "",
|
|
675
|
-
labels,
|
|
676
|
-
groupOrder,
|
|
677
|
-
allowUnlimited: spec.allowUnlimited === true
|
|
678
|
-
});
|
|
679
|
-
if (selection.selected_option) selectedOptions.push(selection.selected_option);
|
|
680
|
-
for (const option of selection.selected_options || []) {
|
|
681
|
-
selectedOptions.push(option);
|
|
682
|
-
}
|
|
683
|
-
for (const option of selection.discovered_options || []) {
|
|
684
|
-
discoveredOptions.push(option);
|
|
685
|
-
}
|
|
686
|
-
for (const unavailable of selection.unavailable_groups || []) {
|
|
687
|
-
unavailableGroups.push(unavailable);
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
const dedupedSelected = [];
|
|
692
|
-
const seenSelected = new Set();
|
|
693
|
-
for (const option of selectedOptions) {
|
|
665
|
+
const labels = Array.isArray(spec.labels) ? spec.labels : [];
|
|
666
|
+
const selection = spec.selectAllLabels === false
|
|
667
|
+
? await selectFilterOption(client, frameNodeId, {
|
|
668
|
+
group: spec.group || "",
|
|
669
|
+
labels,
|
|
670
|
+
groupOrder,
|
|
671
|
+
allowUnlimited: spec.allowUnlimited === true
|
|
672
|
+
})
|
|
673
|
+
: await selectFilterOptions(client, frameNodeId, {
|
|
674
|
+
group: spec.group || "",
|
|
675
|
+
labels,
|
|
676
|
+
groupOrder,
|
|
677
|
+
allowUnlimited: spec.allowUnlimited === true
|
|
678
|
+
});
|
|
679
|
+
if (selection.selected_option) selectedOptions.push(selection.selected_option);
|
|
680
|
+
for (const option of selection.selected_options || []) {
|
|
681
|
+
selectedOptions.push(option);
|
|
682
|
+
}
|
|
683
|
+
for (const option of selection.discovered_options || []) {
|
|
684
|
+
discoveredOptions.push(option);
|
|
685
|
+
}
|
|
686
|
+
for (const unavailable of selection.unavailable_groups || []) {
|
|
687
|
+
unavailableGroups.push(unavailable);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const dedupedSelected = [];
|
|
692
|
+
const seenSelected = new Set();
|
|
693
|
+
for (const option of selectedOptions) {
|
|
694
694
|
const key = `${option.group || ""}:${normalizeFilterOptionLabel(option.label || "")}`;
|
|
695
695
|
if (seenSelected.has(key)) continue;
|
|
696
696
|
seenSelected.add(key);
|
|
697
697
|
dedupedSelected.push(option);
|
|
698
698
|
}
|
|
699
|
-
|
|
700
|
-
return {
|
|
701
|
-
selected_option: dedupedSelected[0] || null,
|
|
702
|
-
selected_options: dedupedSelected,
|
|
703
|
-
option_box: dedupedSelected.find((option) => option.option_box)?.option_box || null,
|
|
704
|
-
unavailable: unavailableGroups.length > 0,
|
|
705
|
-
unavailable_groups: unavailableGroups,
|
|
706
|
-
discovered_options: discoveredOptions
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
export async function confirmFilterPanel(client, frameNodeId, {
|
|
699
|
+
|
|
700
|
+
return {
|
|
701
|
+
selected_option: dedupedSelected[0] || null,
|
|
702
|
+
selected_options: dedupedSelected,
|
|
703
|
+
option_box: dedupedSelected.find((option) => option.option_box)?.option_box || null,
|
|
704
|
+
unavailable: unavailableGroups.length > 0,
|
|
705
|
+
unavailable_groups: unavailableGroups,
|
|
706
|
+
discovered_options: discoveredOptions
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
export async function confirmFilterPanel(client, frameNodeId, {
|
|
711
711
|
timeoutMs = 8000
|
|
712
712
|
} = {}) {
|
|
713
713
|
const candidates = await readConfirmButtonCandidates(client, frameNodeId);
|
|
@@ -759,223 +759,223 @@ export async function confirmFilterPanel(client, frameNodeId, {
|
|
|
759
759
|
confirm_node_id: attempts.at(-1)?.node_id || null,
|
|
760
760
|
confirm_label: attempts.at(-1)?.label || null,
|
|
761
761
|
confirm_candidates: candidates,
|
|
762
|
-
confirm_attempts: attempts,
|
|
763
|
-
panel_count: await getFilterPanelCount(client, frameNodeId)
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
function normalizeStickyVerificationSpecs(options = {}) {
|
|
768
|
-
const source = Array.isArray(options.filterGroups) && options.filterGroups.length
|
|
769
|
-
? options.filterGroups
|
|
770
|
-
: [options];
|
|
771
|
-
return source.filter((spec) => spec?.verifySticky === true).map((spec) => ({
|
|
772
|
-
group: String(spec.group || ""),
|
|
773
|
-
labels: Array.isArray(spec.labels) ? spec.labels : [],
|
|
774
|
-
selectAllLabels: spec.selectAllLabels !== false,
|
|
775
|
-
allowUnlimited: spec.allowUnlimited === true
|
|
776
|
-
})).filter((spec) => spec.group && spec.labels.length);
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
function findUnavailableGroup(unavailableGroups = [], group = "") {
|
|
780
|
-
return unavailableGroups.find((item) => item?.group === group) || null;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
function normalizeRequestedFilterGroups(options = {}) {
|
|
784
|
-
const source = Array.isArray(options.filterGroups) && options.filterGroups.length
|
|
785
|
-
? options.filterGroups.filter(Boolean)
|
|
786
|
-
: (options.group || options.labels?.length ? [options] : []);
|
|
787
|
-
return source.map((spec) => ({
|
|
788
|
-
group: String(spec?.group || ""),
|
|
789
|
-
labels: Array.isArray(spec?.labels)
|
|
790
|
-
? spec.labels.map(normalizeFilterOptionLabel).filter(Boolean)
|
|
791
|
-
: [],
|
|
792
|
-
select_all_labels: spec?.selectAllLabels !== false,
|
|
793
|
-
allow_unlimited: spec?.allowUnlimited === true,
|
|
794
|
-
verify_sticky: spec?.verifySticky === true
|
|
795
|
-
}));
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
export async function verifyFilterGroupsSticky(client, frameNodeId, {
|
|
799
|
-
specs = [],
|
|
800
|
-
unavailableGroups = [],
|
|
801
|
-
settleMs = 300
|
|
802
|
-
} = {}) {
|
|
803
|
-
const normalizedSpecs = specs.filter((spec) => spec?.group && Array.isArray(spec.labels) && spec.labels.length);
|
|
804
|
-
const groups = [];
|
|
805
|
-
const availableSpecs = [];
|
|
806
|
-
for (const spec of normalizedSpecs) {
|
|
807
|
-
const unavailable = findUnavailableGroup(unavailableGroups, spec.group);
|
|
808
|
-
if (unavailable) {
|
|
809
|
-
groups.push({
|
|
810
|
-
group: spec.group,
|
|
811
|
-
requested_labels: spec.labels,
|
|
812
|
-
active_labels: [],
|
|
813
|
-
verified: true,
|
|
814
|
-
unavailable: true,
|
|
815
|
-
reason: unavailable.reason || "control_unavailable_default"
|
|
816
|
-
});
|
|
817
|
-
} else {
|
|
818
|
-
availableSpecs.push(spec);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
let reopen = null;
|
|
823
|
-
let closeConfirmation = null;
|
|
824
|
-
if (availableSpecs.length) {
|
|
825
|
-
reopen = await openFilterPanel(client, frameNodeId);
|
|
826
|
-
for (const spec of availableSpecs) {
|
|
827
|
-
const options = await listFilterOptions(client, frameNodeId, {
|
|
828
|
-
groupOrder: [spec.group]
|
|
829
|
-
});
|
|
830
|
-
const requestedLabels = spec.labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
831
|
-
const activeLabels = options
|
|
832
|
-
.filter((option) => option.group === spec.group && option.active)
|
|
833
|
-
.map((option) => normalizeFilterOptionLabel(option.label));
|
|
834
|
-
const verified = spec.selectAllLabels === false
|
|
835
|
-
? requestedLabels.length === 1
|
|
836
|
-
&& activeLabels.length === 1
|
|
837
|
-
&& activeLabels[0] === requestedLabels[0]
|
|
838
|
-
: requestedLabels.every((label) => activeLabels.includes(label));
|
|
839
|
-
groups.push({
|
|
840
|
-
group: spec.group,
|
|
841
|
-
requested_labels: requestedLabels,
|
|
842
|
-
active_labels: activeLabels,
|
|
843
|
-
verified,
|
|
844
|
-
unavailable: false,
|
|
845
|
-
single_select: spec.selectAllLabels === false,
|
|
846
|
-
discovered_options: options.map((option) => ({
|
|
847
|
-
label: option.label,
|
|
848
|
-
active: option.active,
|
|
849
|
-
node_id: option.node_id
|
|
850
|
-
}))
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
closeConfirmation = await confirmFilterPanel(client, frameNodeId);
|
|
854
|
-
if (!closeConfirmation.confirmed) {
|
|
855
|
-
throw new Error("Recommend filter sticky verification panel could not be closed");
|
|
856
|
-
}
|
|
857
|
-
if (settleMs > 0) await sleep(settleMs);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
const verified = groups.length === normalizedSpecs.length && groups.every((item) => item.verified);
|
|
861
|
-
const result = {
|
|
862
|
-
verified,
|
|
863
|
-
groups,
|
|
864
|
-
reopened: Boolean(reopen),
|
|
865
|
-
reopen_panel_node_id: reopen?.panel_node_id || null,
|
|
866
|
-
close_confirmation: closeConfirmation
|
|
867
|
-
? {
|
|
868
|
-
confirmed: closeConfirmation.confirmed,
|
|
869
|
-
label: closeConfirmation.confirm_label,
|
|
870
|
-
node_id: closeConfirmation.confirm_node_id
|
|
871
|
-
}
|
|
872
|
-
: null
|
|
873
|
-
};
|
|
874
|
-
if (!verified) {
|
|
875
|
-
const failedGroups = groups.filter((item) => !item.verified).map((item) => item.group);
|
|
876
|
-
const error = new Error(`Recommend filter sticky verification failed for: ${failedGroups.join(", ")}`);
|
|
877
|
-
error.sticky_verification = result;
|
|
878
|
-
throw error;
|
|
879
|
-
}
|
|
880
|
-
return result;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
export async function selectAndConfirmFirstSafeFilter(client, frameNodeId, options = {}) {
|
|
884
|
-
const beforeCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
885
|
-
const requestedGroups = normalizeRequestedFilterGroups(options);
|
|
886
|
-
let openResult;
|
|
887
|
-
try {
|
|
888
|
-
openResult = await openFilterPanel(client, frameNodeId);
|
|
889
|
-
} catch (error) {
|
|
890
|
-
const onlyGroup = requestedGroups.length === 1 ? requestedGroups[0] : null;
|
|
891
|
-
const requestedLabels = onlyGroup?.labels || [];
|
|
892
|
-
const unavailableActivityDefault = (
|
|
893
|
-
error?.code === "RECOMMEND_FILTER_TRIGGER_UNAVAILABLE"
|
|
894
|
-
&& normalizeText(onlyGroup?.group) === RECOMMEND_ACTIVITY_GROUP
|
|
895
|
-
&& onlyGroup?.allow_unlimited === true
|
|
896
|
-
&& requestedLabels.length === 1
|
|
897
|
-
&& requestedLabels[0] === normalizeFilterOptionLabel("不限")
|
|
898
|
-
);
|
|
899
|
-
if (!unavailableActivityDefault) throw error;
|
|
900
|
-
|
|
901
|
-
const unavailableGroups = [{
|
|
902
|
-
group: RECOMMEND_ACTIVITY_GROUP,
|
|
903
|
-
requested_labels: requestedLabels,
|
|
904
|
-
reason: "activity_control_unavailable_default",
|
|
905
|
-
scope: "filter_panel"
|
|
906
|
-
}];
|
|
907
|
-
const stickySpecs = normalizeStickyVerificationSpecs(options);
|
|
908
|
-
const stickyVerification = stickySpecs.length
|
|
909
|
-
? await verifyFilterGroupsSticky(client, frameNodeId, {
|
|
910
|
-
specs: stickySpecs,
|
|
911
|
-
unavailableGroups,
|
|
912
|
-
settleMs: 0
|
|
913
|
-
})
|
|
914
|
-
: null;
|
|
915
|
-
const afterCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
916
|
-
return {
|
|
917
|
-
opened_panel: false,
|
|
918
|
-
trigger: null,
|
|
919
|
-
initial_close_attempts: [],
|
|
920
|
-
open_attempts: [],
|
|
921
|
-
before_counts: beforeCounts,
|
|
922
|
-
after_open_counts: afterCounts,
|
|
923
|
-
requested_groups: requestedGroups,
|
|
924
|
-
selected_option: null,
|
|
925
|
-
selected_options: [],
|
|
926
|
-
option_box: null,
|
|
927
|
-
unavailable: true,
|
|
928
|
-
unavailable_default: true,
|
|
929
|
-
unavailable_groups: unavailableGroups,
|
|
930
|
-
discovered_options: [],
|
|
931
|
-
confirmed: true,
|
|
932
|
-
confirm_node_id: null,
|
|
933
|
-
confirm_label: "unavailable-default",
|
|
934
|
-
confirm_candidates: [],
|
|
935
|
-
confirm_attempts: [],
|
|
936
|
-
panel_count: Number(afterCounts.filter_panel || 0),
|
|
937
|
-
sticky_verification: stickyVerification,
|
|
938
|
-
after_confirm_counts: afterCounts
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
const afterOpenCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
942
|
-
const filterGroups = Array.isArray(options.filterGroups) ? options.filterGroups : [];
|
|
762
|
+
confirm_attempts: attempts,
|
|
763
|
+
panel_count: await getFilterPanelCount(client, frameNodeId)
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function normalizeStickyVerificationSpecs(options = {}) {
|
|
768
|
+
const source = Array.isArray(options.filterGroups) && options.filterGroups.length
|
|
769
|
+
? options.filterGroups
|
|
770
|
+
: [options];
|
|
771
|
+
return source.filter((spec) => spec?.verifySticky === true).map((spec) => ({
|
|
772
|
+
group: String(spec.group || ""),
|
|
773
|
+
labels: Array.isArray(spec.labels) ? spec.labels : [],
|
|
774
|
+
selectAllLabels: spec.selectAllLabels !== false,
|
|
775
|
+
allowUnlimited: spec.allowUnlimited === true
|
|
776
|
+
})).filter((spec) => spec.group && spec.labels.length);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
function findUnavailableGroup(unavailableGroups = [], group = "") {
|
|
780
|
+
return unavailableGroups.find((item) => item?.group === group) || null;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
function normalizeRequestedFilterGroups(options = {}) {
|
|
784
|
+
const source = Array.isArray(options.filterGroups) && options.filterGroups.length
|
|
785
|
+
? options.filterGroups.filter(Boolean)
|
|
786
|
+
: (options.group || options.labels?.length ? [options] : []);
|
|
787
|
+
return source.map((spec) => ({
|
|
788
|
+
group: String(spec?.group || ""),
|
|
789
|
+
labels: Array.isArray(spec?.labels)
|
|
790
|
+
? spec.labels.map(normalizeFilterOptionLabel).filter(Boolean)
|
|
791
|
+
: [],
|
|
792
|
+
select_all_labels: spec?.selectAllLabels !== false,
|
|
793
|
+
allow_unlimited: spec?.allowUnlimited === true,
|
|
794
|
+
verify_sticky: spec?.verifySticky === true
|
|
795
|
+
}));
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
export async function verifyFilterGroupsSticky(client, frameNodeId, {
|
|
799
|
+
specs = [],
|
|
800
|
+
unavailableGroups = [],
|
|
801
|
+
settleMs = 300
|
|
802
|
+
} = {}) {
|
|
803
|
+
const normalizedSpecs = specs.filter((spec) => spec?.group && Array.isArray(spec.labels) && spec.labels.length);
|
|
804
|
+
const groups = [];
|
|
805
|
+
const availableSpecs = [];
|
|
806
|
+
for (const spec of normalizedSpecs) {
|
|
807
|
+
const unavailable = findUnavailableGroup(unavailableGroups, spec.group);
|
|
808
|
+
if (unavailable) {
|
|
809
|
+
groups.push({
|
|
810
|
+
group: spec.group,
|
|
811
|
+
requested_labels: spec.labels,
|
|
812
|
+
active_labels: [],
|
|
813
|
+
verified: true,
|
|
814
|
+
unavailable: true,
|
|
815
|
+
reason: unavailable.reason || "control_unavailable_default"
|
|
816
|
+
});
|
|
817
|
+
} else {
|
|
818
|
+
availableSpecs.push(spec);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
let reopen = null;
|
|
823
|
+
let closeConfirmation = null;
|
|
824
|
+
if (availableSpecs.length) {
|
|
825
|
+
reopen = await openFilterPanel(client, frameNodeId);
|
|
826
|
+
for (const spec of availableSpecs) {
|
|
827
|
+
const options = await listFilterOptions(client, frameNodeId, {
|
|
828
|
+
groupOrder: [spec.group]
|
|
829
|
+
});
|
|
830
|
+
const requestedLabels = spec.labels.map(normalizeFilterOptionLabel).filter(Boolean);
|
|
831
|
+
const activeLabels = options
|
|
832
|
+
.filter((option) => option.group === spec.group && option.active)
|
|
833
|
+
.map((option) => normalizeFilterOptionLabel(option.label));
|
|
834
|
+
const verified = spec.selectAllLabels === false
|
|
835
|
+
? requestedLabels.length === 1
|
|
836
|
+
&& activeLabels.length === 1
|
|
837
|
+
&& activeLabels[0] === requestedLabels[0]
|
|
838
|
+
: requestedLabels.every((label) => activeLabels.includes(label));
|
|
839
|
+
groups.push({
|
|
840
|
+
group: spec.group,
|
|
841
|
+
requested_labels: requestedLabels,
|
|
842
|
+
active_labels: activeLabels,
|
|
843
|
+
verified,
|
|
844
|
+
unavailable: false,
|
|
845
|
+
single_select: spec.selectAllLabels === false,
|
|
846
|
+
discovered_options: options.map((option) => ({
|
|
847
|
+
label: option.label,
|
|
848
|
+
active: option.active,
|
|
849
|
+
node_id: option.node_id
|
|
850
|
+
}))
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
closeConfirmation = await confirmFilterPanel(client, frameNodeId);
|
|
854
|
+
if (!closeConfirmation.confirmed) {
|
|
855
|
+
throw new Error("Recommend filter sticky verification panel could not be closed");
|
|
856
|
+
}
|
|
857
|
+
if (settleMs > 0) await sleep(settleMs);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const verified = groups.length === normalizedSpecs.length && groups.every((item) => item.verified);
|
|
861
|
+
const result = {
|
|
862
|
+
verified,
|
|
863
|
+
groups,
|
|
864
|
+
reopened: Boolean(reopen),
|
|
865
|
+
reopen_panel_node_id: reopen?.panel_node_id || null,
|
|
866
|
+
close_confirmation: closeConfirmation
|
|
867
|
+
? {
|
|
868
|
+
confirmed: closeConfirmation.confirmed,
|
|
869
|
+
label: closeConfirmation.confirm_label,
|
|
870
|
+
node_id: closeConfirmation.confirm_node_id
|
|
871
|
+
}
|
|
872
|
+
: null
|
|
873
|
+
};
|
|
874
|
+
if (!verified) {
|
|
875
|
+
const failedGroups = groups.filter((item) => !item.verified).map((item) => item.group);
|
|
876
|
+
const error = new Error(`Recommend filter sticky verification failed for: ${failedGroups.join(", ")}`);
|
|
877
|
+
error.sticky_verification = result;
|
|
878
|
+
throw error;
|
|
879
|
+
}
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
export async function selectAndConfirmFirstSafeFilter(client, frameNodeId, options = {}) {
|
|
884
|
+
const beforeCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
885
|
+
const requestedGroups = normalizeRequestedFilterGroups(options);
|
|
886
|
+
let openResult;
|
|
887
|
+
try {
|
|
888
|
+
openResult = await openFilterPanel(client, frameNodeId);
|
|
889
|
+
} catch (error) {
|
|
890
|
+
const onlyGroup = requestedGroups.length === 1 ? requestedGroups[0] : null;
|
|
891
|
+
const requestedLabels = onlyGroup?.labels || [];
|
|
892
|
+
const unavailableActivityDefault = (
|
|
893
|
+
error?.code === "RECOMMEND_FILTER_TRIGGER_UNAVAILABLE"
|
|
894
|
+
&& normalizeText(onlyGroup?.group) === RECOMMEND_ACTIVITY_GROUP
|
|
895
|
+
&& onlyGroup?.allow_unlimited === true
|
|
896
|
+
&& requestedLabels.length === 1
|
|
897
|
+
&& requestedLabels[0] === normalizeFilterOptionLabel("不限")
|
|
898
|
+
);
|
|
899
|
+
if (!unavailableActivityDefault) throw error;
|
|
900
|
+
|
|
901
|
+
const unavailableGroups = [{
|
|
902
|
+
group: RECOMMEND_ACTIVITY_GROUP,
|
|
903
|
+
requested_labels: requestedLabels,
|
|
904
|
+
reason: "activity_control_unavailable_default",
|
|
905
|
+
scope: "filter_panel"
|
|
906
|
+
}];
|
|
907
|
+
const stickySpecs = normalizeStickyVerificationSpecs(options);
|
|
908
|
+
const stickyVerification = stickySpecs.length
|
|
909
|
+
? await verifyFilterGroupsSticky(client, frameNodeId, {
|
|
910
|
+
specs: stickySpecs,
|
|
911
|
+
unavailableGroups,
|
|
912
|
+
settleMs: 0
|
|
913
|
+
})
|
|
914
|
+
: null;
|
|
915
|
+
const afterCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
916
|
+
return {
|
|
917
|
+
opened_panel: false,
|
|
918
|
+
trigger: null,
|
|
919
|
+
initial_close_attempts: [],
|
|
920
|
+
open_attempts: [],
|
|
921
|
+
before_counts: beforeCounts,
|
|
922
|
+
after_open_counts: afterCounts,
|
|
923
|
+
requested_groups: requestedGroups,
|
|
924
|
+
selected_option: null,
|
|
925
|
+
selected_options: [],
|
|
926
|
+
option_box: null,
|
|
927
|
+
unavailable: true,
|
|
928
|
+
unavailable_default: true,
|
|
929
|
+
unavailable_groups: unavailableGroups,
|
|
930
|
+
discovered_options: [],
|
|
931
|
+
confirmed: true,
|
|
932
|
+
confirm_node_id: null,
|
|
933
|
+
confirm_label: "unavailable-default",
|
|
934
|
+
confirm_candidates: [],
|
|
935
|
+
confirm_attempts: [],
|
|
936
|
+
panel_count: Number(afterCounts.filter_panel || 0),
|
|
937
|
+
sticky_verification: stickyVerification,
|
|
938
|
+
after_confirm_counts: afterCounts
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
const afterOpenCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
942
|
+
const filterGroups = Array.isArray(options.filterGroups) ? options.filterGroups : [];
|
|
943
943
|
const selection = filterGroups.length
|
|
944
|
-
? await selectFilterGroups(client, frameNodeId, { filterGroups, groupOrder: options.groupOrder })
|
|
945
|
-
: options.selectAllLabels
|
|
946
|
-
? await selectFilterOptions(client, frameNodeId, options)
|
|
947
|
-
: await selectFilterOption(client, frameNodeId, options);
|
|
948
|
-
const confirm = await confirmFilterPanel(client, frameNodeId);
|
|
949
|
-
const stickySpecs = normalizeStickyVerificationSpecs(options);
|
|
950
|
-
const stickyVerification = confirm.confirmed && stickySpecs.length
|
|
951
|
-
? await verifyFilterGroupsSticky(client, frameNodeId, {
|
|
952
|
-
specs: stickySpecs,
|
|
953
|
-
unavailableGroups: selection.unavailable_groups || [],
|
|
954
|
-
settleMs: Number.isFinite(options.stickySettleMs) ? Math.max(0, options.stickySettleMs) : 300
|
|
955
|
-
})
|
|
956
|
-
: null;
|
|
957
|
-
const afterConfirmSettleMs = Number.isFinite(options.afterConfirmSettleMs)
|
|
958
|
-
? Math.max(0, options.afterConfirmSettleMs)
|
|
959
|
-
: 1200;
|
|
960
|
-
if (afterConfirmSettleMs > 0) await sleep(afterConfirmSettleMs);
|
|
961
|
-
const afterConfirmCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
962
|
-
|
|
963
|
-
return {
|
|
964
|
-
opened_panel: true,
|
|
965
|
-
requested_groups: requestedGroups,
|
|
966
|
-
trigger: {
|
|
944
|
+
? await selectFilterGroups(client, frameNodeId, { filterGroups, groupOrder: options.groupOrder })
|
|
945
|
+
: options.selectAllLabels
|
|
946
|
+
? await selectFilterOptions(client, frameNodeId, options)
|
|
947
|
+
: await selectFilterOption(client, frameNodeId, options);
|
|
948
|
+
const confirm = await confirmFilterPanel(client, frameNodeId);
|
|
949
|
+
const stickySpecs = normalizeStickyVerificationSpecs(options);
|
|
950
|
+
const stickyVerification = confirm.confirmed && stickySpecs.length
|
|
951
|
+
? await verifyFilterGroupsSticky(client, frameNodeId, {
|
|
952
|
+
specs: stickySpecs,
|
|
953
|
+
unavailableGroups: selection.unavailable_groups || [],
|
|
954
|
+
settleMs: Number.isFinite(options.stickySettleMs) ? Math.max(0, options.stickySettleMs) : 300
|
|
955
|
+
})
|
|
956
|
+
: null;
|
|
957
|
+
const afterConfirmSettleMs = Number.isFinite(options.afterConfirmSettleMs)
|
|
958
|
+
? Math.max(0, options.afterConfirmSettleMs)
|
|
959
|
+
: 1200;
|
|
960
|
+
if (afterConfirmSettleMs > 0) await sleep(afterConfirmSettleMs);
|
|
961
|
+
const afterConfirmCounts = await getRecommendFilterCounts(client, frameNodeId);
|
|
962
|
+
|
|
963
|
+
return {
|
|
964
|
+
opened_panel: true,
|
|
965
|
+
requested_groups: requestedGroups,
|
|
966
|
+
trigger: {
|
|
967
967
|
node_id: openResult.trigger.nodeId,
|
|
968
968
|
selector: openResult.trigger.selector,
|
|
969
969
|
center: openResult.trigger_box.center,
|
|
970
970
|
rect: openResult.trigger_box.rect
|
|
971
|
-
},
|
|
972
|
-
initial_close_attempts: openResult.initial_close_attempts,
|
|
973
|
-
open_attempts: openResult.open_attempts || [],
|
|
974
|
-
before_counts: beforeCounts,
|
|
975
|
-
after_open_counts: afterOpenCounts,
|
|
976
|
-
...selection,
|
|
977
|
-
...confirm,
|
|
978
|
-
sticky_verification: stickyVerification,
|
|
979
|
-
after_confirm_counts: afterConfirmCounts
|
|
980
|
-
};
|
|
981
|
-
}
|
|
971
|
+
},
|
|
972
|
+
initial_close_attempts: openResult.initial_close_attempts,
|
|
973
|
+
open_attempts: openResult.open_attempts || [],
|
|
974
|
+
before_counts: beforeCounts,
|
|
975
|
+
after_open_counts: afterOpenCounts,
|
|
976
|
+
...selection,
|
|
977
|
+
...confirm,
|
|
978
|
+
sticky_verification: stickyVerification,
|
|
979
|
+
after_confirm_counts: afterConfirmCounts
|
|
980
|
+
};
|
|
981
|
+
}
|