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
2 changes: 1 addition & 1 deletion .deploy/mta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ID: tutorials-ims
# Bump this on each release you deploy — it's the version shown by `cf mtas`
# and in the mtar filename (tutorials-ims_<version>.mtar). Deploy is manual:
# `cd .deploy && mbt build && cf deploy mta_archives/tutorials-ims_<version>.mtar -e ../deploy/<env>.mtaext -f`.
version: 1.41.0
version: 1.41.3

# Top-level parameters (overridable per-env via deploy/<env>.mtaext).
parameters:
Expand Down
2 changes: 1 addition & 1 deletion hugo/data/glossary.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ terms:
link: https://help.sap.com/docs/sap-mobile-services
TypeScript:
term: TypeScript
definition: Microsoft's typed superset of JavaScript — compiles to JS; preferred for new CAP and UI5 projects in this codebase.
definition: Microsoft's typed superset of JavaScript — compiles to JS; preferred for new UI5 projects.
link: https://www.typescriptlang.org/
Eclipse:
term: Eclipse IDE
Expand Down
145 changes: 144 additions & 1 deletion hugo/data/whats_new.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"generatedAt": "2026-10-24T10:33:13.644Z",
"generatedAt": "2026-10-25T13:42:26.548Z",
"repos": [
{
"key": "tutorials-ims",
Expand All @@ -8,6 +8,149 @@
}
],
"entries": [
{
"id": "tutorials-ims#2923",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2923,
"title": "fix(ci): QA asset guard probes PROD approuter (QA is a feature of prod)",
"summary": "Fixed the QA author-preview rebuild so its asset check targets the correct approuter, unblocking QA content refreshes.",
"category": "Maintenance",
"mergedAt": "2026-10-25T13:37:15Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2923"
},
{
"id": "tutorials-ims#2922",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2922,
"title": "fix(ci): regenerate gitignored CSS before unit-test Hugo build",
"summary": "Unit-test build now regenerates its CSS first, so the test suite runs reliably on a clean checkout.",
"category": "Maintenance",
"mergedAt": "2026-10-25T12:48:25Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2922"
},
{
"id": "tutorials-ims#2921",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2921,
"title": "TypeScript glossary entry corrected",
"summary": "Corrected the glossary definition for TypeScript so the term reads accurately for learners.",
"category": "Fix",
"mergedAt": "2026-10-25T12:23:58Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2921"
},
{
"id": "tutorials-ims#2919",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2919,
"title": "release v1.41.2 DEV to main promotion",
"summary": "Release 1.41.2 promoted the QA content-pipeline fix from DEV to the production branch.",
"category": "Maintenance",
"mergedAt": "2026-10-25T12:05:49Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2919"
},
{
"id": "tutorials-ims#2918",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2918,
"title": "docs: record QA/PROD rebuild-workflow parity rule (follow-up to #2917)",
"summary": "Documented the parity rule that keeps the QA and production content-rebuild pipelines generating identical CSS, preventing a class of build break.",
"category": "Maintenance",
"mergedAt": "2026-10-25T11:59:44Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2918"
},
{
"id": "tutorials-ims#2917",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2917,
"title": "QA tutorial previews build and style correctly again",
"summary": "The QA author-preview channel now regenerates its icon and base CSS before building, so author previews render with full styling instead of failing the build.",
"category": "Fix",
"mergedAt": "2026-10-25T11:53:50Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2917"
},
{
"id": "tutorials-ims#2916",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2916,
"title": "release v1.41.1 DEV to main promotion",
"summary": "Release 1.41.1 promoted the prior window of fixes from DEV to the production branch.",
"category": "Maintenance",
"mergedAt": "2026-10-25T11:44:57Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2916"
},
{
"id": "tutorials-ims#2915",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2915,
"title": "Prize-drawing winner cards show the winner's email again",
"summary": "Prize-drawing winner cards now show the winner's email by falling back to their verified sign-in identity when no address is on their main profile, so operators can reach winners instead of seeing \"No Email on File\".",
"category": "Fix",
"mergedAt": "2026-10-25T08:20:00Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2915"
},
{
"id": "tutorials-ims#2914",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2914,
"title": "Badge scanner shows the contestant name in dark mode",
"summary": "The badge scanner's contestant name is now legible in dark mode instead of rendering dark-on-dark, and the underlying theme fix also corrects icon and card-border colors across every page island.",
"category": "Fix",
"mergedAt": "2026-10-25T08:08:40Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2914"
},
{
"id": "tutorials-ims#2913",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2913,
"title": "App Space parallel-path timelines use the full width",
"summary": "App Space tracks with multiple parallel lanes now widen to fill the available space so card titles stop wrapping one word per line, while single-path tracks keep their comfortable reading width.",
"category": "Fix",
"mergedAt": "2026-10-24T14:02:14Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2913"
},
{
"id": "tutorials-ims#2911",
"repo": "tutorials-ims",
"label": "Developer Portal",
"number": 2911,
"title": "release v1.41.0 DEV to main promotion",
"summary": "Release 1.41.0 promoted the prior window of fixes and features from DEV to the production branch.",
"category": "Maintenance",
"mergedAt": "2026-10-24T10:35:54Z",
"week": "2026-W43",
"weekStart": "2026-10-19",
"url": "https://github.com/sap-tutorials/tutorials-ims/pull/2911"
},
{
"id": "tutorials-ims#2910",
"repo": "tutorials-ims",
Expand Down
4 changes: 2 additions & 2 deletions hugo/layouts/partials/tutorial-meta.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
{{ with .Params.displayTags }}
<span class="meta-tags">
<svg class="meta-icon-svg" viewBox="0 0 16 16" width="14" height="14"><path d="M2 2h5.5l6.5 6.5-5.5 5.5L2 7.5V2zm3 1.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3z" fill="currentColor" opacity="0.6"/></svg>
{{/* #2112 — Overview tags now deep-link to /tutorials/?tag=<slug> for parity with the
{{/* #2112 — Overview tags now deep-link to /tutorial-navigator/?tag=<slug> for parity with the
header chips (u1-object-page.html). Zip displayTags with displayTagSlugs; fall back
to a plain span when a slug is missing. "License" stays label-matched + skipped. */}}
{{ $slugs := $.Params.displayTagSlugs }}
{{ range $i, $label := . }}{{ if ne $label "License" }}{{ $slug := "" }}{{ if and $slugs (lt $i (len $slugs)) }}{{ $slug = index $slugs $i }}{{ end }}{{ if $slug }}<a class="tutorial-tag tutorial-tag--link" href="{{ "/tutorials/" | relURL }}?tag={{ $slug | urlquery }}" aria-label="Filter tutorials by {{ $label }}">{{ $label }}</a>{{ else }}<span class="tutorial-tag">{{ $label }}</span>{{ end }}{{ end }}{{ end }}
{{ range $i, $label := . }}{{ if ne $label "License" }}{{ $slug := "" }}{{ if and $slugs (lt $i (len $slugs)) }}{{ $slug = index $slugs $i }}{{ end }}{{ if $slug }}<a class="tutorial-tag tutorial-tag--link" href="{{ "/tutorial-navigator/" | relURL }}?tag={{ $slug | urlquery }}" aria-label="Filter tutorials by {{ $label }}">{{ $label }}</a>{{ else }}<span class="tutorial-tag">{{ $label }}</span>{{ end }}{{ end }}{{ end }}
</span>
{{ end }}
{{ if in .Params.tags "tutorial>license" }}
Expand Down
10 changes: 5 additions & 5 deletions hugo/layouts/tutorials/u1-object-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,11 @@ <h1 class="op-header__title tutorial-hero-title">{{ .Title }}{{ if in .Params.ta
</div>
{{ with .Params.description }}<p class="op-header__description">{{ . }}</p>{{ end }}
<div class="op-header__chips">
{{ with .Params.level }}<a class="op-chip op-chip--link" href="{{ "/tutorials/" | relURL }}?level={{ . | lower | urlquery }}" aria-label="Filter tutorials by experience: {{ . }}"><span class="op-chip__icon">🎓</span>{{ . }}</a>{{ end }}
{{ with .Params.experienceLevel }}<a class="op-chip op-chip--link" href="{{ "/tutorials/" | relURL }}?level={{ . | lower | urlquery }}" aria-label="Filter tutorials by experience: {{ . }}"><span class="op-chip__icon">🎓</span>{{ . }}</a>{{ end }}
{{ with .Params.level }}<a class="op-chip op-chip--link" href="{{ "/tutorial-navigator/" | relURL }}?level={{ . | lower | urlquery }}" aria-label="Filter tutorials by experience: {{ . }}"><span class="op-chip__icon">🎓</span>{{ . }}</a>{{ end }}
{{ with .Params.experienceLevel }}<a class="op-chip op-chip--link" href="{{ "/tutorial-navigator/" | relURL }}?level={{ . | lower | urlquery }}" aria-label="Filter tutorials by experience: {{ . }}"><span class="op-chip__icon">🎓</span>{{ . }}</a>{{ end }}
{{ with .Params.time }}<span class="op-chip"><span class="op-chip__icon">⏱</span>{{ . }} min</span>{{ end }}
{{/* Prefer human-readable displayTags zipped with displayTagSlugs; fall back to raw primaryTag.
#161 — chips are <a> anchors that deep-link to /tutorials/?tag=<slug>. The "License" label
#161 — chips are <a> anchors that deep-link to /tutorial-navigator/?tag=<slug>. The "License" label
is intentionally label-matched (not slug-matched) to preserve existing chip-strip behaviour;
see docs/superpowers/specs/2026-06-01-clickable-tutorial-tags-design.md. */}}
{{ if .Params.displayTags }}
Expand All @@ -266,14 +266,14 @@ <h1 class="op-header__title tutorial-hero-title">{{ .Title }}{{ if in .Params.ta
{{ $slug := "" }}
{{ if and $slugs (lt $i (len $slugs)) }}{{ $slug = index $slugs $i }}{{ end }}
{{ if $slug }}
<a class="op-chip op-chip--tag op-chip--link" href="{{ "/tutorials/" | relURL }}?tag={{ $slug | urlquery }}" aria-label="Filter tutorials by {{ $label }}">{{ $label }}</a>
<a class="op-chip op-chip--tag op-chip--link" href="{{ "/tutorial-navigator/" | relURL }}?tag={{ $slug | urlquery }}" aria-label="Filter tutorials by {{ $label }}">{{ $label }}</a>
{{ else }}
<span class="op-chip op-chip--tag">{{ $label }}</span>
{{ end }}
{{ end }}
{{ end }}
{{ else if .Params.primaryTag }}
<a class="op-chip op-chip--tag op-chip--link" href="{{ "/tutorials/" | relURL }}?tag={{ .Params.primaryTag | urlquery }}" aria-label="Filter tutorials by {{ .Params.primaryTag }}">{{ .Params.primaryTag }}</a>
<a class="op-chip op-chip--tag op-chip--link" href="{{ "/tutorial-navigator/" | relURL }}?tag={{ .Params.primaryTag | urlquery }}" aria-label="Filter tutorials by {{ .Params.primaryTag }}">{{ .Params.primaryTag }}</a>
{{ end }}
{{/* No progress ring for step-less tutorials (e.g. Devtoberfest validation
tutorials, #2127) — nothing to complete, so "0/0" would be misleading. */}}
Expand Down
2 changes: 1 addition & 1 deletion mta-mcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ _schema-version: 3.3.0
# This file lives at repo root → path: gen/srv-mcp (root-relative, no ../).
# before-all runs from ROOT (no cd ..) — mbt uses the descriptor's directory as cwd.
ID: tutorials-mcp
version: 1.1.0
version: 1.1.3

# Destinations are subaccount-level, so DEV and PROD (sharing one subaccount)
# need DISTINCT destination names. `dest-main-srv` defaults to the PROD name;
Expand Down
9 changes: 5 additions & 4 deletions test/smoke/clickable-chips.smoke.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// test/smoke/clickable-chips.smoke.test.ts
//
// Issue #161 — verifies the U1 Object Page renders experience and
// topic/product chips as anchors deep-linking to /tutorials/?level=...
// and /tutorials/?tag=... respectively. Pattern follows
// topic/product chips as anchors deep-linking to /tutorial-navigator/?level=...
// and /tutorial-navigator/?tag=... respectively (the navigator reads these as
// deep-link entry params; /tutorials/ has no listing route and 404s). Pattern follows
// test/smoke/license-icon.test.js. Quote-stripping tolerant — the Hugo
// minifier removes quotes from safe attribute values, so regexes accept
// both `class="op-chip..."` and `class=op-chip...` forms; see
Expand Down Expand Up @@ -33,12 +34,12 @@ describe(`Clickable chips on /tutorials/${SLUG}/ (#161)`, () => {
/<a[^>]*class=["']?op-chip op-chip--link["']?[^>]*>[^<]*<span[^>]*op-chip__icon[^>]*>[^<]*<\/span>[^<]*<\/a>/,
)
expect(anchor, 'expected an experience chip anchor').toBeTruthy()
expect(html).toMatch(/href=["']?[^"' >]*\/tutorials\/\?level=[a-z]+["']?/)
expect(html).toMatch(/href=["']?[^"' >]*\/tutorial-navigator\/\?level=[a-z]+["']?/)
})

it('renders at least one topic/product chip as an anchor with ?tag=', () => {
expect(html).toMatch(
/<a[^>]*class=["']?op-chip op-chip--tag op-chip--link["']?[^>]*href=["']?[^"' >]*\/tutorials\/\?tag=[^"' >]+["']?/,
/<a[^>]*class=["']?op-chip op-chip--tag op-chip--link["']?[^>]*href=["']?[^"' >]*\/tutorial-navigator\/\?tag=[^"' >]+["']?/,
)
})

Expand Down
Loading