Skip to main content

CnFeaturesAndRoadmapPage

Manifest-driven page primitive for type: "roadmap" in v2 app manifests. Wraps CnFeaturesAndRoadmapView so consuming apps can declare a Features & Roadmap surface in their manifest without a per-app wrapper file.

When to use

Declare it in manifest.json:

{
"id": "FeaturesRoadmap",
"route": "/features-roadmap",
"type": "roadmap",
"title": "Features & roadmap"
}

CnPageRenderer mounts this page when the manifest declares the type. No registry entry or custom component file is needed.

Resolution order

For each of the three values handed to CnFeaturesAndRoadmapView (repo, features, disabled):

  1. Explicit pages[].config.<key> from the manifest entry.
  2. loadState(appId, 'features_roadmap_<key>', <fallback>) — backed by Nextcloud IInitialState populated server-side.
  3. Hardcoded fallback (repo defaults to ConductionNL/<appId>, features to [], disabled to false).

appId comes from the cnAiContext inject populated by CnAppRoot. Override the prop in tests to bypass the inject.

Props

PropTypeRequiredNotes
repoStringNo<owner>/<repo> slug. Manifest-config override.
featuresArray | nullNoBuild-time feature manifest override.
disabledBoolean | nullNoAdmin opt-out override.
appIdStringNoOverride for the appId used to namespace loadState lookups. Tests set this; production reads it from the cnAiContext inject.

Backend contract

Identical to CnFeaturesAndRoadmapView — the Roadmap tab consumes GET /index.php/apps/openregister/api/github/issues?labels=enhancement,feature and the Suggest modal POSTs to the same endpoint. See CnFeaturesAndRoadmapView for details.

Migration from per-app wrapper

Before:

<!-- src/views/FeaturesRoadmap.vue -->
<template>
<CnFeaturesAndRoadmapView :repo="repo" :features="features" :disabled="disabled" />
</template>

<script>
import { loadState } from '@nextcloud/initial-state'
import { CnFeaturesAndRoadmapView } from '@conduction/nextcloud-vue'

export default {
data() {
return {
repo: loadState('myapp', 'features_roadmap_repo', 'ConductionNL/myapp'),
features: loadState('myapp', 'features_roadmap_features', []),
disabled: loadState('myapp', 'features_roadmap_disabled', false),
}
},
}
</script>
{ "id": "FeaturesRoadmap", "route": "/features-roadmap", "type": "custom", "component": "FeaturesRoadmap" }

After:

{ "id": "FeaturesRoadmap", "route": "/features-roadmap", "type": "roadmap" }

Delete the wrapper file, remove the registry/customComponents entry, and the page just works.

Spec

ConductionNL/nextcloud-vue#264