diff --git a/.changeset/bright-crabs-crash.md b/.changeset/bright-crabs-crash.md
new file mode 100644
index 0000000000..f5518505b5
--- /dev/null
+++ b/.changeset/bright-crabs-crash.md
@@ -0,0 +1,39 @@
+---
+'app': major
+---
+
+Use dynamic frontend plugins across the app
+
+This change makes `dynamicPlugins.frontend.mountPoints` generic and declarative:
+
+Mountpoint now support following names/types:
+
+- Allow passing \*/context mountpoints for React context
+- Allow passing \*/cards for Card components (with layout)
+
+- `entity.page.overview`
+- `entity.page.topology`
+- `entity.page.issues`
+- `entity.page.pull-requests`
+- `entity.page.ci`
+- `entity.page.cd`
+- `entity.page.kubernetes`
+- `entity.page.tekton`
+- `entity.page.image-registry`
+- `entity.page.monitoring`
+- `entity.page.lighthouse`
+- `entity.page.api`
+- `entity.page.dependencies`
+- `entity.page.docs`
+- `entity.page.definition`
+- `entity.page.diagram`
+
+Mountpoints support following configuration:
+
+- `layout` for layout features that propagates to allowing users to use CSS properties gridColumnStart including responsiveness queries etc. (mui.com/system/getting-started/the-sx-prop)
+- `if` for EntitySwitch.Case if=... - allows allOf|anyOf|oneOf conditionals with isKind|isType|hasAnnotation builtin methods or code imports via Scalprum (direct string reference)
+- `props` to pass additional props to the mounted component
+
+Current limitations of the dynamic frontend plugins:
+
+Allows you to mount to existing mountPoints only. You're unable to create additional tabs for example. (will be addressed in a follow up PR)
diff --git a/app-config.example.yaml b/app-config.example.yaml
index aaf3c60420..eb85b2e900 100644
--- a/app-config.example.yaml
+++ b/app-config.example.yaml
@@ -98,3 +98,337 @@ catalog:
# Note: integrations.github[].apps must be correctly configured to read GitHub locations
- type: file
target: ../../catalog-entities/all.yaml
+
+
+dynamicPlugins:
+ frontend:
+ backstage.plugin-azure-devops:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: AzureDevopsPlugin
+ importName: EntityAzurePipelinesContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isAzureDevOpsAvailable
+ - mountPoint: entity.page.pull-requests/cards
+ module: AzureDevopsPlugin
+ importName: EntityAzurePullRequestsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isAzureDevOpsAvailable
+ backstage.plugin-dynatrace:
+ mountPoints:
+ - mountPoint: entity.page.monitoring/cards
+ module: DynatracePlugin
+ importName: DynatraceTab
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isDynatraceAvailable
+ backstage.plugin-github-actions:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: GithubActionsPlugin
+ importName: EntityGithubActionsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGithubActionsAvailable
+ backstage.plugin-github-issues:
+ mountPoints:
+ - mountPoint: entity.page.issues/cards
+ module: GithubIssuesPlugin
+ importName: GithubIssuesCard
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - hasAnnotation: github.com/project-slug
+ backstage.plugin-jenkins:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: JenkinsPlugin
+ importName: EntityJenkinsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isJenkinsAvailable
+ backstage.plugin-kubernetes:
+ mountPoints:
+ - mountPoint: entity.page.kubernetes/cards
+ module: KubernetesPlugin
+ importName: EntityKubernetesContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ anyOf:
+ - hasAnnotation: backstage.io/kubernetes-id
+ - hasAnnotation: backstage.io/kubernetes-namespace
+ backstage.plugin-lighthouse:
+ dynamicRoutes:
+ - path: /lighthouse
+ module: LighthousePlugin
+ importName: LighthousePage
+ menuItem:
+ icon: Assessment
+ text: Lighthouse
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: LighthousePlugin
+ importName: EntityLastLighthouseAuditCard
+ config:
+ layout:
+ gridColumnEnd: "span 6"
+ if:
+ allOf:
+ - isLighthouseAvailable
+ backstage.plugin-pagerduty:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: PagerdutyPlugin
+ importName: EntityPagerDutyCard
+ config:
+ layout:
+ gridColumnEnd: "span 6"
+ if:
+ allOf:
+ - isPluginApplicableToEntity
+ backstage.plugin-sonarqube:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: SonarQubePlugin
+ importName: EntitySonarQubeCard
+ config:
+ layout:
+ gridColumnStart: "span 4"
+ gridRowEnd: "span 2"
+ if:
+ allOf:
+ - isSonarQubeAvailable
+ immobiliarelabs.backstage-plugin-gitlab:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: GitlabPlugin
+ importName: EntityGitlabMergeRequestStatsCard
+ config:
+ layout:
+ gridRowEnd: "span 2"
+ gridColumnStart: "span 4"
+ if:
+ allOf:
+ - isGitlabAvailable
+ - mountPoint: entity.page.ci/cards
+ module: GitlabPlugin
+ importName: EntityGitlabPipelinesTable
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGitlabAvailable
+ - mountPoint: entity.page.issues/cards
+ module: GitlabPlugin
+ importName: EntityGitlabIssuesTable
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGitlabAvailable
+ - mountPoint: entity.page.pull-requests/cards
+ module: GitlabPlugin
+ importName: EntityGitlabMergeRequestsTable
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGitlabAvailable
+ janus-idp.backstage-plugin-jfrog-artifactory:
+ mountPoints:
+ - mountPoint: entity.page.image-registry/cards
+ module: JfrogArtifactoryPlugin
+ importName: JfrogArtifactoryPage
+ config:
+ layout:
+ gridColumn: 1 / -1
+ if:
+ anyOf:
+ - isJfrogArtifactoryAvailable
+ janus-idp.backstage-plugin-nexus-repository-manager:
+ mountPoints:
+ - mountPoint: entity.page.image-registry/cards
+ module: NexusRepositoryManagerPlugin
+ importName: NexusRepositoryManagerPage
+ config:
+ layout:
+ gridColumn: 1 / -1
+ if:
+ anyOf:
+ - isNexusRepositoryManagerAvailable
+ janus-idp.backstage-plugin-ocm:
+ dynamicRoutes:
+ - path: /ocm
+ module: OcmPlugin
+ importName: OcmPage
+ menuItem:
+ icon: Storage
+ text: Clusters
+ mountPoints:
+ - mountPoint: entity.page.overview/context
+ module: OcmPlugin
+ importName: ClusterContextProvider
+ - mountPoint: entity.page.overview/cards
+ module: OcmPlugin
+ importName: ClusterAvailableResourceCard
+ config:
+ layout:
+ gridRowStart: 1
+ gridColumnStart: "span 1"
+ if:
+ anyOf:
+ - isKind: resource
+ - isType: kubernetes-cluster
+ - mountPoint: entity.page.overview/cards
+ importName: ClusterInfoCard
+ module: OcmPlugin
+ config:
+ if:
+ allOf:
+ - isKind: resource
+ - isType: kubernetes-cluster
+ janus-idp.backstage-plugin-quay:
+ mountPoints:
+ - mountPoint: entity.page.image-registry/cards
+ module: QuayPlugin
+ importName: QuayPage
+ config:
+ layout:
+ gridColumn: 1 / -1
+ if:
+ anyOf:
+ - isQuayAvailable
+ janus-idp.backstage-plugin-tekton:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: TektonPlugin
+ importName: TektonCI
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isTektonCIAvailable
+ janus-idp.backstage-plugin-topology:
+ mountPoints:
+ - mountPoint: entity.page.topology/cards
+ module: TopologyPlugin
+ importName: TopologyPage
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ anyOf:
+ - hasAnnotation: backstage.io/kubernetes-id
+ - hasAnnotation: backstage.io/kubernetes-namespace
+ roadiehq.backstage-plugin-argo-cd:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: ArgocdPlugin
+ importName: EntityArgoCDOverviewCard
+ config:
+ layout:
+ gridColumn: "1 / span 8"
+ if:
+ allOf:
+ - isArgocdAvailable
+ - mountPoint: entity.page.cd/cards
+ module: ArgocdPlugin
+ importName: EntityArgoCDHistoryCard
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isArgocdAvailable
+ roadiehq.backstage-plugin-datadog:
+ mountPoints:
+ - mountPoint: entity.page.monitoring/cards
+ module: DatadogPlugin
+ importName: EntityDatadogContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isDatadogAvailable
+ roadiehq.backstage-plugin-github-insights:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: GithubInsightsPlugin
+ importName: EntityGithubInsightsComplianceCard
+ config:
+ layout:
+ gridRowEnd: "span 2"
+ gridColumnStart: "span 4"
+ if:
+ allOf:
+ - isGithubInsightsAvailable
+ roadiehq.backstage-plugin-github-pull-requests:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: GithubPullRequestsPlugin
+ importName: EntityGithubPullRequestsOverviewCard
+ config:
+ layout:
+ gridRow: "1 / span 2"
+ gridColumn: "5 / span 4"
+ if:
+ allOf:
+ - isGithubPullRequestsAvailable
+ - mountPoint: entity.page.pull-requests/cards
+ module: GithubPullRequestsPlugin
+ importName: EntityGithubPullRequestsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGithubPullRequestsAvailable
+ roadiehq.backstage-plugin-jira:
+ mountPoints:
+ - mountPoint: entity.page.issues/cards
+ module: JiraPlugin
+ importName: EntityJiraOverviewCard
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isJiraAvailable
+ roadiehq.backstage-plugin-security-insights:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: SecurityInsightsPlugin
+ importName: EntityDependabotAlertsCard
+ config:
+ layout:
+ gridRowEnd: "span 2"
+ gridColumnStart: "span 4"
+ if:
+ allOf:
+ - isSecurityInsightsAvailable
diff --git a/app-config.yaml b/app-config.yaml
index cc70dcfd5b..b70480c04c 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -342,4 +342,3 @@ enabled:
dynamicPlugins:
rootDirectory: dynamic-plugins-root
- frontend: {}
diff --git a/dynamic-plugins.default.yaml b/dynamic-plugins.default.yaml
index e0daa67bda..1ab94d7811 100644
--- a/dynamic-plugins.default.yaml
+++ b/dynamic-plugins.default.yaml
@@ -1,6 +1,5 @@
plugins:
- - package: ./dynamic-plugins/dist/roadiehq-scaffolder-backend-module-utils-dynamic
-
+ # Group: Github
- package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic
disabled: true
pluginConfig:
@@ -11,7 +10,6 @@ plugins:
github:
providerId:
organization: "${GITHUB_ORG}"
-
- package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic
disabled: true
pluginConfig:
@@ -23,7 +21,100 @@ plugins:
default:
id: production
orgUrl: "${GITHUB_ORG_URL}"
+ - package: ./dynamic-plugins/dist/backstage-plugin-github-actions
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-github-actions:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: GithubActionsPlugin
+ importName: EntityGithubActionsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGithubActionsAvailable
+ - package: ./dynamic-plugins/dist/backstage-plugin-github-issues
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-github-issues:
+ mountPoints:
+ - mountPoint: entity.page.issues/cards
+ module: GithubIssuesPlugin
+ importName: GithubIssuesCard
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - hasAnnotation: github.com/project-slug
+ - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-github-insights
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ roadiehq.backstage-plugin-github-insights:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: GithubInsightsPlugin
+ importName: EntityGithubInsightsComplianceCard
+ config:
+ layout:
+ gridRowEnd: "span 2"
+ gridColumnStart: "span 4"
+ if:
+ allOf:
+ - isGithubInsightsAvailable
+ - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ roadiehq.backstage-plugin-github-pull-requests:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: GithubPullRequestsPlugin
+ importName: EntityGithubPullRequestsOverviewCard
+ config:
+ layout:
+ gridRow: "1 / span 2"
+ gridColumn: "5 / span 4"
+ if:
+ allOf:
+ - isGithubPullRequestsAvailable
+ - mountPoint: entity.page.pull-requests/cards
+ module: GithubPullRequestsPlugin
+ importName: EntityGithubPullRequestsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGithubPullRequestsAvailable
+ - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-security-insights
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ roadiehq.backstage-plugin-security-insights:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: SecurityInsightsPlugin
+ importName: EntityDependabotAlertsCard
+ config:
+ layout:
+ gridRowEnd: "span 2"
+ gridColumnStart: "span 4"
+ if:
+ allOf:
+ - isSecurityInsightsAvailable
+ # Group: Gitlab
- package: ./dynamic-plugins/dist/immobiliarelabs-backstage-plugin-gitlab-backend-dynamic
disabled: true
pluginConfig:
@@ -32,7 +123,50 @@ plugins:
gitlab:
host: ${GITLAB_HOST}
token: ${GITLAB_TOKEN}
-
+ - package: ./dynamic-plugins/dist/immobiliarelabs-backstage-plugin-gitlab
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ immobiliarelabs.backstage-plugin-gitlab:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: GitlabPlugin
+ importName: EntityGitlabMergeRequestStatsCard
+ config:
+ layout:
+ gridRowEnd: "span 2"
+ gridColumnStart: "span 4"
+ if:
+ allOf:
+ - isGitlabAvailable
+ - mountPoint: entity.page.ci/cards
+ module: GitlabPlugin
+ importName: EntityGitlabPipelinesTable
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGitlabAvailable
+ - mountPoint: entity.page.issues/cards
+ module: GitlabPlugin
+ importName: EntityGitlabIssuesTable
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGitlabAvailable
+ - mountPoint: entity.page.pull-requests/cards
+ module: GitlabPlugin
+ importName: EntityGitlabMergeRequestsTable
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isGitlabAvailable
- package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-gitlab-dynamic
disabled: true
pluginConfig:
@@ -41,25 +175,10 @@ plugins:
catalog:
providers:
gitlab: {}
-
- package: ./dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-gitlab-dynamic
disabled: true
- - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-keycloak-backend-dynamic
- disabled: true
- pluginConfig:
- enabled:
- keycloak: true
- catalog:
- providers:
- keycloakOrg:
- default:
- baseUrl: "${KEYCLOAK_BASE_URL}"
- loginRealm: "${KEYCLOAK_LOGIN_REALM}"
- realm: "${KEYCLOAK_REALM}"
- clientId: "${KEYCLOAK_CLIENT_ID}"
- clientSecret: "${KEYCLOAK_CLIENT_SECRET}"
-
+ # Group: Kubernetes
- package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic
disabled: true
pluginConfig:
@@ -89,33 +208,42 @@ plugins:
authProvider: 'serviceAccount'
skipTLSVerify: true
serviceAccountToken: ${K8S_CLUSTER_TOKEN}
-
- - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm-backend-dynamic
+ - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes
disabled: true
pluginConfig:
- enabled:
- ocm: true
- catalog:
- providers:
- ocm:
- default:
- name: "${OCM_HUB_NAME}"
- url: "${OCM_HUB_URL}"
- serviceAccountToken: "${moc_infra_token}"
- owner: janus-authors
-
- - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-aap-backend-dynamic
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-kubernetes:
+ mountPoints:
+ - mountPoint: entity.page.kubernetes/cards
+ module: KubernetesPlugin
+ importName: EntityKubernetesContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ anyOf:
+ - hasAnnotation: backstage.io/kubernetes-id
+ - hasAnnotation: backstage.io/kubernetes-namespace
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-topology
disabled: true
pluginConfig:
- enabled:
- aap: true
- catalog:
- providers:
- aap:
- prod:
- baseUrl: '${AAP_BASE_URL}'
- authorization: "${AAP_AUTH_TOKEN}"
+ dynamicPlugins:
+ frontend:
+ janus-idp.backstage-plugin-topology:
+ mountPoints:
+ - mountPoint: entity.page.topology/cards
+ module: TopologyPlugin
+ importName: TopologyPage
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ anyOf:
+ - hasAnnotation: backstage.io/kubernetes-id
+ - hasAnnotation: backstage.io/kubernetes-namespace
+ # Group: ArgoCD
- package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-argo-cd-backend-dynamic
disabled: true
pluginConfig:
@@ -133,7 +261,6 @@ plugins:
- name: argoInstance2
url: "${ARGOCD_INSTANCE2_URL}"
token: "${ARGOCD_AUTH_TOKEN2}"
-
- package: ./dynamic-plugins/dist/roadiehq-scaffolder-backend-argocd-dynamic
disabled: true
pluginConfig:
@@ -151,7 +278,33 @@ plugins:
- name: argoInstance2
url: "${ARGOCD_INSTANCE2_URL}"
token: "${ARGOCD_AUTH_TOKEN2}"
+ - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-argo-cd
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ roadiehq.backstage-plugin-argo-cd:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: ArgocdPlugin
+ importName: EntityArgoCDOverviewCard
+ config:
+ layout:
+ gridColumn: "1 / span 8"
+ if:
+ allOf:
+ - isArgocdAvailable
+ - mountPoint: entity.page.cd/cards
+ module: ArgocdPlugin
+ importName: EntityArgoCDHistoryCard
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isArgocdAvailable
+ # Group: Azure Devops
- package: ./dynamic-plugins/dist/backstage-plugin-azure-devops-backend-dynamic
disabled: true
pluginConfig:
@@ -161,7 +314,33 @@ plugins:
host: dev.azure.com
token: ${AZURE_TOKEN}
organization: ${AZURE_ORG}
+ - package: ./dynamic-plugins/dist/backstage-plugin-azure-devops
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-azure-devops:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: AzureDevopsPlugin
+ importName: EntityAzurePipelinesContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isAzureDevOpsAvailable
+ - mountPoint: entity.page.pull-requests/cards
+ module: AzureDevopsPlugin
+ importName: EntityAzurePullRequestsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isAzureDevOpsAvailable
+ # Group: Jenkins
- package: ./dynamic-plugins/dist/backstage-plugin-jenkins-backend-dynamic
disabled: true
pluginConfig:
@@ -173,7 +352,24 @@ plugins:
baseUrl: ${JENKINS_URL}
username: ${JENKINS_USERNAME}
apiKey: ${JENKINS_TOKEN}
+ - package: ./dynamic-plugins/dist/backstage-plugin-jenkins
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-jenkins:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: JenkinsPlugin
+ importName: EntityJenkinsContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isJenkinsAvailable
+ # Group: SonarQube
- package: ./dynamic-plugins/dist/backstage-plugin-sonarqube-backend-dynamic
disabled: true
pluginConfig:
@@ -182,6 +378,104 @@ plugins:
sonarqube:
baseUrl: ${SONARQUBE_URL}
apiKey: ${SONARQUBE_TOKEN}
+ - package: ./dynamic-plugins/dist/backstage-plugin-sonarqube
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-sonarqube:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: SonarQubePlugin
+ importName: EntitySonarQubeCard
+ config:
+ layout:
+ gridColumnStart: "span 4"
+ gridRowEnd: "span 2"
+ if:
+ allOf:
+ - isSonarQubeAvailable
+
+ # Group: OCM
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm-backend-dynamic
+ disabled: true
+ pluginConfig:
+ enabled:
+ ocm: true
+ catalog:
+ providers:
+ ocm:
+ default:
+ name: "${OCM_HUB_NAME}"
+ url: "${OCM_HUB_URL}"
+ serviceAccountToken: "${moc_infra_token}"
+ owner: janus-authors
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ janus-idp.backstage-plugin-ocm:
+ dynamicRoutes:
+ - path: /ocm
+ module: OcmPlugin
+ importName: OcmPage
+ menuItem:
+ icon: Storage
+ text: Clusters
+ mountPoints:
+ - mountPoint: entity.page.overview/context
+ module: OcmPlugin
+ importName: ClusterContextProvider
+ - mountPoint: entity.page.overview/cards
+ module: OcmPlugin
+ importName: ClusterAvailableResourceCard
+ config:
+ layout:
+ gridRowStart: 1
+ gridColumnStart: "span 1"
+ if:
+ anyOf:
+ - isKind: resource
+ - isType: kubernetes-cluster
+ - mountPoint: entity.page.overview/cards
+ importName: ClusterInfoCard
+ module: OcmPlugin
+ config:
+ if:
+ allOf:
+ - isKind: resource
+ - isType: kubernetes-cluster
+
+ # Standalone plugins
+ - package: ./dynamic-plugins/dist/roadiehq-scaffolder-backend-module-utils-dynamic
+
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-aap-backend-dynamic
+ disabled: true
+ pluginConfig:
+ enabled:
+ aap: true
+ catalog:
+ providers:
+ aap:
+ prod:
+ baseUrl: '${AAP_BASE_URL}'
+ authorization: "${AAP_AUTH_TOKEN}"
+
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-keycloak-backend-dynamic
+ disabled: true
+ pluginConfig:
+ enabled:
+ keycloak: true
+ catalog:
+ providers:
+ keycloakOrg:
+ default:
+ baseUrl: "${KEYCLOAK_BASE_URL}"
+ loginRealm: "${KEYCLOAK_LOGIN_REALM}"
+ realm: "${KEYCLOAK_REALM}"
+ clientId: "${KEYCLOAK_CLIENT_ID}"
+ clientSecret: "${KEYCLOAK_CLIENT_SECRET}"
- package: ./dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic
disabled: true
@@ -202,3 +496,163 @@ plugins:
credentials:
accessKeyId: ${AWS_ACCESS_KEY_ID}
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
+
+ - package: ./dynamic-plugins/dist/backstage-plugin-dynatrace
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-dynatrace:
+ mountPoints:
+ - mountPoint: entity.page.monitoring/cards
+ module: DynatracePlugin
+ importName: DynatraceTab
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isDynatraceAvailable
+
+ - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-jira
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ roadiehq.backstage-plugin-jira:
+ mountPoints:
+ - mountPoint: entity.page.issues/cards
+ module: JiraPlugin
+ importName: EntityJiraOverviewCard
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isJiraAvailable
+
+ - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-datadog
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ roadiehq.backstage-plugin-datadog:
+ mountPoints:
+ - mountPoint: entity.page.monitoring/cards
+ module: DatadogPlugin
+ importName: EntityDatadogContent
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isDatadogAvailable
+
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-tekton
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ janus-idp.backstage-plugin-tekton:
+ mountPoints:
+ - mountPoint: entity.page.ci/cards
+ module: TektonPlugin
+ importName: TektonCI
+ config:
+ layout:
+ gridColumn: "1 / -1"
+ if:
+ allOf:
+ - isTektonCIAvailable
+
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-quay
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ janus-idp.backstage-plugin-quay:
+ mountPoints:
+ - mountPoint: entity.page.image-registry/cards
+ module: QuayPlugin
+ importName: QuayPage
+ config:
+ layout:
+ gridColumn: 1 / -1
+ if:
+ anyOf:
+ - isQuayAvailable
+
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-nexus-repository-manager
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ janus-idp.backstage-plugin-nexus-repository-manager:
+ mountPoints:
+ - mountPoint: entity.page.image-registry/cards
+ module: NexusRepositoryManagerPlugin
+ importName: NexusRepositoryManagerPage
+ config:
+ layout:
+ gridColumn: 1 / -1
+ if:
+ anyOf:
+ - isNexusRepositoryManagerAvailable
+
+ - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-jfrog-artifactory
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ janus-idp.backstage-plugin-jfrog-artifactory:
+ mountPoints:
+ - mountPoint: entity.page.image-registry/cards
+ module: JfrogArtifactoryPlugin
+ importName: JfrogArtifactoryPage
+ config:
+ layout:
+ gridColumn: 1 / -1
+ if:
+ anyOf:
+ - isJfrogArtifactoryAvailable
+
+ - package: ./dynamic-plugins/dist/backstage-plugin-pagerduty
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-pagerduty:
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: PagerdutyPlugin
+ importName: EntityPagerDutyCard
+ config:
+ layout:
+ gridColumnEnd: "span 6"
+ if:
+ allOf:
+ - isPluginApplicableToEntity
+
+ - package: ./dynamic-plugins/dist/backstage-plugin-lighthouse
+ disabled: true
+ pluginConfig:
+ dynamicPlugins:
+ frontend:
+ backstage.plugin-lighthouse:
+ dynamicRoutes:
+ - path: /lighthouse
+ module: LighthousePlugin
+ importName: LighthousePage
+ menuItem:
+ icon: Assessment
+ text: Lighthouse
+ mountPoints:
+ - mountPoint: entity.page.overview/cards
+ module: LighthousePlugin
+ importName: EntityLastLighthouseAuditCard
+ config:
+ layout:
+ gridColumnEnd: "span 6"
+ if:
+ allOf:
+ - isLighthouseAvailable
diff --git a/packages/app/config.d.ts b/packages/app/config.d.ts
index e8732874c3..d9f47c700f 100644
--- a/packages/app/config.d.ts
+++ b/packages/app/config.d.ts
@@ -52,7 +52,7 @@ export interface Config {
/** @deepVisibility frontend */
dynamicPlugins: {
/** @deepVisibility frontend */
- frontend: {
+ frontend?: {
[key: string]: {
dynamicRoutes: ({
[key: string]: any;
@@ -65,7 +65,7 @@ export interface Config {
text: string;
};
})[];
- routeBindings: {
+ routeBindings?: {
bindTarget: string;
bindMap: {
[key: string]: string;
@@ -74,8 +74,36 @@ export interface Config {
mountPoints: {
mountPoint: string;
module: string;
- importName?: string;
- }[];
+ importName: string;
+ config: {
+ layout?: {
+ [key: string]: string;
+ };
+ props?: {
+ [key: string]: string;
+ };
+ if?: {
+ allOf?: (
+ | {
+ [key: string]: string | string[];
+ }
+ | string
+ )[];
+ anyOf?: (
+ | {
+ [key: string]: string | string[];
+ }
+ | string
+ )[];
+ oneOf?: (
+ | {
+ [key: string]: string | string[];
+ }
+ | string
+ )[];
+ };
+ }[];
+ };
};
};
};
diff --git a/packages/app/package.json b/packages/app/package.json
index 50d31ba2af..8aebb2d9bc 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -82,7 +82,7 @@
},
"devDependencies": {
"@backstage/test-utils": "1.4.4",
- "@janus-idp/cli": "^1.3.1",
+ "@janus-idp/cli": "^1.3.2",
"@scalprum/react-test-utils": "0.0.5",
"@testing-library/dom": "8.20.1",
"@testing-library/jest-dom": "5.17.0",
diff --git a/packages/app/src/components/AppBase/AppBase.tsx b/packages/app/src/components/AppBase/AppBase.tsx
index 1a3f969cb7..738d33b140 100644
--- a/packages/app/src/components/AppBase/AppBase.tsx
+++ b/packages/app/src/components/AppBase/AppBase.tsx
@@ -17,7 +17,6 @@ import {
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import { UserSettingsPage } from '@backstage/plugin-user-settings';
-import { OcmPage } from '@janus-idp/backstage-plugin-ocm';
import React, { useContext } from 'react';
import { Route } from 'react-router-dom';
import { Root } from '../Root';
@@ -25,7 +24,6 @@ import { entityPage } from '../catalog/EntityPage';
import { HomePage } from '../home/HomePage';
import { LearningPaths } from '../learningPaths/LearningPathsPage';
import { SearchPage } from '../search/SearchPage';
-import { LighthousePage } from '@backstage/plugin-lighthouse';
import DynamicRootContext from '../DynamicRoot/DynamicRootContext';
const AppBase = () => {
@@ -83,9 +81,7 @@ const AppBase = () => {
} />
} />
- } />
} />
- } />
{dynamicRoutes.map(({ Component, path, ...props }) => (
}[]
- >((acc, { module, importName, mountPoint, scope }) => {
+ {
+ mountPoint: string;
+ Component: React.ComponentType<{}>;
+ config?: ScalprumMountPointConfig;
+ }[]
+ >((acc, { module, importName, mountPoint, scope, config }) => {
const Component = remotePlugins[scope]?.[module]?.[importName];
// Only add mount points that have a component
if (Component) {
acc.push({
mountPoint,
Component: remotePlugins[scope][module][importName],
+ config: {
+ ...config,
+ if: configIfToCallable(
+ Object.fromEntries(
+ Object.entries(config?.if || {}).map(([k, v]) => [
+ k,
+ v.map(c =>
+ typeof c === 'string' ? remotePlugins[scope][module][c] : c,
+ ),
+ ]),
+ ),
+ ),
+ },
});
}
return acc;
@@ -105,7 +125,10 @@ const DynamicRoot = ({
if (!acc[entry.mountPoint]) {
acc[entry.mountPoint] = [];
}
- acc[entry.mountPoint].push(entry.Component);
+ acc[entry.mountPoint].push({
+ component: entry.Component,
+ config: entry.config,
+ });
return acc;
}, {});
getScalprum().api.mountPoints = mountPointComponents;
diff --git a/packages/app/src/components/DynamicRoot/DynamicRootContext.tsx b/packages/app/src/components/DynamicRoot/DynamicRootContext.tsx
index ec54ffe4ec..4bd4f33255 100644
--- a/packages/app/src/components/DynamicRoot/DynamicRootContext.tsx
+++ b/packages/app/src/components/DynamicRoot/DynamicRootContext.tsx
@@ -1,6 +1,7 @@
import React, { createContext } from 'react';
import { ScalprumComponentProps } from '@scalprum/react-core';
+import { Entity } from '@backstage/catalog-model';
export type RouteBinding = {
bindTarget: string;
@@ -24,7 +25,32 @@ export type DynamicRootContextValue = DynamicModuleEntry & {
Component: React.ComponentType;
};
-export type ScalprumMountPoint = React.ComponentType<{}>;
+type ScalprumMountPointConfigBase = {
+ layout?: Record;
+ props?: Record;
+};
+
+export type ScalprumMountPointConfig = ScalprumMountPointConfigBase & {
+ if: (e: Entity) => boolean | Promise;
+};
+
+export type ScalprumMountPointConfigRawIf = {
+ [key in 'allOf' | 'oneOf' | 'anyOf']?: (
+ | {
+ [key: string]: string | string[];
+ }
+ | Function
+ )[];
+};
+
+export type ScalprumMountPointConfigRaw = ScalprumMountPointConfigBase & {
+ if?: ScalprumMountPointConfigRawIf;
+};
+
+export type ScalprumMountPoint = {
+ component: React.ComponentType<{}>;
+ config?: ScalprumMountPointConfig;
+};
export type RemotePlugins = {
[scope: string]: {
diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx
index 11e5e94f54..ac4c35c7e8 100644
--- a/packages/app/src/components/Root/Root.tsx
+++ b/packages/app/src/components/Root/Root.tsx
@@ -21,7 +21,6 @@ import MenuIcon from '@mui/icons-material/Menu';
import MapIcon from '@mui/icons-material/MyLocation';
import SchoolIcon from '@mui/icons-material/School';
import SearchIcon from '@mui/icons-material/Search';
-import AssessmentIcon from '@mui/icons-material/Assessment';
import { makeStyles } from 'tss-react/mui';
import React, { PropsWithChildren, useContext } from 'react';
import { SidebarLogo } from './SidebarLogo';
@@ -98,11 +97,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
to="tech-radar"
text="Tech Radar"
/>
-
{dynamicRoutes.map(({ menuItem, path }) => {
if (menuItem) {
return (
diff --git a/packages/app/src/components/catalog/EntityPage/Content/CD.tsx b/packages/app/src/components/catalog/EntityPage/Content/CD.tsx
deleted file mode 100644
index c14061d2ae..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/CD.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import Grid from '@mui/material/Grid';
-import { EntityArgoCDHistoryCard } from '@roadiehq/backstage-plugin-argo-cd';
-import React from 'react';
-
-export const cdContent = (
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/CI.tsx b/packages/app/src/components/catalog/EntityPage/Content/CI.tsx
deleted file mode 100644
index 7f3d407b9a..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/CI.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { type Entity } from '@backstage/catalog-model';
-import {
- EntityAzurePipelinesContent,
- isAzureDevOpsAvailable,
-} from '@backstage/plugin-azure-devops';
-import { EntitySwitch } from '@backstage/plugin-catalog';
-import {
- EntityGithubActionsContent,
- isGithubActionsAvailable,
-} from '@backstage/plugin-github-actions';
-import {
- EntityGitlabPipelinesTable,
- isGitlabAvailable,
-} from '@immobiliarelabs/backstage-plugin-gitlab';
-import {
- TektonCI,
- isTektonCIAvailable,
-} from '@janus-idp/backstage-plugin-tekton';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-
-const ifCIs: ((e: Entity) => boolean)[] = [
- isGithubActionsAvailable,
- isGitlabAvailable,
- isTektonCIAvailable,
- isAzureDevOpsAvailable,
-];
-
-export const isCIsAvailable = (e: Entity) => ifCIs.some(f => f(e));
-
-export const ciContent = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/Dependencies.tsx b/packages/app/src/components/catalog/EntityPage/Content/Dependencies.tsx
deleted file mode 100644
index 7ddf8b0273..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/Dependencies.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import {
- EntityConsumedApisCard,
- EntityProvidedApisCard,
-} from '@backstage/plugin-api-docs';
-import {
- EntityDependsOnComponentsCard,
- EntityDependsOnResourcesCard,
- EntityHasSubcomponentsCard,
-} from '@backstage/plugin-catalog';
-import {
- Direction,
- EntityCatalogGraphCard,
-} from '@backstage/plugin-catalog-graph';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-
-export const dependenciesContent = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/Docs.tsx b/packages/app/src/components/catalog/EntityPage/Content/Docs.tsx
deleted file mode 100644
index 2f0b62a639..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/Docs.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
-import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
-import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-
-export const techdocsContent = (
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/EntityWarning.tsx b/packages/app/src/components/catalog/EntityPage/Content/EntityWarning.tsx
deleted file mode 100644
index ef72595b99..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/EntityWarning.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import {
- EntityOrphanWarning,
- EntityProcessingErrorsPanel,
- EntityRelationWarning,
- EntitySwitch,
- hasCatalogProcessingErrors,
- hasRelationWarnings,
- isOrphan,
-} from '@backstage/plugin-catalog';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-
-export const entityWarningContent = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/ImageRegistry.tsx b/packages/app/src/components/catalog/EntityPage/Content/ImageRegistry.tsx
deleted file mode 100644
index e136c9e57c..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/ImageRegistry.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { type Entity } from '@backstage/catalog-model';
-import { EntitySwitch } from '@backstage/plugin-catalog';
-import {
- JfrogArtifactoryPage,
- isJfrogArtifactoryAvailable,
-} from '@janus-idp/backstage-plugin-jfrog-artifactory';
-import { QuayPage, isQuayAvailable } from '@janus-idp/backstage-plugin-quay';
-import {
- isNexusRepositoryManagerAvailable,
- NexusRepositoryManagerPage,
-} from '@janus-idp/backstage-plugin-nexus-repository-manager';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-
-const ifImageRegistries: ((e: Entity) => boolean)[] = [
- isQuayAvailable,
- isJfrogArtifactoryAvailable,
-];
-
-export const isImageRegistriesAvailable = (e: Entity) =>
- ifImageRegistries.some(f => f(e));
-
-export const imageRegistry = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/Issues.tsx b/packages/app/src/components/catalog/EntityPage/Content/Issues.tsx
deleted file mode 100644
index 99a2ec33b3..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/Issues.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { type Entity } from '@backstage/catalog-model';
-import { EntitySwitch } from '@backstage/plugin-catalog';
-import { GithubIssuesCard } from '@backstage/plugin-github-issues';
-import {
- EntityGitlabIssuesTable,
- isGitlabAvailable,
-} from '@immobiliarelabs/backstage-plugin-gitlab';
-import Grid from '@mui/material/Grid';
-import { isGithubPullRequestsAvailable } from '@roadiehq/backstage-plugin-github-pull-requests';
-import {
- EntityJiraOverviewCard,
- isJiraAvailable,
-} from '@roadiehq/backstage-plugin-jira';
-import React from 'react';
-
-const ifIssues: ((e: Entity) => boolean)[] = [
- isGithubPullRequestsAvailable,
- isGitlabAvailable,
- isJiraAvailable,
-];
-
-export const isIssuesAvailable = (e: Entity) => ifIssues.some(f => f(e));
-
-export const issuesContent = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* TODO: update GithubIssuesCard if entity check once its available */}
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/Monitoring.tsx b/packages/app/src/components/catalog/EntityPage/Content/Monitoring.tsx
deleted file mode 100644
index 73a5603be8..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/Monitoring.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { type Entity } from '@backstage/catalog-model';
-import { EntitySwitch } from '@backstage/plugin-catalog';
-import Grid from '@mui/material/Grid';
-import {
- DynatraceTab,
- isDynatraceAvailable,
-} from '@backstage/plugin-dynatrace';
-import {
- EntityDatadogContent,
- isDatadogAvailable,
-} from '@roadiehq/backstage-plugin-datadog';
-import React from 'react';
-
-const ifMonitoring: ((e: Entity) => boolean)[] = [
- isDatadogAvailable,
- isDynatraceAvailable,
-];
-
-export const isMonitoringAvailable = (e: Entity) =>
- ifMonitoring.some(f => f(e));
-
-export const monitoringContent = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/Overview.tsx b/packages/app/src/components/catalog/EntityPage/Content/Overview.tsx
deleted file mode 100644
index 12db9040c4..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/Overview.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-import { EmptyState } from '@backstage/core-components';
-import {
- EntityAboutCard,
- EntityLinksCard,
- EntitySwitch,
-} from '@backstage/plugin-catalog';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-
-import {
- EntityLatestJenkinsRunCard,
- isJenkinsAvailable,
-} from '@backstage/plugin-jenkins';
-import { EntitySonarQubeCard } from '@backstage/plugin-sonarqube';
-import { isSonarQubeAvailable } from '@backstage/plugin-sonarqube-react';
-import {
- EntityGitlabMergeRequestStatsCard,
- isGitlabAvailable,
-} from '@immobiliarelabs/backstage-plugin-gitlab';
-import { EntityArgoCDOverviewCard } from '@roadiehq/backstage-plugin-argo-cd';
-import {
- EntityGithubInsightsComplianceCard,
- isGithubInsightsAvailable,
-} from '@roadiehq/backstage-plugin-github-insights';
-import {
- EntityGithubPullRequestsOverviewCard,
- isGithubPullRequestsAvailable,
-} from '@roadiehq/backstage-plugin-github-pull-requests';
-import {
- EntityDependabotAlertsCard,
- isSecurityInsightsAvailable,
-} from '@roadiehq/backstage-plugin-security-insights';
-import {
- isPluginApplicableToEntity as isPagerDutyAvailable,
- EntityPagerDutyCard,
-} from '@backstage/plugin-pagerduty';
-import {
- EntityLastLighthouseAuditCard,
- isLighthouseAvailable,
-} from '@backstage/plugin-lighthouse';
-import { isCIsAvailable } from './CI';
-import { entityWarningContent } from './EntityWarning';
-import { isPRsAvailable } from './PullRequests';
-
-export const overviewContent = (
-
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- !isPRsAvailable(e)}>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Use `isArgocdAvailable` once its fixed */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/PullRequests.tsx b/packages/app/src/components/catalog/EntityPage/Content/PullRequests.tsx
deleted file mode 100644
index f85288cae8..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/PullRequests.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { type Entity } from '@backstage/catalog-model';
-import {
- EntityAzurePullRequestsContent,
- isAzureDevOpsAvailable,
-} from '@backstage/plugin-azure-devops';
-import { EntitySwitch } from '@backstage/plugin-catalog';
-import {
- EntityGitlabMergeRequestsTable,
- isGitlabAvailable,
-} from '@immobiliarelabs/backstage-plugin-gitlab';
-import Grid from '@mui/material/Grid';
-import {
- EntityGithubPullRequestsContent,
- isGithubPullRequestsAvailable,
-} from '@roadiehq/backstage-plugin-github-pull-requests';
-import React from 'react';
-
-const ifPRs: ((e: Entity) => boolean)[] = [
- isGithubPullRequestsAvailable,
- isGitlabAvailable,
- isAzureDevOpsAvailable,
-];
-
-export const isPRsAvailable = (e: Entity) => ifPRs.some(f => f(e));
-
-export const prContent = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/SecurityInsights.tsx b/packages/app/src/components/catalog/EntityPage/Content/SecurityInsights.tsx
deleted file mode 100644
index 3ce67c9c30..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/SecurityInsights.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import Grid from '@mui/material/Grid';
-import {
- EntityGithubDependabotContent,
- EntitySecurityInsightsContent,
-} from '@roadiehq/backstage-plugin-security-insights';
-import React from 'react';
-
-export const securityContent = (
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Content/index.tsx b/packages/app/src/components/catalog/EntityPage/Content/index.tsx
deleted file mode 100644
index ff4cbc2073..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Content/index.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-export * from './CD';
-export * from './CI';
-export * from './Dependencies';
-export * from './Docs';
-export * from './ImageRegistry';
-export * from './Issues';
-export * from './Monitoring';
-export * from './Overview';
-export * from './PullRequests';
-export * from './SecurityInsights';
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/Api.tsx b/packages/app/src/components/catalog/EntityPage/Pages/Api.tsx
deleted file mode 100644
index 033ab60154..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/Api.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import {
- EntityApiDefinitionCard,
- EntityConsumingComponentsCard,
- EntityProvidingComponentsCard,
-} from '@backstage/plugin-api-docs';
-import {
- EntityAboutCard,
- EntityLayout,
- EntityLinksCard,
-} from '@backstage/plugin-catalog';
-import { EntityCatalogGraphCard } from '@backstage/plugin-catalog-graph';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-import { entityWarningContent } from '../Content/EntityWarning';
-
-export const apiPage = (
-
-
-
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/Component.tsx b/packages/app/src/components/catalog/EntityPage/Pages/Component.tsx
deleted file mode 100644
index dea2a70878..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/Component.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-import {
- EntityConsumedApisCard,
- EntityProvidedApisCard,
-} from '@backstage/plugin-api-docs';
-import {
- EntityLayout,
- EntitySwitch,
- isComponentType,
-} from '@backstage/plugin-catalog';
-import { EntityKubernetesContent } from '@backstage/plugin-kubernetes';
-import {
- EntityLighthouseContent,
- isLighthouseAvailable,
-} from '@backstage/plugin-lighthouse';
-import { TektonCI } from '@janus-idp/backstage-plugin-tekton';
-import { TopologyPage } from '@janus-idp/backstage-plugin-topology';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-import {
- cdContent,
- ciContent,
- dependenciesContent,
- imageRegistry,
- isCIsAvailable,
- isImageRegistriesAvailable,
- isIssuesAvailable,
- isMonitoringAvailable,
- isPRsAvailable,
- issuesContent,
- monitoringContent,
- overviewContent,
- prContent,
- techdocsContent,
-} from '../Content';
-import { defaultEntityPage } from './DefaultEntity';
-
-const componentEntityPage = (componentType: 'service' | 'website') => (
-
-
- {overviewContent}
-
-
-
-
-
-
-
- {issuesContent}
-
-
-
- {prContent}
-
-
-
- {ciContent}
-
-
- {/* Use `isArgocdAvailable` once its fixed */}
-
- {cdContent}
-
-
-
-
-
-
-
-
-
-
-
- {imageRegistry}
-
-
-
- {monitoringContent}
-
-
-
-
-
-
- {componentType === 'service' && (
-
-
-
-
-
-
-
-
-
-
- )}
-
-
- {dependenciesContent}
-
-
-
- {techdocsContent}
-
-
-);
-
-export const componentPage = (
-
-
- {componentEntityPage('service')}
-
-
-
- {componentEntityPage('website')}
-
-
- {defaultEntityPage}
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/DefaultEntity.tsx b/packages/app/src/components/catalog/EntityPage/Pages/DefaultEntity.tsx
deleted file mode 100644
index 20282c2b32..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/DefaultEntity.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { EntityLayout } from '@backstage/plugin-catalog';
-import React from 'react';
-import { overviewContent, techdocsContent } from '../Content';
-
-export const defaultEntityPage = (
-
-
- {overviewContent}
-
-
-
- {techdocsContent}
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/Domain.tsx b/packages/app/src/components/catalog/EntityPage/Pages/Domain.tsx
deleted file mode 100644
index d87730ef0f..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/Domain.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import {
- EntityAboutCard,
- EntityHasSystemsCard,
- EntityLayout,
-} from '@backstage/plugin-catalog';
-import { EntityCatalogGraphCard } from '@backstage/plugin-catalog-graph';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-import { entityWarningContent } from '../Content/EntityWarning';
-
-export const domainPage = (
-
-
-
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/Group.tsx b/packages/app/src/components/catalog/EntityPage/Pages/Group.tsx
deleted file mode 100644
index f5664e2952..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/Group.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { EntityLayout } from '@backstage/plugin-catalog';
-import {
- EntityGroupProfileCard,
- EntityMembersListCard,
- EntityOwnershipCard,
-} from '@backstage/plugin-org';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-import { entityWarningContent } from '../Content/EntityWarning';
-
-export const groupPage = (
-
-
-
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/Resource.tsx b/packages/app/src/components/catalog/EntityPage/Pages/Resource.tsx
deleted file mode 100644
index 3f7d51e33a..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/Resource.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import {
- EntityAboutCard,
- EntityHasSystemsCard,
- EntityLayout,
- EntityLinksCard,
- EntitySwitch,
-} from '@backstage/plugin-catalog';
-import { EntityCatalogGraphCard } from '@backstage/plugin-catalog-graph';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-
-import {
- ClusterAvailableResourceCard,
- ClusterContextProvider,
- ClusterInfoCard,
-} from '@janus-idp/backstage-plugin-ocm';
-import { isType } from '../../utils';
-import { entityWarningContent } from '../Content/EntityWarning';
-
-export const resourcePage = (
-
-
-
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/System.tsx b/packages/app/src/components/catalog/EntityPage/Pages/System.tsx
deleted file mode 100644
index ef261b498f..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/System.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import {
- RELATION_API_CONSUMED_BY,
- RELATION_API_PROVIDED_BY,
- RELATION_CONSUMES_API,
- RELATION_DEPENDENCY_OF,
- RELATION_DEPENDS_ON,
- RELATION_HAS_PART,
- RELATION_PART_OF,
- RELATION_PROVIDES_API,
-} from '@backstage/catalog-model';
-import { EntityHasApisCard } from '@backstage/plugin-api-docs';
-import {
- EntityAboutCard,
- EntityHasComponentsCard,
- EntityHasResourcesCard,
- EntityLayout,
- EntityLinksCard,
-} from '@backstage/plugin-catalog';
-import {
- Direction,
- EntityCatalogGraphCard,
-} from '@backstage/plugin-catalog-graph';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-import { entityWarningContent } from '../Content/EntityWarning';
-
-export const systemPage = (
-
-
-
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/User.tsx b/packages/app/src/components/catalog/EntityPage/Pages/User.tsx
deleted file mode 100644
index b4ec1f9c6d..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/User.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { EntityLayout } from '@backstage/plugin-catalog';
-import {
- EntityOwnershipCard,
- EntityUserProfileCard,
-} from '@backstage/plugin-org';
-import Grid from '@mui/material/Grid';
-import React from 'react';
-import { entityWarningContent } from '../Content/EntityWarning';
-
-export const userPage = (
-
-
-
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/app/src/components/catalog/EntityPage/Pages/index.tsx b/packages/app/src/components/catalog/EntityPage/Pages/index.tsx
deleted file mode 100644
index 6f03788200..0000000000
--- a/packages/app/src/components/catalog/EntityPage/Pages/index.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-export * from './Api';
-export * from './Component';
-export * from './DefaultEntity';
-export * from './Domain';
-export * from './Group';
-export * from './Resource';
-export * from './System';
-export * from './User';
diff --git a/packages/app/src/components/catalog/EntityPage/index.tsx b/packages/app/src/components/catalog/EntityPage/index.tsx
index a0179b656a..e30fa7eab2 100644
--- a/packages/app/src/components/catalog/EntityPage/index.tsx
+++ b/packages/app/src/components/catalog/EntityPage/index.tsx
@@ -1,27 +1,345 @@
-import { EntitySwitch, isKind } from '@backstage/plugin-catalog';
import React from 'react';
-
import {
- componentPage,
- defaultEntityPage,
- apiPage,
- groupPage,
- userPage,
- systemPage,
- domainPage,
- resourcePage,
-} from './Pages';
+ EntityApiDefinitionCard,
+ EntityConsumedApisCard,
+ EntityConsumingComponentsCard,
+ EntityHasApisCard,
+ EntityProvidedApisCard,
+ EntityProvidingComponentsCard,
+} from '@backstage/plugin-api-docs';
+import {
+ EntityAboutCard,
+ EntityDependsOnComponentsCard,
+ EntityDependsOnResourcesCard,
+ EntityHasComponentsCard,
+ EntityHasResourcesCard,
+ EntityHasSubcomponentsCard,
+ EntityHasSystemsCard,
+ EntityLayout,
+ EntityLinksCard,
+ EntityOrphanWarning,
+ EntityProcessingErrorsPanel,
+ EntityRelationWarning,
+ EntitySwitch,
+ hasCatalogProcessingErrors,
+ hasRelationWarnings,
+ isKind,
+ isOrphan,
+} from '@backstage/plugin-catalog';
+import tab from '../tab';
+import { hasLinks, isType } from '../utils';
+import {
+ Direction,
+ EntityCatalogGraphCard,
+} from '@backstage/plugin-catalog-graph';
+import {
+ EntityTechdocsContent,
+ isTechDocsAvailable,
+} from '@backstage/plugin-techdocs';
+import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
+import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
+import {
+ EntityGroupProfileCard,
+ EntityMembersListCard,
+ EntityOwnershipCard,
+ EntityUserProfileCard,
+} from '@backstage/plugin-org';
+import {
+ RELATION_API_CONSUMED_BY,
+ RELATION_API_PROVIDED_BY,
+ RELATION_CONSUMES_API,
+ RELATION_DEPENDENCY_OF,
+ RELATION_DEPENDS_ON,
+ RELATION_HAS_PART,
+ RELATION_PART_OF,
+ RELATION_PROVIDES_API,
+} from '@backstage/catalog-model';
+import Grid from '../Grid';
export const entityPage = (
-
-
-
-
-
-
-
-
-
- {defaultEntityPage}
-
+
+ {tab({
+ path: '/',
+ title: 'Overview',
+ mountPoint: 'entity.page.overview',
+ children: (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ ),
+ })}
+
+ {tab({
+ path: '/topology',
+ title: 'Topology',
+ mountPoint: 'entity.page.topology',
+ })}
+
+ {tab({
+ path: '/issues',
+ title: 'Issues',
+ mountPoint: 'entity.page.issues',
+ })}
+
+ {tab({
+ path: '/pr',
+ title: 'Pull/Merge Requests',
+ mountPoint: 'entity.page.pull-requests',
+ })}
+
+ {tab({
+ path: '/ci',
+ title: 'CI',
+ mountPoint: 'entity.page.ci',
+ })}
+
+ {tab({
+ path: '/cd',
+ title: 'CD',
+ mountPoint: 'entity.page.cd',
+ })}
+
+ {tab({
+ path: '/kubernetes',
+ title: 'Kubernetes',
+ mountPoint: 'entity.page.kubernetes',
+ })}
+
+ {tab({
+ path: '/tekton',
+ title: 'Tekton',
+ mountPoint: 'entity.page.tekton',
+ })}
+
+ {tab({
+ path: '/image-registry',
+ title: 'Image Registry',
+ mountPoint: 'entity.page.image-registry',
+ })}
+
+ {tab({
+ path: '/monitoring',
+ title: 'Monitoring',
+ mountPoint: 'entity.page.monitoring',
+ })}
+
+ {tab({
+ path: '/lighthouse',
+ title: 'Lighthouse',
+ mountPoint: 'entity.page.lighthouse',
+ })}
+
+ {tab({
+ path: '/api',
+ title: 'Api',
+ mountPoint: 'entity.page.api',
+ if: e => isType('service')(e) && isKind('component')(e),
+ children: (
+
+ isType('service')(e) && isKind('component')(e)}
+ >
+
+
+
+
+
+
+
+
+ ),
+ })}
+
+ {tab({
+ path: '/dependencies',
+ title: 'Dependencies',
+ mountPoint: 'entity.page.dependencies',
+ if: isKind('component'),
+ children: (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+ })}
+
+ {tab({
+ path: '/docs',
+ title: 'Docs',
+ mountPoint: 'entity.page.docs',
+ if: isTechDocsAvailable,
+ children: (
+
+
+
+
+
+
+
+
+
+
+
+ ),
+ })}
+
+ {tab({
+ path: '/definition',
+ title: 'Definition',
+ mountPoint: 'entity.page.definition',
+ if: isKind('api'),
+ children: (
+
+
+
+
+
+
+
+ ),
+ })}
+
+ {tab({
+ path: '/diagram',
+ title: 'Diagram',
+ mountPoint: 'entity.page.diagram',
+ if: isKind('system'),
+ children: (
+
+
+
+
+
+
+
+ ),
+ })}
+
);
diff --git a/packages/app/src/components/catalog/Grid/Grid.tsx b/packages/app/src/components/catalog/Grid/Grid.tsx
new file mode 100644
index 0000000000..8e9ad36fbe
--- /dev/null
+++ b/packages/app/src/components/catalog/Grid/Grid.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import Box, { BoxProps } from '@mui/material/Box';
+import { makeStyles } from 'tss-react/mui';
+
+const useStyles = makeStyles()(theme => ({
+ grid: {
+ display: 'grid',
+ gridTemplateColumns: 'repeat(12, 1fr)',
+ gridGap: theme.spacing(3),
+ gridAutoFlow: 'dense',
+ },
+}));
+
+const Grid = ({
+ container = false,
+ item = true,
+ children,
+ ...props
+}: React.PropsWithChildren<
+ { container?: boolean; item?: boolean } & BoxProps
+>) => {
+ const { classes } = useStyles();
+
+ if (container) {
+ return (
+
+ {children}
+
+ );
+ }
+ if (item) {
+ return {children};
+ }
+ return null;
+};
+
+export default Grid;
diff --git a/packages/app/src/components/catalog/Grid/index.ts b/packages/app/src/components/catalog/Grid/index.ts
new file mode 100644
index 0000000000..3d919c9acb
--- /dev/null
+++ b/packages/app/src/components/catalog/Grid/index.ts
@@ -0,0 +1 @@
+export { default } from './Grid';
diff --git a/packages/app/src/components/catalog/tab/index.ts b/packages/app/src/components/catalog/tab/index.ts
new file mode 100644
index 0000000000..bd1dff4eb0
--- /dev/null
+++ b/packages/app/src/components/catalog/tab/index.ts
@@ -0,0 +1 @@
+export { default } from './tab';
diff --git a/packages/app/src/components/catalog/tab/tab.tsx b/packages/app/src/components/catalog/tab/tab.tsx
new file mode 100644
index 0000000000..0f12032a10
--- /dev/null
+++ b/packages/app/src/components/catalog/tab/tab.tsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import getMountPointData from '../../../utils/dynamicUI/getMountPointData';
+import { EntityLayout, EntitySwitch } from '@backstage/plugin-catalog';
+import Grid from '../Grid';
+import { Entity } from '@backstage/catalog-model';
+
+export type TabProps = {
+ path: string;
+ title: string;
+ mountPoint: string;
+ if?: (e: Entity) => boolean;
+ children?: React.ReactNode;
+};
+
+const tab = ({
+ path,
+ title,
+ mountPoint,
+ children,
+ if: condition,
+}: TabProps) => (
+
+ (condition ? condition(e) : Boolean(children)) ||
+ getMountPointData(`${mountPoint}/cards`)
+ .flatMap(({ config }) => config.if)
+ .some(c => c(e))
+ }
+ >
+ {getMountPointData(`${mountPoint}/context`).reduce(
+ (acc, { component: Component }) => (
+ {acc}
+ ),
+
+ {children}
+ {getMountPointData(`${mountPoint}/cards`).map(
+ ({ component: Component, config }) => (
+
+
+
+
+
+
+
+ ),
+ )}
+ ,
+ )}
+
+);
+
+export default tab;
diff --git a/packages/app/src/components/catalog/utils.tsx b/packages/app/src/components/catalog/utils.tsx
index af4898acc9..ee4c683027 100644
--- a/packages/app/src/components/catalog/utils.tsx
+++ b/packages/app/src/components/catalog/utils.tsx
@@ -8,3 +8,8 @@ export const isType = (types: string | string[]) => (entity: Entity) => {
? entity?.spec?.type === types
: types.includes(entity.spec.type as string);
};
+export const hasAnnotation = (keys: string) => (entity: Entity) =>
+ Boolean(entity.metadata.annotations?.[keys]);
+
+export const hasLinks = (entity: Entity) =>
+ Boolean(entity.metadata.links?.length);
diff --git a/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts b/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts
index 537e73fb73..a12147da57 100644
--- a/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts
+++ b/packages/app/src/utils/dynamicUI/extractDynamicConfig.ts
@@ -1,7 +1,12 @@
import { defaultConfigLoader } from '@backstage/core-app-api';
+import { Entity } from '@backstage/catalog-model';
+import { isKind } from '@backstage/plugin-catalog';
+import { hasAnnotation, isType } from '../../components/catalog/utils';
import {
DynamicModuleEntry,
RouteBinding,
+ ScalprumMountPointConfigRaw,
+ ScalprumMountPointConfigRawIf,
} from '../../components/DynamicRoot/DynamicRootContext';
type AppConfig = {
@@ -37,6 +42,45 @@ type CustomProperties = {
mountPoints?: MountPoint[];
};
+const conditionsArrayMapper = (
+ condition:
+ | {
+ [key: string]: string | string[];
+ }
+ | Function,
+) => {
+ if (typeof condition === 'function') {
+ return (entity: Entity) => Boolean(condition(entity));
+ }
+ if (condition.isKind) {
+ return isKind(condition.isKind);
+ }
+ if (condition.isType) {
+ return isType(condition.isType);
+ }
+ if (condition.hasAnnotation) {
+ return hasAnnotation(condition.hasAnnotation as string);
+ }
+ return () => false;
+};
+
+export const configIfToCallable =
+ (conditional: ScalprumMountPointConfigRawIf) => (e: Entity) => {
+ if (conditional?.allOf) {
+ return conditional.allOf.map(conditionsArrayMapper).every(f => f(e));
+ }
+ if (conditional?.anyOf) {
+ return conditional.anyOf.map(conditionsArrayMapper).some(f => f(e));
+ }
+ if (conditional?.oneOf) {
+ return (
+ conditional.oneOf.map(conditionsArrayMapper).filter(f => f(e))
+ .length === 1
+ );
+ }
+ return true;
+ };
+
async function extractDynamicConfig() {
// Extract routes lists and app bindings from the app config file
const appsConfig = await defaultConfigLoader();
@@ -48,6 +92,7 @@ async function extractDynamicConfig() {
module: string;
importName: string;
mountPoint: string;
+ config?: ScalprumMountPointConfigRaw;
}[];
}>(
(acc, { data }) => {
diff --git a/packages/app/src/utils/dynamicUI/getMountPointData.ts b/packages/app/src/utils/dynamicUI/getMountPointData.ts
index ab1dcf4f6c..0e17888134 100644
--- a/packages/app/src/utils/dynamicUI/getMountPointData.ts
+++ b/packages/app/src/utils/dynamicUI/getMountPointData.ts
@@ -1,6 +1,9 @@
import { getScalprum } from '@scalprum/core';
+import { ScalprumMountPointConfig } from '../../components/DynamicRoot/DynamicRootContext';
-function getMountPointData(mountPoint: string): T[] {
+function getMountPointData(
+ mountPoint: string,
+): { config: ScalprumMountPointConfig; component: T }[] {
return getScalprum().api.mountPoints?.[mountPoint] ?? [];
}
diff --git a/yarn.lock b/yarn.lock
index dbff2f5b3c..a44cbeaca0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5427,7 +5427,7 @@
lodash "^4.17.21"
react-use "^17.4.0"
-"@janus-idp/cli@1.3.1", "@janus-idp/cli@^1.3.1":
+"@janus-idp/cli@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@janus-idp/cli/-/cli-1.3.1.tgz#8272576a20ec88241c082d233f0a6d0e29cae77e"
integrity sha512-1GRfojww/cj3J0eNV3a6c7xE13f4HjqDb4ad0O2wirRfzY3aBvCl1/nCucmReYtpBI5TuQPmDL8O8S+7IixhBQ==
@@ -5489,6 +5489,68 @@
yml-loader "^2.1.0"
yn "^4.0.0"
+"@janus-idp/cli@^1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@janus-idp/cli/-/cli-1.3.2.tgz#e659eaf71c12c125047968650b6f047f58b76ef7"
+ integrity sha512-AmzLlxUpZ2RGoGC5GKJ5JZ/mSUrEf5vpwpu6/V73i+dyyLnV3c28JFE+WwW9b4CRN7b2yzkjFxplc302JoI72g==
+ dependencies:
+ "@backstage/cli-common" "^0.1.13"
+ "@backstage/cli-node" "^0.1.5"
+ "@backstage/config" "^1.1.1"
+ "@backstage/config-loader" "^1.5.1"
+ "@backstage/errors" "^1.2.3"
+ "@backstage/eslint-plugin" "^0.1.3"
+ "@backstage/types" "^1.1.1"
+ "@manypkg/get-packages" "^1.1.3"
+ "@openshift/dynamic-plugin-sdk-webpack" "^3.0.0"
+ "@pmmmwh/react-refresh-webpack-plugin" "^0.5.7"
+ "@rollup/plugin-commonjs" "^25.0.4"
+ "@rollup/plugin-json" "^6.0.0"
+ "@rollup/plugin-node-resolve" "^15.2.1"
+ "@rollup/plugin-yaml" "^4.0.0"
+ "@svgr/rollup" "^8.1.0"
+ "@svgr/webpack" "^6.5.1"
+ "@yarnpkg/lockfile" "^1.1.0"
+ "@yarnpkg/parsers" "^3.0.0-rc.4"
+ bfj "^7.0.2"
+ chalk "^4.0.0"
+ chokidar "^3.3.1"
+ commander "^9.1.0"
+ css-loader "^6.5.1"
+ esbuild "^0.19.0"
+ esbuild-loader "^2.18.0"
+ eslint "^8.49.0"
+ eslint-config-prettier "^8.10.0"
+ eslint-webpack-plugin "^3.2.0"
+ express "^4.18.2"
+ fork-ts-checker-webpack-plugin "^7.0.0-alpha.8"
+ fs-extra "^10.1.0"
+ handlebars "^4.7.7"
+ html-webpack-plugin "^5.3.1"
+ inquirer "^8.2.0"
+ lodash "^4.17.21"
+ mini-css-extract-plugin "^2.4.2"
+ node-libs-browser "^2.2.1"
+ npm-packlist "^5.0.0"
+ ora "^5.3.0"
+ postcss "^8.2.13"
+ process "^0.11.10"
+ react-dev-utils "^12.0.0-next.60"
+ react-refresh "^0.14.0"
+ recursive-readdir "^2.2.2"
+ rollup "^2.78.0"
+ rollup-plugin-dts "^4.0.1"
+ rollup-plugin-esbuild "^4.7.2"
+ rollup-plugin-postcss "^4.0.0"
+ rollup-pluginutils "^2.8.2"
+ semver "^7.5.4"
+ style-loader "^3.3.1"
+ swc-loader "^0.2.3"
+ webpack "^5.89.0"
+ webpack-dev-server "^4.15.1"
+ yml-loader "^2.1.0"
+ yn "^4.0.0"
+
"@janus-idp/shared-react@2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@janus-idp/shared-react/-/shared-react-2.0.0.tgz#4330f480f99bdb7c291f0db479122b2e3f94b8de"