feat: add Telemetry page under OSS Health section#471
Conversation
Add a public telemetry statistics page that displays anonymous usage data fetched from the Cozystack telemetry server. - Add "OSS Health" dropdown menu with "Telemetry" sub-item - Create telemetry page with tabs: Last Month, Last Quarter, Last 12 Months - Display cluster count, node count/avg, tenant count/avg, and per-app usage - Add GitHub Action workflow to fetch overview.json from telemetry server daily - Style page consistently with the rest of the site (Bootstrap 5 + Cozystack theme) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
✅ Deploy Preview for cozystack ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThis pull request introduces a telemetry feature comprising a scheduled GitHub Actions workflow to fetch and commit daily telemetry data, new documentation content for OSS Health metrics with updated navigation, and associated styling and layout templates to display the telemetry information. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a new OSS Health section and a Telemetry page to display anonymous usage statistics. The changes include new SCSS styling, content files, menu updates, and Hugo layouts for rendering data from a JSON source. Review feedback suggests refactoring the tab navigation to dynamically handle active states, formatting numerical averages to a single decimal place for better readability, and using relative URLs for internal documentation links to improve environment portability.
| <ul class="nav nav-tabs justify-content-center mb-4" id="telemetryTabs" role="tablist"> | ||
| {{ with index $data.periods "month" }} | ||
| <li class="nav-item" role="presentation"> | ||
| <button class="nav-link active" id="month-tab" data-bs-toggle="tab" data-bs-target="#month-pane" type="button" role="tab" aria-controls="month-pane" aria-selected="true"> | ||
| <i class="fas fa-calendar-day me-1"></i> Last Month | ||
| </button> | ||
| </li> | ||
| {{ end }} | ||
| {{ with index $data.periods "quarter" }} | ||
| <li class="nav-item" role="presentation"> | ||
| <button class="nav-link" id="quarter-tab" data-bs-toggle="tab" data-bs-target="#quarter-pane" type="button" role="tab" aria-controls="quarter-pane" aria-selected="false"> | ||
| <i class="fas fa-calendar-week me-1"></i> Last Quarter | ||
| </button> | ||
| </li> | ||
| {{ end }} | ||
| {{ with index $data.periods "year" }} | ||
| <li class="nav-item" role="presentation"> | ||
| <button class="nav-link" id="year-tab" data-bs-toggle="tab" data-bs-target="#year-pane" type="button" role="tab" aria-controls="year-pane" aria-selected="false"> | ||
| <i class="fas fa-calendar-alt me-1"></i> Last 12 Months | ||
| </button> | ||
| </li> | ||
| {{ end }} | ||
| </ul> |
There was a problem hiding this comment.
The current tab implementation hardcodes the active class on the 'Last Month' tab. If the 'month' data is missing from the JSON but other periods (quarter/year) are present, the first available pane will be shown (due to the logic on line 45), but no tab will be highlighted as active.
Refactoring the tabs to use a loop similar to the panes ensures that the active state remains synchronized and makes the code more maintainable.
<ul class="nav nav-tabs justify-content-center mb-4" id="telemetryTabs" role="tablist">
{{ $firstTab := true }}
{{ $tabIds := slice "month" "quarter" "year" }}
{{ $tabIcons := dict "month" "fa-calendar-day" "quarter" "fa-calendar-week" "year" "fa-calendar-alt" }}
{{ $tabLabels := dict "month" "Last Month" "quarter" "Last Quarter" "year" "Last 12 Months" }}
{{ range $id := $tabIds }}
{{ with index $data.periods $id }}
<li class="nav-item" role="presentation">
<button class="nav-link {{ if $firstTab }}active{{ end }}" id="{{ $id }}-tab" data-bs-toggle="tab" data-bs-target="#{{ $id }}-pane" type="button" role="tab" aria-controls="{{ $id }}-pane" aria-selected="{{ if $firstTab }}true{{ else }}false{{ end }}">
<i class="fas {{ index $tabIcons $id }} me-1"></i> {{ index $tabLabels $id }}
</button>
</li>
{{ $firstTab = false }}
{{ end }}
{{ end }}
</ul>There was a problem hiding this comment.
Fixed in f699fc9 — tab activation is now dynamic: a $firstTab variable is computed from the first available period, and both button and pane use it consistently.
| <div class="telemetry-icon"><i class="fas fa-microchip"></i></div> | ||
| <div class="telemetry-value">{{ $period.total_nodes }}</div> | ||
| <div class="telemetry-label">Total Nodes</div> | ||
| <div class="telemetry-secondary">avg {{ $period.avg_nodes_per_cluster }} per cluster</div> |
There was a problem hiding this comment.
Average values calculated from telemetry data might contain many decimal places. It is recommended to format these values to a single decimal place for a cleaner user interface.
| <div class="telemetry-secondary">avg {{ $period.avg_nodes_per_cluster }} per cluster</div> | |
| <div class="telemetry-secondary">avg {{ printf "%.1f" $period.avg_nodes_per_cluster }} per cluster</div> |
There was a problem hiding this comment.
Fixed in f699fc9 — now uses printf "%.1f" for consistent display.
| <div class="telemetry-icon"><i class="fas fa-users"></i></div> | ||
| <div class="telemetry-value">{{ $period.total_tenants }}</div> | ||
| <div class="telemetry-label">Tenants</div> | ||
| <div class="telemetry-secondary">avg {{ $period.avg_tenants_per_cluster }} per cluster</div> |
There was a problem hiding this comment.
Similar to the nodes average, the tenants average should be formatted to avoid displaying excessive decimal places.
| <div class="telemetry-secondary">avg {{ $period.avg_tenants_per_cluster }} per cluster</div> | |
| <div class="telemetry-secondary">avg {{ printf "%.1f" $period.avg_tenants_per_cluster }} per cluster</div> |
There was a problem hiding this comment.
Fixed in f699fc9 — same printf "%.1f" applied.
| <p class="text-muted"> | ||
| <small> | ||
| Cozystack collects anonymous, aggregate telemetry to understand usage patterns. | ||
| <a href="https://cozystack.io/docs/telemetry/">Learn more about what is collected</a>. |
There was a problem hiding this comment.
Using a hardcoded absolute URL for internal documentation links can break in preview environments or if the domain changes. It is better to use the relURL function to ensure the link is always relative to the site root.
| <a href="https://cozystack.io/docs/telemetry/">Learn more about what is collected</a>. | |
| <a href="{{ "docs/telemetry/" | relURL }}">Learn more about what is collected</a>. |
There was a problem hiding this comment.
Fixed in f699fc9 — now uses {{ "docs/telemetry/" | relURL }}.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
layouts/oss-health/baseof.html (1)
10-13: Use a semantic<main>landmark for primary page content.This improves accessibility and aligns with typical page structure semantics.
♻️ Suggested change
- <div class="container-fluid td-outer"> - <div class="td-main"> - {{ block "main" . }}{{ end }} - </div> + <div class="container-fluid td-outer"> + <main class="td-main" role="main"> + {{ block "main" . }}{{ end }} + </main> {{ partial "footer.html" . }} </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@layouts/oss-health/baseof.html` around lines 10 - 13, Replace the non-semantic container used for the primary content with a semantic main landmark: change the element wrapping the Hugo block "main" that currently uses <div class="td-main"> to a <main class="td-main"> (and update the closing tag accordingly) so the Hugo block "main" remains unchanged but is now inside a semantic <main> element for better accessibility and page structure.assets/scss/_telemetry.scss (1)
76-80: Optional: Add empty line before thecolorproperty for style consistency.Stylelint flags a missing blank line before line 79. Adding it would improve consistency with the project's code style rules.
🎨 Suggested style improvement
.table-primary { --bs-table-bg: #{rgba($primary, 0.08)}; --bs-table-border-color: #{rgba($primary, 0.15)}; + color: $cozy-black; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@assets/scss/_telemetry.scss` around lines 76 - 80, In the .table-primary rule in assets/scss/_telemetry.scss (look for the .table-primary selector and the --bs-table-border-color declaration), insert a single blank line before the color: $cozy-black; property so there is an empty line between the CSS custom properties and the color declaration to satisfy stylelint and project style consistency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/fetch-telemetry.yml:
- Around line 30-37: The current check only validates JSON syntax using the
python3 -c "import json; json.load(open('/tmp/overview.json'))" command but not
the expected structure; add a minimal schema guard that parses
/tmp/overview.json and verifies required top-level keys and types (e.g.,
presence of keys used by templates) before copying to
data/usage-stats/overview.json; update the workflow step that runs the python3
-c check to instead run a short Python snippet or script that loads
/tmp/overview.json, asserts the expected fields (and simple types/array shapes),
prints an error on mismatch and exits nonzero so the file is not copied, and
only proceed to cp /tmp/overview.json data/usage-stats/overview.json when the
schema check passes.
In `@layouts/oss-health/telemetry.html`:
- Around line 13-46: The nav buttons are hardcoded to mark "month" active while
the panes determine the active pane dynamically using $first, causing no button
to be active when month is absent; change the nav generation to the same loop
used for panes so the first available period gets the "active" class.
Concretely, replace the three separate {{ with index $data.periods "..."}}
button blocks with a loop over $tabIds (same slice "month" "quarter" "year"),
for each $id render the button with class "nav-link{{ if $first }} active{{ end
}}" and the matching data-bs-target/id (e.g., "{{ $id }}-tab", "{{ $id
}}-pane"), and after rendering the first valid button set {{ $first = false }}
so panes and buttons share the same single-source-of-truth ($first/$id) for
activation.
---
Nitpick comments:
In `@assets/scss/_telemetry.scss`:
- Around line 76-80: In the .table-primary rule in assets/scss/_telemetry.scss
(look for the .table-primary selector and the --bs-table-border-color
declaration), insert a single blank line before the color: $cozy-black; property
so there is an empty line between the CSS custom properties and the color
declaration to satisfy stylelint and project style consistency.
In `@layouts/oss-health/baseof.html`:
- Around line 10-13: Replace the non-semantic container used for the primary
content with a semantic main landmark: change the element wrapping the Hugo
block "main" that currently uses <div class="td-main"> to a <main
class="td-main"> (and update the closing tag accordingly) so the Hugo block
"main" remains unchanged but is now inside a semantic <main> element for better
accessibility and page structure.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d3dff4d5-0533-4842-92e0-ab197e5a4ce0
📒 Files selected for processing (9)
.github/workflows/fetch-telemetry.ymlassets/scss/_telemetry.scssassets/scss/main.scsscontent/en/oss-health/_index.mdcontent/en/oss-health/telemetry/_index.mddata/usage-stats/overview.jsonhugo.yamllayouts/oss-health/baseof.htmllayouts/oss-health/telemetry.html
Hugo preserves directory hyphens in data keys, so "usage-stats" must be accessed via index rather than dot notation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
layouts/oss-health/telemetry.html (1)
13-46:⚠️ Potential issue | 🟠 MajorTab activation state is inconsistent when
monthdata is missing.This issue was already flagged in a previous review. The tab buttons hardcode
monthasactive(line 16), while the tab panes dynamically select the first available period using$first(lines 40-45). When onlyquarteroryeardata exists, the corresponding pane will be active but no button will be selected.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@layouts/oss-health/telemetry.html` around lines 13 - 46, The tab buttons hardcode the "month" button as active while panes use $first to mark the first available period active; fix by making the buttons iterate the same $tabIds and use the same first-available logic as the panes so the nav-link and aria-selected state match the first existing period. Locate the nav list (elements with id "telemetryTabs" and buttons like "month-tab"/"quarter-tab"/"year-tab") and change the hardcoded button block to loop over $tabIds, check if index $data.periods $id exists, and apply the "active" class and aria-selected="true" only when $first is true (same $first used for tab-pane), advancing $first after the first rendered button so button activation matches the pane activation.
🧹 Nitpick comments (2)
layouts/oss-health/telemetry.html (2)
54-54: Consider formatting large numbers with thousand separators (optional).For improved readability when displaying large values (e.g., thousands of nodes or tenants), you could use Hugo's
lang.FormatNumberto add thousand separators: "1,234" instead of "1234".Example formatting approach
- <div class="telemetry-value">{{ $period.total_nodes }}</div> + <div class="telemetry-value">{{ lang.FormatNumber 0 $period.total_nodes }}</div>Apply similarly to
clusters,total_tenants, and app$countvalues. The0parameter specifies no decimal places for integers.Also applies to: 63-63, 73-73, 96-96
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@layouts/oss-health/telemetry.html` at line 54, The telemetry template currently outputs raw integers (e.g., {{$period.clusters}}, {{$period.total_tenants}}, and app count variables) which can be hard to read for large numbers; update those occurrences to use Hugo's lang.FormatNumber with 0 decimal places (e.g., lang.FormatNumber <value> 0) so values like $period.clusters, $period.total_tenants and each app's $count render with thousand separators; locate and replace the raw uses in telemetry.html (including the other spots noted) with formatted calls while preserving existing template context.
65-65: Format average values to limit decimal places.The average values may display excessive decimal places if the API returns raw floats (e.g., "3.7894736842105263 per cluster"). For better readability, format these to one or two decimal places.
📊 Proposed fix to format averages
- <div class="telemetry-secondary">avg {{ $period.avg_nodes_per_cluster }} per cluster</div> + <div class="telemetry-secondary">avg {{ printf "%.1f" $period.avg_nodes_per_cluster }} per cluster</div>- <div class="telemetry-secondary">avg {{ $period.avg_tenants_per_cluster }} per cluster</div> + <div class="telemetry-secondary">avg {{ printf "%.1f" $period.avg_tenants_per_cluster }} per cluster</div>Also applies to: 75-75
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@layouts/oss-health/telemetry.html` at line 65, The template is outputting raw float averages (e.g., $period.avg_nodes_per_cluster) resulting in long decimal tails; update the template to format these values with printf (e.g., use {{ printf "%.1f" $period.avg_nodes_per_cluster }} or "%.2f" as preferred) wherever average variables are rendered (specifically replace the $period.avg_nodes_per_cluster interpolation and the other average interpolation on the same page with printf-formatting to limit decimals).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@layouts/oss-health/telemetry.html`:
- Around line 13-46: The tab buttons hardcode the "month" button as active while
panes use $first to mark the first available period active; fix by making the
buttons iterate the same $tabIds and use the same first-available logic as the
panes so the nav-link and aria-selected state match the first existing period.
Locate the nav list (elements with id "telemetryTabs" and buttons like
"month-tab"/"quarter-tab"/"year-tab") and change the hardcoded button block to
loop over $tabIds, check if index $data.periods $id exists, and apply the
"active" class and aria-selected="true" only when $first is true (same $first
used for tab-pane), advancing $first after the first rendered button so button
activation matches the pane activation.
---
Nitpick comments:
In `@layouts/oss-health/telemetry.html`:
- Line 54: The telemetry template currently outputs raw integers (e.g.,
{{$period.clusters}}, {{$period.total_tenants}}, and app count variables) which
can be hard to read for large numbers; update those occurrences to use Hugo's
lang.FormatNumber with 0 decimal places (e.g., lang.FormatNumber <value> 0) so
values like $period.clusters, $period.total_tenants and each app's $count render
with thousand separators; locate and replace the raw uses in telemetry.html
(including the other spots noted) with formatted calls while preserving existing
template context.
- Line 65: The template is outputting raw float averages (e.g.,
$period.avg_nodes_per_cluster) resulting in long decimal tails; update the
template to format these values with printf (e.g., use {{ printf "%.1f"
$period.avg_nodes_per_cluster }} or "%.2f" as preferred) wherever average
variables are rendered (specifically replace the $period.avg_nodes_per_cluster
interpolation and the other average interpolation on the same page with
printf-formatting to limit decimals).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f3e5e292-4348-4145-a4d7-613d2ac24108
📒 Files selected for processing (1)
layouts/oss-health/telemetry.html
- Sync tab button and pane active state dynamically (first available tab) - Format avg values to 1 decimal place with printf "%.1f" - Use relURL for docs/telemetry link instead of hardcoded absolute URL - Add JSON schema validation in fetch workflow (check generated_at, periods) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- hugo.yaml: keep OSS Health menu + upstream's renamed "Enterprise support" - main.scss: include upstream's new imports + our telemetry import Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/fetch-telemetry.yml:
- Around line 31-36: The YAML parser is choking on the multiline python3 -c
"..." in the if conditional; replace that multiline-in-string usage in the if
block (the python3 -c invocation) with a YAML-safe form—either collapse the
Python into a single-quoted one-liner (use semicolons and single quotes) or
switch the check to use a heredoc (bash <<'PY' ... PY) so the shell receives the
multiline script but YAML sees a proper scalar; update the conditional to run
the same assertions (generated_at and periods checks) using the chosen YAML-safe
form.
In `@assets/scss/main.scss`:
- Line 152: The `@import` "telemetry"; statement is placed after style rule blocks
causing a Stylelint no-invalid-position-at-import-rule failure; move the import
so it appears before any CSS/SCSS rule definitions (i.e., place `@import`
"telemetry"; at the very top of main.scss, above all selectors, variables, and
mixins) to satisfy the linter.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 507ff226-df99-4fa7-aef8-2a231aeb3865
📒 Files selected for processing (2)
.github/workflows/fetch-telemetry.ymlassets/scss/main.scss
| @import "announcement-banner"; | ||
| @import "tabs_alerts"; | ||
| @import "override-docsy-tabs"; | ||
| @import "telemetry"; |
There was a problem hiding this comment.
Move the telemetry import above all style rules.
Line 152 places @import "telemetry"; after rule blocks, which violates the current Stylelint rule (no-invalid-position-at-import-rule) and will keep lint failing.
♻️ Proposed fix
// Import Docsy styles_project (allows further customization)
`@import` "docsy/styles_project";
+@import "telemetry";
@@
`@import` "tabs_alerts";
`@import` "override-docsy-tabs";
-@import "telemetry";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @import "telemetry"; | |
| // Import Docsy styles_project (allows further customization) | |
| `@import` "docsy/styles_project"; | |
| `@import` "telemetry"; | |
| `@import` "tabs_alerts"; | |
| `@import` "override-docsy-tabs"; |
🧰 Tools
🪛 Stylelint (17.6.0)
[error] 152-152: Unexpected invalid position @import rule (no-invalid-position-at-import-rule)
(no-invalid-position-at-import-rule)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@assets/scss/main.scss` at line 152, The `@import` "telemetry"; statement is
placed after style rule blocks causing a Stylelint
no-invalid-position-at-import-rule failure; move the import so it appears before
any CSS/SCSS rule definitions (i.e., place `@import` "telemetry"; at the very top
of main.scss, above all selectors, variables, and mixins) to satisfy the linter.
Signed-off-by: tym83 <6355522@gmail.com> # Conflicts: # content/en/oss-health/_index.md # hugo.yaml
The telemetry server endpoint now requires year and month query params (it returns 400 without them). Two changes: - Seed data/usage-stats/overview.json with the current month snapshot (April 2026) so the /oss-health/telemetry/ page renders real numbers immediately rather than the empty placeholder. - Update .github/workflows/fetch-telemetry.yml to include the current year and month in the request URL so the daily cron keeps working. Signed-off-by: tym83 <6355522@gmail.com>
Layout - Convert content/en/oss-health/telemetry/_index.md to a single-file page (content/en/oss-health/telemetry.md) with layout: oss-health-app and oss_health_kind: "telemetry" — same hero + snapshot shell as DevStats, OpenSSF, and OSS Insight. - Add renderTelemetry() to layouts/_default/oss-health-app.html using the shared renderCards / renderTable helpers plus a month / quarter / year switcher. - Extend renderCards with an optional "hint" subtitle so the summary cards can show "avg X per cluster" under the raw count. - Delete the standalone layouts/oss-health/telemetry.html — it's no longer needed. Data shape - hack/fetch_telemetry.py replaces the inline curl+python block. It fetches the upstream API with year and month, keeps only apps visible on the Cozystack dashboard (applications, services, networking, virtualization from docs/v1.2), and merges case-insensitive / Pax* / legacy-name variants by taking the maximum count. Tenant is promoted from the apps map to the Tenants summary card because the API's top-level total_tenants is always zero. Info and zero-count rows after the merge are dropped. - Output lives at static/oss-health-data/telemetry.json, matching the other OSS Health feeds. data/usage-stats/ is removed. Workflow - .github/workflows/fetch-telemetry.yml now calls the script so local refreshes and the daily cron share the same transform. Signed-off-by: tym83 <6355522@gmail.com>
The previous commit (38959d4) accidentally left three modified files unstaged, so the port landed only partially: - layouts/_default/oss-health-app.html — adds renderTelemetry() and the kind === "telemetry" dispatch. Without this, telemetry pages fall through to renderTimeseries and crash on undefined fields ("Cannot read properties of undefined (reading 'map')"). - assets/scss/_oss_health.scss — adds .oss-health-stat__hint so the "avg X per cluster" subtitle renders properly on the summary cards. - .github/workflows/fetch-telemetry.yml — switches to calling the hack/fetch_telemetry.py script instead of the old inline fetcher. Signed-off-by: tym83 <6355522@gmail.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
assets/scss/main.scss (1)
164-164:⚠️ Potential issue | 🟠 MajorThe telemetry import must be moved above CSS rules to satisfy Stylelint.
This issue was already flagged in the previous review. The
@import "telemetry";statement at line 164 appears after CSS rule blocks (lines 44-124, 129-146), which violates theno-invalid-position-at-import-rule. Move it immediately after line 127 (@import "docsy/styles_project";) as previously suggested.♻️ Apply the previously suggested fix
// Import Docsy styles_project (allows further customization) `@import` "docsy/styles_project"; +@import "telemetry"; // Import Google Fonts (Montserrat) `@import` url($web-font-path);`@import` "tabs_alerts"; `@import` "override-docsy-tabs"; -@import "telemetry";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@assets/scss/main.scss` at line 164, Move the `@import "telemetry";` rule so it appears with other imports before any CSS rules: relocate the `@import "telemetry";` statement to directly follow the existing `@import "docsy/styles_project";` import (i.e., place it above the rule blocks that start around lines 44-124 and 129-146) to satisfy the no-invalid-position-at-import-rule in Stylelint.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@assets/scss/main.scss`:
- Line 164: Move the `@import "telemetry";` rule so it appears with other
imports before any CSS rules: relocate the `@import "telemetry";` statement to
directly follow the existing `@import "docsy/styles_project";` import (i.e.,
place it above the rule blocks that start around lines 44-124 and 129-146) to
satisfy the no-invalid-position-at-import-rule in Stylelint.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 990f84ab-474c-4b20-88b3-5038d2414307
📒 Files selected for processing (3)
.github/workflows/fetch-telemetry.ymlassets/scss/_oss_health.scssassets/scss/main.scss
✅ Files skipped from review due to trivial changes (2)
- assets/scss/_oss_health.scss
- .github/workflows/fetch-telemetry.yml
Summary
/oss-health/telemetry/page displaying anonymous usage statistics from Cozystack clustersfetch-telemetry.yml) that fetches JSON fromtelemetry.cozystack.io/api/overviewdaily and commits todata/usage-stats/overview.jsonFiles added/changed
hugo.yaml— add OSS Health menu with Telemetry child itemcontent/en/oss-health/_index.md— section indexcontent/en/oss-health/telemetry/_index.md— telemetry page contentlayouts/oss-health/baseof.html— base template with standard header/footerlayouts/oss-health/telemetry.html— page template with tabs, stat cards, app usage tableassets/scss/_telemetry.scss— page-specific stylesassets/scss/main.scss— import telemetry stylesdata/usage-stats/overview.json— placeholder data file (populated by CI).github/workflows/fetch-telemetry.yml— daily data fetch workflowDepends on
/api/overviewendpoint)Test plan
hugo servelocally and verify the Telemetry page renders at/oss-health/telemetry/data/usage-stats/overview.jsonto confirm tab switching works🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes