)]}'
{
  "commit": "f34e34b70ee12837ee49dff15140ab2aab3b2de4",
  "tree": "d7ef1332b659055688e5526b8d0a2b44e5ab09f4",
  "parents": [
    "c8e3ba5e0bd2a75e3b06a4e2b17ba4c666ea637c"
  ],
  "author": {
    "name": "Dmitry Grand",
    "email": "dmgr@google.com",
    "time": "Fri May 08 15:29:23 2026 -0700"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Fri May 08 22:29:23 2026 +0000"
  },
  "message": "[Gemini Log Analyzer] Part 4: Frontend Integration (Dashboard UI) (#5044)\n\nThis is Part 4 of the stacked Pull Request series implementing the Gemini Log Analyzer feature.\n\n**Depends on Part 3:** #5043 (Note: Targets `main` due to GitHub cross-repo limits, but chains to #5043 via description).\n\nThis PR integrates the feature into the Cocoon Dashboard UI:\n- Adds \"Log Analysis\" tab to display the Gemini log analyzer results when available.\n- Adds \"Analyze Logs with Gemini\" action button to trigger the API from the presubmit dashboard.\n- Implements spellchecking, permission-checking, and error-handling for the trigger action.\n\n### Stacked PR Series:\n- Part 1: Backend Foundation (Models \u0026 Setup) (Merged)\n- Part 2: Backend Infrastructure (Config \u0026 Database Data Flow) (#5045)\n- Part 3: Backend Core API (Genkit Logic \u0026 Handlers) (#5043)\n- **Part 4: Frontend Dashboard UI** (This PR)",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "3b6aa1d26afdb3933f19add73b0887346f2d4827",
      "old_mode": 33188,
      "old_path": "app_dart/config.yaml",
      "new_id": "c2ff721db9620e5f02623bf2e76e34c8e6bef891",
      "new_mode": 33188,
      "new_path": "app_dart/config.yaml"
    },
    {
      "type": "modify",
      "old_id": "097be64fd4de2ac0e63dd3bd3c4062a8c943572a",
      "old_mode": 33188,
      "old_path": "app_dart/lib/src/generated_config.dart",
      "new_id": "d1bf3d39a8fe16ea5e7146c28dedce5d4f373b3f",
      "new_mode": 33188,
      "new_path": "app_dart/lib/src/generated_config.dart"
    },
    {
      "type": "modify",
      "old_id": "a7cf7bc494088e89f020e7681c32476cf7a5941b",
      "old_mode": 33188,
      "old_path": "app_dart/lib/src/request_handlers/get_presubmit_guard.dart",
      "new_id": "85dec735ee3d0993d6f9bd59f8c8137a3d1ba8b1",
      "new_mode": 33188,
      "new_path": "app_dart/lib/src/request_handlers/get_presubmit_guard.dart"
    },
    {
      "type": "modify",
      "old_id": "6902efa96fc93d1b902d145a7f4ab5c280f28868",
      "old_mode": 33188,
      "old_path": "app_dart/lib/src/service/flags/dynamic_config.dart",
      "new_id": "51d1f12c2bd6ab2336f4435bd602024d7e7dfbab",
      "new_mode": 33188,
      "new_path": "app_dart/lib/src/service/flags/dynamic_config.dart"
    },
    {
      "type": "modify",
      "old_id": "fc81a2c8fb511157252d25ac48c5c4eaf4b65707",
      "old_mode": 33188,
      "old_path": "app_dart/lib/src/service/flags/dynamic_config.g.dart",
      "new_id": "fae2ae9b1a96304c5a4bf21241fbaf951f68714d",
      "new_mode": 33188,
      "new_path": "app_dart/lib/src/service/flags/dynamic_config.g.dart"
    },
    {
      "type": "modify",
      "old_id": "38a63059c1a2b0a891ddb07712d5e8c41eac1d60",
      "old_mode": 33188,
      "old_path": "dashboard/lib/service/appengine_cocoon.dart",
      "new_id": "1716fe1b1bc2294d8400dbf50cc83419f5c8dc89",
      "new_mode": 33188,
      "new_path": "dashboard/lib/service/appengine_cocoon.dart"
    },
    {
      "type": "modify",
      "old_id": "11e1c5db68672ed946d760a69d41148354a71393",
      "old_mode": 33188,
      "old_path": "dashboard/lib/service/cocoon.dart",
      "new_id": "5ebcf1e930a3b2bdcd8374ab7de0641837e334fc",
      "new_mode": 33188,
      "new_path": "dashboard/lib/service/cocoon.dart"
    },
    {
      "type": "modify",
      "old_id": "0b0352c2aa3ad842c18b46a878f08dc9841f3c01",
      "old_mode": 33188,
      "old_path": "dashboard/lib/service/data_seeder.dart",
      "new_id": "f22ebfbec7c655323b8fca045b5ab2ff086ead7c",
      "new_mode": 33188,
      "new_path": "dashboard/lib/service/data_seeder.dart"
    },
    {
      "type": "modify",
      "old_id": "754525ddcb2671718aea9406b9be5620e7b54e6f",
      "old_mode": 33188,
      "old_path": "dashboard/lib/state/presubmit.dart",
      "new_id": "586d33df6b380ba6783e6fd46031f90ac61847c1",
      "new_mode": 33188,
      "new_path": "dashboard/lib/state/presubmit.dart"
    },
    {
      "type": "modify",
      "old_id": "36aff0651d8d67533fec4c7793424f27b37367fe",
      "old_mode": 33188,
      "old_path": "dashboard/lib/views/presubmit_view.dart",
      "new_id": "e5662799f002645f943893780047fce9ccf4d782",
      "new_mode": 33188,
      "new_path": "dashboard/lib/views/presubmit_view.dart"
    },
    {
      "type": "modify",
      "old_id": "c28fe76d22ecbf5437b5c3edb8458470359511ef",
      "old_mode": 33188,
      "old_path": "dashboard/test/state/presubmit_test.dart",
      "new_id": "c46f7a85a3ba1a40c123302678807d07f4f9acbb",
      "new_mode": 33188,
      "new_path": "dashboard/test/state/presubmit_test.dart"
    },
    {
      "type": "modify",
      "old_id": "25cfec53943e3a481cc55c0d2cbcc04eb0260012",
      "old_mode": 33188,
      "old_path": "dashboard/test/utils/mocks.mocks.dart",
      "new_id": "990233c025f1787630a011569dc074c0d19a2c35",
      "new_mode": 33188,
      "new_path": "dashboard/test/utils/mocks.mocks.dart"
    },
    {
      "type": "modify",
      "old_id": "e3b1e4bdc6597f371797da48eb1868b13833439b",
      "old_mode": 33188,
      "old_path": "dashboard/test/views/presubmit_view_test.dart",
      "new_id": "a5366c1db657c1d79de085c4ef5817e6131e7dc0",
      "new_mode": 33188,
      "new_path": "dashboard/test/views/presubmit_view_test.dart"
    },
    {
      "type": "modify",
      "old_id": "ab2d7e0a8c0af24db2c1fee35e6bbcf8314c8f22",
      "old_mode": 33188,
      "old_path": "packages/cocoon_common/lib/src/rpc_model/presubmit_guard.dart",
      "new_id": "e555552246c5bcbd20d72b57dbe1ff9b7f38cb13",
      "new_mode": 33188,
      "new_path": "packages/cocoon_common/lib/src/rpc_model/presubmit_guard.dart"
    },
    {
      "type": "modify",
      "old_id": "9e5e9decd2d848c69c7b08185572999c411176cf",
      "old_mode": 33188,
      "old_path": "packages/cocoon_common/lib/src/rpc_model/presubmit_guard.g.dart",
      "new_id": "0141903b87a1dcc5efcb3cf7e9183a4b71291c32",
      "new_mode": 33188,
      "new_path": "packages/cocoon_common/lib/src/rpc_model/presubmit_guard.g.dart"
    }
  ]
}
