* @brief Walks workspace widget refs and reports orphans + unreferenced groups. */
| 1248 | * @brief Walks workspace widget refs and reports orphans + unreferenced groups. |
| 1249 | */ |
| 1250 | API::CommandResponse API::Handlers::WorkspacesHandler::validate(const QString& id, |
| 1251 | const QJsonObject& params) |
| 1252 | { |
| 1253 | const auto& pm = DataModel::ProjectModel::instance(); |
| 1254 | const auto& wsList = pm.editorWorkspaces(); |
| 1255 | const auto lookup = DataModel::ProjectEditor::buildResolvedWidgetLookup(pm); |
| 1256 | |
| 1257 | const bool filtered = params.contains(QStringLiteral("workspaceId")); |
| 1258 | const int onlyWid = filtered ? params.value(QStringLiteral("workspaceId")).toInt() : -1; |
| 1259 | |
| 1260 | QJsonArray issues; |
| 1261 | int orphanedCount = 0; |
| 1262 | int workspaceCount = 0; |
| 1263 | QSet<int> referencedGroups; |
| 1264 | bool ok = true; |
| 1265 | |
| 1266 | for (const auto& ws : wsList) { |
| 1267 | if (filtered && ws.workspaceId != onlyWid) |
| 1268 | continue; |
| 1269 | |
| 1270 | ++workspaceCount; |
| 1271 | int refIndex = 0; |
| 1272 | for (const auto& ref : ws.widgetRefs) { |
| 1273 | referencedGroups.insert(ref.groupUniqueId); |
| 1274 | const auto key = DataModel::ProjectEditor::workspaceWidgetKey( |
| 1275 | ref.widgetType, ref.groupUniqueId, ref.relativeIndex); |
| 1276 | if (!lookup.contains(key)) { |
| 1277 | ++orphanedCount; |
| 1278 | ok = false; |
| 1279 | QJsonObject issue; |
| 1280 | issue[QStringLiteral("level")] = QStringLiteral("error"); |
| 1281 | issue[QStringLiteral("location")] = |
| 1282 | QStringLiteral("workspace[%1].widgetRef[%2]") |
| 1283 | .arg(QString::number(ws.workspaceId), QString::number(refIndex)); |
| 1284 | issue[QStringLiteral("workspaceId")] = ws.workspaceId; |
| 1285 | issue[QStringLiteral("widgetType")] = ref.widgetType; |
| 1286 | issue[QStringLiteral("widgetTypeSlug")] = |
| 1287 | API::EnumLabels::dashboardWidgetSlug(ref.widgetType); |
| 1288 | issue[QStringLiteral("groupId")] = ref.groupUniqueId; |
| 1289 | issue[QStringLiteral("relativeIndex")] = ref.relativeIndex; |
| 1290 | issue[QStringLiteral("widgetId")] = |
| 1291 | widgetIdFor(ws.workspaceId, ref.widgetType, ref.groupUniqueId, ref.relativeIndex); |
| 1292 | issue[QStringLiteral("message")] = |
| 1293 | QStringLiteral("Widget ref does not resolve to any live group/dataset/widgetType"); |
| 1294 | issues.append(issue); |
| 1295 | } |
| 1296 | ++refIndex; |
| 1297 | } |
| 1298 | } |
| 1299 | |
| 1300 | QJsonArray unreferenced; |
| 1301 | if (!filtered) { |
| 1302 | for (const auto& g : pm.groups()) { |
| 1303 | if (!referencedGroups.contains(g.uniqueId)) { |
| 1304 | unreferenced.append(g.groupId); |
| 1305 | QJsonObject issue; |
| 1306 | issue[QStringLiteral("level")] = QStringLiteral("warning"); |
| 1307 | issue[QStringLiteral("location")] = QStringLiteral("group[%1]").arg(g.groupId); |
nothing calls this directly
no test coverage detected