@qingflow-tech/qingflow-app-user-mcp 1.0.9 → 1.0.11

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.
@@ -5,6 +5,215 @@ import re
5
5
 
6
6
 
7
7
  DEFAULT_ICON_COLOR = "qing-orange"
8
+ WORKSPACE_ICON_COLORS: tuple[str, ...] = (
9
+ "qing-orange",
10
+ "yellow",
11
+ "green",
12
+ "emerald",
13
+ "blue",
14
+ "azure",
15
+ "indigo",
16
+ "qing-purple",
17
+ "purple",
18
+ "pink",
19
+ "red",
20
+ "orange",
21
+ )
22
+ WORKSPACE_ICON_NAMES: tuple[str, ...] = (
23
+ "user",
24
+ "user-group",
25
+ "user-remove",
26
+ "user-add",
27
+ "user-circle",
28
+ "base-camera",
29
+ "view-grid",
30
+ "inbox",
31
+ "inbox-in",
32
+ "share",
33
+ "sitemap",
34
+ "airplane",
35
+ "template",
36
+ "music-note",
37
+ "movie-play",
38
+ "clock",
39
+ "document",
40
+ "document-search",
41
+ "clipboard-check",
42
+ "document-download",
43
+ "document-text",
44
+ "clipboard-copy",
45
+ "presentation-chart-bar",
46
+ "chart-square-bar",
47
+ "database",
48
+ "server",
49
+ "calendar",
50
+ "mail",
51
+ "annotation",
52
+ "chat",
53
+ "bell",
54
+ "key",
55
+ "shopping-bag",
56
+ "download",
57
+ "eye",
58
+ "eye-off",
59
+ "emoji-happy",
60
+ "emoji-sad",
61
+ "sun",
62
+ "moon",
63
+ "cloud",
64
+ "lightning-bolt",
65
+ "fire",
66
+ "star",
67
+ "sparkles",
68
+ "heart",
69
+ "cake",
70
+ "gift",
71
+ "light-bulb",
72
+ "exclamation",
73
+ "cog",
74
+ "thumb-up",
75
+ "thumb-down",
76
+ "cloud-download",
77
+ "cloud-upload",
78
+ "printer",
79
+ "phone-incoming",
80
+ "phone-missed-call",
81
+ "terminal",
82
+ "search-circle",
83
+ "x-circle",
84
+ "check-circle",
85
+ "exclamation-circle",
86
+ "question-mark-circle",
87
+ "information-circle",
88
+ "academic-cap",
89
+ "briefcase",
90
+ "home",
91
+ "phone",
92
+ "photograph",
93
+ "puzzle",
94
+ "color-swatch",
95
+ "lock-open",
96
+ "lock-closed",
97
+ "shield-check",
98
+ "shield-exclamation",
99
+ "currency-dollar",
100
+ "currency-yen",
101
+ "globe",
102
+ "at-symbol",
103
+ "slack",
104
+ "microphone",
105
+ "speakerphone",
106
+ "trash",
107
+ "book-open",
108
+ "truck",
109
+ "filter",
110
+ "essetional-filter-search",
111
+ "essetional-filter-tick",
112
+ "table",
113
+ "calculator",
114
+ "location-radar",
115
+ "essetional-weight",
116
+ "school-award",
117
+ "comp-cloud-connection",
118
+ "comp-cloud-remove",
119
+ "comp-cpu-charge",
120
+ "comp-cpu-setting",
121
+ "comp-cpu",
122
+ "comp-devices",
123
+ "comp-driver-2",
124
+ "comp-driver-refresh",
125
+ "location-global",
126
+ "location-location",
127
+ "location-map",
128
+ "location-gps",
129
+ "essetional-ranking",
130
+ "chart-bar",
131
+ "business-graph",
132
+ "business-status-up",
133
+ "business-trend-down",
134
+ "business-trend-up",
135
+ "business-presention-chart",
136
+ "business-favorite-chart",
137
+ "business-health",
138
+ "receipt-refund",
139
+ "receipt-tax",
140
+ "money-receipt-2-1",
141
+ "money-transaction-minus",
142
+ "action-hourglass-full",
143
+ "action-work",
144
+ "bug-f",
145
+ "essetional-pet",
146
+ "files-folder",
147
+ "badge-check",
148
+ "money-wallet-1",
149
+ "money-ticket",
150
+ "money-money",
151
+ "money-tag",
152
+ "money-wallet-2",
153
+ "business-personalcard",
154
+ "car-airplane",
155
+ "car-bus",
156
+ "car-car",
157
+ "car-driving",
158
+ "car-gas-station",
159
+ "car-smart-car",
160
+ "car-ship",
161
+ "location-map-1",
162
+ "location-route-square",
163
+ "cone",
164
+ "design-brush-4",
165
+ "paint-roll",
166
+ "wrench-f",
167
+ "essetional-reserve",
168
+ "essetional-broom",
169
+ "design-brush-2",
170
+ "essetional-judge",
171
+ "design-bucket",
172
+ "palette",
173
+ "comp-electricity",
174
+ "vial",
175
+ "beaker",
176
+ "leaf-f",
177
+ "cursor-click",
178
+ "solid-search-alt-2",
179
+ "md-library",
180
+ "building-3",
181
+ "office-building",
182
+ "building-hospital",
183
+ "school",
184
+ "store",
185
+ "video-camera-vintage-f",
186
+ "comp-monitor",
187
+ "delivery-truck",
188
+ "delivery-box-1",
189
+ "delivery-box-add",
190
+ "delivery-box-remove",
191
+ "settings-setting-3",
192
+ "document-duplicate",
193
+ "essetional-flag-2",
194
+ "flag",
195
+ "icon-currency-dollar",
196
+ "clipboard-list",
197
+ "save-as",
198
+ "wifi",
199
+ "status-online",
200
+ "scissors",
201
+ "globe-alt",
202
+ "ban",
203
+ "finger-print",
204
+ "qrcode",
205
+ "paper-clip",
206
+ "translate",
207
+ "cube-transparent",
208
+ "variable",
209
+ "switch-vertical",
210
+ "sports-baseball",
211
+ "sports-basketball",
212
+ "sports-soccer",
213
+ "sports-football",
214
+ "sports-volleyball",
215
+ )
216
+ GENERIC_WORKSPACE_ICON_NAMES: tuple[str, ...] = ("template",)
8
217
  DEFAULT_ICON_STYLE_POOL: tuple[tuple[str, str], ...] = (
9
218
  ("briefcase", "qing-orange"),
10
219
  ("calendar", "emerald"),
@@ -115,6 +324,91 @@ def parse_workspace_icon(value: str | None) -> tuple[str | None, str | None, str
115
324
  return normalize_workspace_icon_name(stripped), None, None
116
325
 
117
326
 
327
+ def workspace_icon_config(value: str | None) -> dict[str, str | None]:
328
+ icon_name, icon_color, icon_text = parse_workspace_icon(value)
329
+ raw = str(value).strip() if value not in (None, "") else None
330
+ return {
331
+ "icon_name": icon_name,
332
+ "icon_color": icon_color,
333
+ "icon_text": icon_text,
334
+ "raw": raw,
335
+ }
336
+
337
+
338
+ def workspace_icon_catalog_payload() -> dict[str, object]:
339
+ return {
340
+ "icon_names": list(WORKSPACE_ICON_NAMES),
341
+ "icon_colors": list(WORKSPACE_ICON_COLORS),
342
+ "generic_icon_names": list(GENERIC_WORKSPACE_ICON_NAMES),
343
+ "notes": [
344
+ "Use explicit icon + color for app/package/portal creation.",
345
+ "Do not use template for newly created workspace resources.",
346
+ "The CLI validates candidates only; it does not infer an icon from business names.",
347
+ ],
348
+ "common_examples": {
349
+ "employee": ["business-personalcard", "user-group", "user"],
350
+ "task": ["clipboard-check", "action-work"],
351
+ "worklog": ["clock", "action-hourglass-full"],
352
+ "order": ["delivery-box-1", "shopping-bag"],
353
+ "payment": ["money-receipt-2-1", "money-wallet-1"],
354
+ "opportunity": ["business-graph", "business-trend-up"],
355
+ "dashboard": ["view-grid", "chart-square-bar", "presentation-chart-bar"],
356
+ },
357
+ }
358
+
359
+
360
+ def validate_workspace_icon_choice(
361
+ *,
362
+ icon: str | None,
363
+ color: str | None,
364
+ require_explicit: bool,
365
+ disallow_generic: bool,
366
+ ) -> tuple[bool, str | None, str | None, dict[str, object]]:
367
+ normalized_icon = _normalize_workspace_icon_candidate(icon)
368
+ normalized_color = str(color or "").strip() or None
369
+ details: dict[str, object] = {
370
+ "icon": icon,
371
+ "normalized_icon": normalized_icon,
372
+ "color": color,
373
+ "icon_catalog_command": "qingflow --json builder icon catalog",
374
+ }
375
+ if require_explicit and not normalized_icon:
376
+ return False, "WORKSPACE_ICON_REQUIRED", "icon is required when creating a workspace resource", details
377
+ if require_explicit and not normalized_color:
378
+ return False, "WORKSPACE_ICON_COLOR_REQUIRED", "color is required when creating a workspace resource", details
379
+ if normalized_icon and normalized_icon not in WORKSPACE_ICON_NAMES:
380
+ details["allowed_icon_names"] = list(WORKSPACE_ICON_NAMES)
381
+ return False, "WORKSPACE_ICON_NOT_FOUND", "icon is not in the workspace icon catalog", details
382
+ if normalized_color and normalized_color not in WORKSPACE_ICON_COLORS:
383
+ details["allowed_icon_colors"] = list(WORKSPACE_ICON_COLORS)
384
+ return False, "WORKSPACE_ICON_COLOR_NOT_FOUND", "color is not in the workspace icon color catalog", details
385
+ if disallow_generic and normalized_icon in GENERIC_WORKSPACE_ICON_NAMES:
386
+ details["generic_icon_names"] = list(GENERIC_WORKSPACE_ICON_NAMES)
387
+ return False, "GENERIC_WORKSPACE_ICON_NOT_ALLOWED", "template is a generic icon and is not allowed for new workspace resources", details
388
+ return True, None, None, details
389
+
390
+
391
+ def _normalize_workspace_icon_candidate(icon: str | None) -> str | None:
392
+ if not icon:
393
+ return None
394
+ raw = str(icon).strip()
395
+ if not raw:
396
+ return None
397
+ if _looks_like_icon_json(raw):
398
+ try:
399
+ payload = json.loads(raw)
400
+ except Exception:
401
+ return None
402
+ return _normalize_workspace_icon_candidate(payload.get("iconName"))
403
+ normalized = raw.lower()
404
+ if normalized in WORKSPACE_ICON_NAMES:
405
+ return normalized
406
+ legacy = LEGACY_EX_ICON_MAP.get(normalized)
407
+ if legacy in WORKSPACE_ICON_NAMES:
408
+ return legacy
409
+ return normalized
410
+
411
+
118
412
  def encode_workspace_icon_with_defaults(
119
413
  *,
120
414
  icon: str | None,