Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
steps:
- name: Check out repository
uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Set up Node.js
uses: actions/setup-node@v6
Expand All @@ -29,13 +31,17 @@ jobs:
run: corepack enable

- name: Install dependencies
run: corepack pnpm install --frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Audit changed client code
if: github.event_name == 'pull_request'
run: pnpm run audit --base '${{ github.event.pull_request.base.sha }}' --format github-annotations

- name: Test client
run: corepack pnpm test
run: pnpm test

- name: Build client
run: corepack pnpm build
run: pnpm build

dotnet:
name: .NET (Umbraco ${{ matrix.umbraco-version }})
Expand Down Expand Up @@ -84,7 +90,7 @@ jobs:

- name: Install backoffice dependencies
working-directory: src/TheBuilder.WebAnalytics/Client
run: corepack pnpm install --frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Pack NuGet package
run: >-
Expand Down
80 changes: 80 additions & 0 deletions src/TheBuilder.WebAnalytics/Client/.fallowrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
"entry": [
"src/bundle.manifests.ts",
"scripts/**/*.js",
"vite.config.ts"
],
"dynamicallyLoaded": [
"src/entrypoints/entrypoint.ts",
"src/section/analytics-enabled.condition.ts",
"src/section/analytics-section.element.ts",
"src/settings/settings-dashboard.element.ts",
"src/workspace/analytics-workspace.element.ts",
"src/workspace/document-analytics.condition.ts"
],
"ignorePatterns": [
"src/api/**/*.gen.ts",
"src/api/index.ts",
"src/api/client/index.ts"
],
"ignoreDependencies": [
// Build-time generator dependencies and the Umbraco-provided runtime peer
// intentionally remain devDependencies; production code is bundled.
"@hey-api/openapi-ts",
"@umbraco-cms/backoffice",
"chalk",
"node-fetch"
],
"usedClassMembers": [
"connectedCallback",
"disconnectedCallback",
"focusFirstInvalid",
"styles"
],
"duplicates": {
"minOccurrences": 2,
"ignore": [
"src/api/**/*.gen.ts",
"src/api/index.ts",
"src/api/client/index.ts"
]
},
"health": {
// Lit templates count every conditional binding and optional chain as a
// branch. These ceilings still catch structural hotspots without treating
// declarative rendering as equivalent to imperative control flow.
"maxCyclomatic": 30,
"maxCognitive": 35,
// Until CI produces Istanbul coverage, Fallow's static CRAP estimate
// overstates tested Lit and controller code. Keep a finite ceiling while
// structural complexity remains the primary gate.
"maxCrap": 300,
"ignore": [
"src/api/**/*.gen.ts",
"src/api/index.ts",
"src/api/client/index.ts",
"**/*.test.ts"
],
"thresholdOverrides": [
{
"files": ["src/analytics/analytics-dashboard.element.ts"],
"functions": ["render"],
"maxCyclomatic": 35,
"reason": "The dashboard render method composes independent optional panels and dialog states; its declarative Lit bindings are kept under a narrow render-only ceiling."
},
{
"files": ["src/settings/connection-editor.element.ts"],
"functions": ["render"],
"maxCyclomatic": 65,
"maxCognitive": 95,
"maxCrap": 900,
"reason": "The connection editor is a single declarative Lit form whose conditional bindings mirror independent provider capabilities; extracting them would fragment the form contract without reducing runtime decision-making."
}
]
},
"rules": {
"unused-dev-dependencies": "error",
"dev-dependencies-in-production": "error"
}
}
1 change: 1 addition & 0 deletions src/TheBuilder.WebAnalytics/Client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.fallow/
2 changes: 2 additions & 0 deletions src/TheBuilder.WebAnalytics/Client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"build": "tsc && vite build",
"check": "tsc --noEmit",
"test": "vitest run",
"audit": "fallow audit --gate new-only",
"generate-client": "node scripts/generate-openapi.js"
},
"dependencies": {
Expand All @@ -19,6 +20,7 @@
"@umbraco-cms/backoffice": "^17.1.0",
"chalk": "^5.6.2",
"cross-env": "^10.1.0",
"fallow": "3.9.1",
"jsdom": "^27.4.0",
"node-fetch": "^3.3.2",
"typescript": "^5.9.3",
Expand Down
91 changes: 91 additions & 0 deletions src/TheBuilder.WebAnalytics/Client/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ export class WebAnalyticsBreakdownGridElement extends UmbElementMixin(LitElement
};
}

#renderBreakdownFooter(
loading: boolean,
unavailable: string | undefined,
hasRows: boolean,
selected: ReturnType<typeof selectedCardDimension>,
) {
if (!loading && hasRows && !unavailable) {
return html`
<uui-button class="view-all" compact look="default" label=${`View all ${selected.headline}`} @click=${() => this.#dispatch("view-breakdown", selected)}>View all</uui-button>
`;
}
return !loading && unavailable
? html`<uui-button look="secondary" label=${`Retry ${selected.headline} report`} @click=${() => this.#dispatch("retry-reports")}>Retry</uui-button>`
: "";
}

#renderCard(card: DashboardCard) {
const selected = selectedCardDimension(card, this.audienceDimension, this.utmDimension);
const state = this.breakdowns[selected.dimension];
Expand Down Expand Up @@ -97,11 +113,7 @@ export class WebAnalyticsBreakdownGridElement extends UmbElementMixin(LitElement
</web-analytics-breakdown-table>
${planLimited && unavailable ? html`<p class="hint breakdown-hint">UTM reporting availability depends on your analytics plan and reporting window.</p>` : ""}
<footer class="breakdown-footer">
${!loading && !unavailable && rows.length ? html`
<uui-button class="view-all" compact look="default" label=${`View all ${selected.headline}`} @click=${() => this.#dispatch("view-breakdown", selected)}>View all</uui-button>
` : !loading && unavailable ? html`
<uui-button look="secondary" label=${`Retry ${selected.headline} report`} @click=${() => this.#dispatch("retry-reports")}>Retry</uui-button>
` : ""}
${this.#renderBreakdownFooter(loading, unavailable, rows.length > 0, selected)}
</footer>
</div>
</uui-box>
Expand Down Expand Up @@ -139,11 +151,7 @@ export class WebAnalyticsBreakdownGridElement extends UmbElementMixin(LitElement
@heading-tab-change=${(event: CustomEvent<{ value: AcquisitionView }>) => this.#dispatch("acquisition-change", { view: event.detail.value })}
@subheading-tab-change=${(event: CustomEvent<{ value: UtmDimension }>) => this.#dispatch("utm-change", { dimension: event.detail.value })}></web-analytics-breakdown-table>
<footer class="breakdown-footer">
${!loading && !unavailable && rows.length ? html`
<uui-button class="view-all" compact look="default" label=${`View all ${selected.headline}`} @click=${() => this.#dispatch("view-breakdown", selected)}>View all</uui-button>
` : !loading && unavailable ? html`
<uui-button look="secondary" label=${`Retry ${selected.headline} report`} @click=${() => this.#dispatch("retry-reports")}>Retry</uui-button>
` : ""}
${this.#renderBreakdownFooter(loading, unavailable, rows.length > 0, selected)}
</footer>
</div>
</uui-box>
Expand Down
Loading