Use uniform document titles in configuration pages

Squash commits of branch feature/uniform_configuration_document_titles:

- Use uniform document titles in configuration pages
- Use different titles for global, repository and namespace config
- Make the code a lot prettier
- Remove detailed configuration title
This commit is contained in:
Rene Pfeuffer
2025-04-30 13:25:26 +02:00
parent 9423f54d6d
commit 63aa914e79
6 changed files with 69 additions and 5 deletions

View File

@@ -0,0 +1,2 @@
- type: changed
description: Uniform document titles for configuration pages

View File

@@ -21,6 +21,8 @@ import { Route } from "react-router-dom";
import { useTranslation, WithTranslation, withTranslation } from "react-i18next";
import { Link, Links, Namespace, Repository } from "@scm-manager/ui-types";
import { urls } from "@scm-manager/ui-api";
import { useDocumentTitleForRepository } from "@scm-manager/ui-core";
import { useDocumentTitle } from "@scm-manager/ui-core";
type GlobalRouteProps = {
url: string;
@@ -75,10 +77,20 @@ class ConfigurationBinder {
// route for global configuration, passes the link from the index resource to component
const ConfigRoute = ({ url, links, ...additionalProps }: GlobalRouteProps) => {
const link = links[linkName];
const TitledGlobalSettingComponent: FC = ({ children }) => {
const [t] = useTranslation(this.i18nNamespace);
const [commonTranslation] = useTranslation("commons");
useDocumentTitle(t(labelI18nKey), commonTranslation("documentTitle.globalConfiguration"));
return <>{children}</>;
};
if (link) {
return this.route(
url + "/settings" + to,
<ConfigurationComponent link={(link as Link).href} {...additionalProps} />
<TitledGlobalSettingComponent>
<ConfigurationComponent link={(link as Link).href} {...additionalProps} />
</TitledGlobalSettingComponent>
);
}
};
@@ -138,7 +150,13 @@ class ConfigurationBinder {
binder.bind("repository.route", RepoRoute, repoPredicate);
}
bindRepositorySetting(to: string, labelI18nKey: string, linkName: string, RepositoryComponent: any, sortKey?: string) {
bindRepositorySetting(
to: string,
labelI18nKey: string,
linkName: string,
RepositoryComponent: any,
sortKey?: string
) {
// create predicate based on the link name of the current repository route
// if the linkname is not available, the navigation link and the route are not bound to the extension points
const repoPredicate = (props: any) => {
@@ -156,10 +174,24 @@ class ConfigurationBinder {
// route for global configuration, passes the current repository to component
const RepoRoute = ({ url, repository, ...additionalProps }: RepositoryRouteProps) => {
const link = repository._links[linkName];
const TitledRepositorySettingComponent: FC = ({ children }) => {
const [t] = useTranslation(this.i18nNamespace);
const [commonTranslation] = useTranslation("commons");
useDocumentTitleForRepository(
repository,
t(labelI18nKey),
commonTranslation("documentTitle.repositoryConfiguration")
);
return <>{children}</>;
};
if (link) {
return this.route(
urls.unescapeUrlForRoute(url) + "/settings" + to,
<RepositoryComponent repository={repository} link={(link as Link).href} {...additionalProps} />
<TitledRepositorySettingComponent>
<RepositoryComponent repository={repository} link={(link as Link).href} {...additionalProps} />
</TitledRepositorySettingComponent>
);
}
};
@@ -186,10 +218,24 @@ class ConfigurationBinder {
const NamespaceRoute: FC<extensionPoints.NamespaceRoute["props"]> = ({ url, namespace, ...additionalProps }) => {
const link = namespace._links[linkName];
const TitledNamespaceSettingComponent: FC = ({ children }) => {
const [t] = useTranslation(this.i18nNamespace);
const [commonTranslation] = useTranslation("commons");
useDocumentTitle(
t(labelI18nKey),
commonTranslation("documentTitle.namespaceConfiguration"),
namespace.namespace
);
return <>{children}</>;
};
if (link) {
return this.route(
urls.unescapeUrlForRoute(url) + "/settings" + to,
<ConfigurationComponent namespace={namespace} link={(link as Link).href} {...additionalProps} />
<TitledNamespaceSettingComponent>
<ConfigurationComponent namespace={namespace} link={(link as Link).href} {...additionalProps} />
</TitledNamespaceSettingComponent>
);
}
return null;

View File

@@ -17,6 +17,7 @@
import { useEffect } from "react";
import { binder, extensionPoints } from "@scm-manager/ui-extensions";
import { Repository } from "@scm-manager/ui-types";
import { useTranslation } from "react-i18next";
/**
* Hook to set the document title.
@@ -25,9 +26,10 @@ import { Repository } from "@scm-manager/ui-types";
* Title parts should be sorted with the highest specificity first.
*/
export default function useDocumentTitle(...titleParts: string[]) {
const [t] = useTranslation("commons");
useEffect(() => {
const extension = binder.getExtension<extensionPoints.DocumentTitleExtensionPoint>("document.title");
let title = `${titleParts.join(" - ")} - SCM-Manager`;
let title = [...titleParts, t("documentTitle.suffix")].join(" - ");
if (extension) {
if (typeof extension.documentTitle === "string") {
title += ` (${extension.documentTitle})`;

View File

@@ -361,5 +361,11 @@
"next": "Fokussiere den nächsten Listeneintrag",
"previous": "Fokussiere den vorherigen Listeneintrag"
}
},
"documentTitle": {
"suffix": "SCM-Manager",
"repositoryConfiguration": "Konfiguration",
"namespaceConfiguration": "Konfiguration",
"globalConfiguration": "Konfiguration"
}
}

View File

@@ -362,5 +362,11 @@
"next": "Focus next list item",
"previous": "Focus previous list item"
}
},
"documentTitle": {
"suffix": "SCM-Manager",
"repositoryConfiguration": "Configuration",
"namespaceConfiguration": "Configuration",
"globalConfiguration": "Configuration"
}
}

View File

@@ -45,8 +45,10 @@ const usePermissionData = (namespaceOrRepository: Namespace | Repository) => {
const Permissions: FC<Props> = ({ namespaceOrRepository }) => {
const { isLoading, error, permissions, availablePermissions } = usePermissionData(namespaceOrRepository);
const [t] = useTranslation("repos");
const [commonTranslation] = useTranslation("commons");
useDocumentTitle(
t("repositoryRoot.menu.permissionsNavLink"),
commonTranslation(`documentTitle.${isRepository(namespaceOrRepository) ? "repository" : "namespace"}Configuration`),
namespaceOrRepository.namespace + (isRepository(namespaceOrRepository) ? "/" + namespaceOrRepository.name : "")
);