mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-02 03:25:56 +01:00
Set descriptive document titles
Document titles represent the pages, for example in lists with bookmarks. They are important for navigation and orientation in websites. If the offer or the content of the page is not labeled, orientation is impaired. This changes the behavior for setting document titles. The functionality has been removed from the Page and Title components and is now represented by `useDocumentTitle` hook to better describe the content of inividual pages. Co-authored-by: Anna Vetcininova<anna.vetcininova@cloudogu.com>
This commit is contained in:
@@ -114,12 +114,14 @@
|
||||
"repositoryRole": {
|
||||
"navLink": "Berechtigungsrollen",
|
||||
"title": "Berechtigungsrollen",
|
||||
"titleWithPage": "Berechtigungsrollen Seite {{page}} von {{total}}",
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Berechtigungsrollen Fehler",
|
||||
"detailsTitle": "Berechtigungsrolle",
|
||||
"createSubtitle": "Berechtigungsrolle erstellen",
|
||||
"editSubtitle": "Berechtigungsrolle bearbeiten",
|
||||
"overview": {
|
||||
"title": "Übersicht aller verfügbaren Berechtigungsrollen",
|
||||
"subtitle": "Übersicht aller verfügbaren Berechtigungsrollen",
|
||||
"noPermissionRoles": "Keine Berechtigungsrollen gefunden.",
|
||||
"createButton": "Berechtigungsrolle erstellen"
|
||||
},
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
"loading": "Lade Daten ..."
|
||||
},
|
||||
"logout": {
|
||||
"title": "Abmeldung",
|
||||
"error": {
|
||||
"title": "Abmeldung fehlgeschlagen",
|
||||
"subtitle": "Während der Abmeldung ist ein Fehler aufgetreten."
|
||||
@@ -135,6 +136,7 @@
|
||||
"previous": "Zurück"
|
||||
},
|
||||
"profile": {
|
||||
"subtitle": "Information",
|
||||
"navigationLabel": "Profil",
|
||||
"informationNavLink": "Information",
|
||||
"changePasswordNavLink": "Passwort ändern",
|
||||
@@ -263,6 +265,7 @@
|
||||
"ariaLabel": "Globale Suche",
|
||||
"placeholder": "Suche...",
|
||||
"title": "Suche",
|
||||
"titleWithPage": "Suche Seite {{page}} von {{total}}",
|
||||
"subtitle": "{{type}} Ergebnisse",
|
||||
"subtitleWithContext": "{{type}} Ergebnisse für in \"{{context}}\"",
|
||||
"withQueryType": " mit {{queryType}}",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"createButton": "Gruppe erstellen"
|
||||
},
|
||||
"singleGroup": {
|
||||
"settingsTitle": "Generelle Einstellungen",
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Gruppen Fehler",
|
||||
"menu": {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"skipLfsHelpText": "Ist diese Option aktiviert, werden beim Import keine (potentiell vorhandenen) LFS-Dateien in den SCM-Manager geladen. Diese Option ist nur für Git Repositories relevant."
|
||||
},
|
||||
"repositoryRoot": {
|
||||
"settingsTitle": "Generelle Einstellungen",
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Repository Fehler",
|
||||
"menu": {
|
||||
@@ -56,6 +57,9 @@
|
||||
},
|
||||
"overview": {
|
||||
"title": "Repositories",
|
||||
"titleWithPage": "Repositories Seite {{page}} von {{total}}",
|
||||
"titleWithNamespace": "Repositories in {{namespace}}",
|
||||
"titleWithNamespaceAndPage": "Repositories Seite {{page}} von {{total}} in {{namespace}}",
|
||||
"subtitle": "Übersicht aller verfügbaren Repositories",
|
||||
"noRepositories": "Keine Repositories gefunden.",
|
||||
"invalidNamespace": "Keine Repositories gefunden. Möglicherweise existiert der ausgewählte Namespace nicht.",
|
||||
@@ -172,7 +176,8 @@
|
||||
"cancel": "Nein",
|
||||
"submit": "Ja"
|
||||
}
|
||||
}
|
||||
},
|
||||
"branchWithNamespaceName": "Branch {{branch}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"compare": {
|
||||
"title": "Vergleiche Änderungen",
|
||||
@@ -183,6 +188,16 @@
|
||||
"target": "Target",
|
||||
"with": "Vergleiche Änderungen mit...",
|
||||
"filter": "Auswahl filtern...",
|
||||
"typeTitle": {
|
||||
"b": "Branch",
|
||||
"t": "Tag",
|
||||
"r": "Revision"
|
||||
},
|
||||
"type": {
|
||||
"b": "Branch",
|
||||
"t": "Tag",
|
||||
"r": "Revision"
|
||||
},
|
||||
"emptyResult": "Es wurden keine dem Filter entsprechenden Ergebnisse gefunden.",
|
||||
"tabs": {
|
||||
"b": "Branches",
|
||||
@@ -197,7 +212,8 @@
|
||||
"tabs": {
|
||||
"diff": "Diff",
|
||||
"commits": "Commits"
|
||||
}
|
||||
},
|
||||
"compareSourceAndTargetWithNamespaceName": "Vergleiche {{sourceType}} {{source}} mit {{targetType}} {{target}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"tags": {
|
||||
"overview": {
|
||||
@@ -249,7 +265,8 @@
|
||||
"cancel": "Nein",
|
||||
"submit": "Ja"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tagWithNamespaceName": "Tag {{tag}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"code": {
|
||||
"sources": "Sources",
|
||||
@@ -258,6 +275,11 @@
|
||||
"noBranches": "Keine Sources für das Repository gefunden."
|
||||
},
|
||||
"changesets": {
|
||||
"commitsWithNamespaceName": "Commits in {{namespace}}/{{name}}",
|
||||
"commitsWithPageAndNamespaceName": "Commits Seite {{page}} von {{total}} in {{namespace}}/{{name}}",
|
||||
"commitsWithPageRevisionAndNamespaceName": "Commits Seite {{page}} von {{total}} auf {{revision}} in {{namespace}}/{{name}}",
|
||||
"commitsWithRevisionAndNamespaceName": "Commits auf {{revision}} in {{namespace}}/{{name}}",
|
||||
"idWithNamespaceName": "{{id}} in {{namespace}}/{{name}}",
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Changesets konnten nicht abgerufen werden",
|
||||
"noChangesets": "Keine Changesets in diesem Branch gefunden. Die Commits könnten gelöscht worden sein.",
|
||||
@@ -420,7 +442,9 @@
|
||||
"notBound": "Keine Erweiterung angebunden."
|
||||
},
|
||||
"loadMore": "Laden",
|
||||
"moreFilesAvailable": "Es werden nur die ersten {{count}} Dateien angezeigt. Es sind weitere Dateien vorhanden."
|
||||
"moreFilesAvailable": "Es werden nur die ersten {{count}} Dateien angezeigt. Es sind weitere Dateien vorhanden.",
|
||||
"pathWithRevisionAndNamespaceName": "{{path}} von {{revision}} in {{namespace}}/{{name}}",
|
||||
"sourcesWithRevisionAndNamespaceName": "Sources von {{revision}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"permission": {
|
||||
"title": "Berechtigungen",
|
||||
@@ -547,6 +571,13 @@
|
||||
"started": "Die Reindizierung wurde erfolgreich gestartet. Dies ist eine asynchrone Operation und kann einige Zeit in Anspruch nehmen."
|
||||
},
|
||||
"diff": {
|
||||
"changes": {
|
||||
"add": "added",
|
||||
"delete": "deleted",
|
||||
"modify": "modified",
|
||||
"rename": "renamed",
|
||||
"copy": "copied"
|
||||
},
|
||||
"jumpToSource": "Zur Quelldatei springen",
|
||||
"jumpToTarget": "Zur vorherigen Version der Datei springen",
|
||||
"sideBySide": "Zur zweispaltigen Ansicht wechseln",
|
||||
@@ -587,7 +618,8 @@
|
||||
"notifications": {
|
||||
"queryToShort": "Tippe mindestens 2 Zeichen ein, um die Suche zu starten",
|
||||
"emptyResult": "Es wurden keine Ergebnisse für <0>{{query}}</0> gefunden"
|
||||
}
|
||||
},
|
||||
"searchWithRevisionAndNamespaceName": "Suche auf {{revision}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"shortcuts": {
|
||||
"info": "Wechsel zur Repository-Info",
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"createButton": "Benutzer erstellen"
|
||||
},
|
||||
"singleUser": {
|
||||
"settingsTitle": "Generelle Einstellungen",
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Benutzer Fehler",
|
||||
"menu": {
|
||||
|
||||
@@ -114,12 +114,14 @@
|
||||
"repositoryRole": {
|
||||
"navLink": "Permission Roles",
|
||||
"title": "Permission Roles",
|
||||
"titleWithPage": "Permission Roles page {{page}} of {{total}}",
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown Permission Role Error",
|
||||
"detailsTitle": "Permission Role",
|
||||
"createSubtitle": "Create Permission Role",
|
||||
"editSubtitle": "Edit Permission Role",
|
||||
"overview": {
|
||||
"title": "Overview of all Permission Roles",
|
||||
"subtitle": "Overview of all Permission Roles",
|
||||
"noPermissionRoles": "No Permission Roles found.",
|
||||
"createButton": "Create Permission Role"
|
||||
},
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"error": "Error"
|
||||
},
|
||||
"logout": {
|
||||
"title": "Logout",
|
||||
"error": {
|
||||
"title": "Logout Failed",
|
||||
"subtitle": "Something went wrong during logout"
|
||||
@@ -136,6 +137,7 @@
|
||||
"previous": "Previous"
|
||||
},
|
||||
"profile": {
|
||||
"subtitle": "Information",
|
||||
"navigationLabel": "Profile",
|
||||
"informationNavLink": "Information",
|
||||
"changePasswordNavLink": "Change Password",
|
||||
@@ -264,6 +266,7 @@
|
||||
"ariaLabel": "Global search",
|
||||
"placeholder": "Search...",
|
||||
"title": "Search",
|
||||
"titleWithPage": "Search page {{page}} of {{total}}",
|
||||
"subtitle": "{{type}} results",
|
||||
"subtitleWithContext": "{{type}} results in \"{{context}}\"",
|
||||
"withQueryType": " with {{queryType}}",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"createButton": "Create Group"
|
||||
},
|
||||
"singleGroup": {
|
||||
"settingsTitle": "General Settings",
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown group error",
|
||||
"menu": {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"skipLfsHelpText": "Check this if (potentially available) LFS files shall not be loaded into SCM-Manager during the import. This option is relevant only for git repositories."
|
||||
},
|
||||
"repositoryRoot": {
|
||||
"settingsTitle": "General Settings",
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown repository error",
|
||||
"menu": {
|
||||
@@ -56,6 +57,9 @@
|
||||
},
|
||||
"overview": {
|
||||
"title": "Repositories",
|
||||
"titleWithPage": "Repositories page {{page}} of {{total}}",
|
||||
"titleWithNamespace": "Repositories in {{namespace}}",
|
||||
"titleWithNamespaceAndPage": "Repositories page {{page}} of {{total}} in {{namespace}}",
|
||||
"subtitle": "Overview of available repositories",
|
||||
"noRepositories": "No repositories found.",
|
||||
"invalidNamespace": "No repositories found. It's likely that the selected namespace does not exist.",
|
||||
@@ -172,7 +176,8 @@
|
||||
"cancel": "No",
|
||||
"submit": "Yes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"branchWithNamespaceName": "Branch {{branch}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"compare": {
|
||||
"title": "Compare Changes",
|
||||
@@ -183,6 +188,16 @@
|
||||
"target": "Target",
|
||||
"with": "Compare changes with...",
|
||||
"filter": "Filter selection...",
|
||||
"typeTitle": {
|
||||
"b": "Branch",
|
||||
"t": "Tag",
|
||||
"r": "Revision"
|
||||
},
|
||||
"type": {
|
||||
"b": "branch",
|
||||
"t": "tag",
|
||||
"r": "revision"
|
||||
},
|
||||
"emptyResult": "No results matching the filter were found.",
|
||||
"tabs": {
|
||||
"b": "Branches",
|
||||
@@ -197,7 +212,8 @@
|
||||
"tabs": {
|
||||
"diff": "Diff",
|
||||
"commits": "Commits"
|
||||
}
|
||||
},
|
||||
"compareSourceAndTargetWithNamespaceName": "Compare {{sourceType}} {{source}} with {{targetType}} {{target}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"tags": {
|
||||
"overview": {
|
||||
@@ -249,7 +265,8 @@
|
||||
"cancel": "No",
|
||||
"submit": "Yes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tagWithNamespaceName": "Tag {{tag}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"code": {
|
||||
"sources": "Sources",
|
||||
@@ -258,6 +275,11 @@
|
||||
"noBranches": "No sources found for this repository."
|
||||
},
|
||||
"changesets": {
|
||||
"commitsWithNamespaceName": "Commits in {{namespace}}/{{name}}",
|
||||
"commitsWithPageAndNamespaceName": "Commits page {{page}} of {{total}} in {{namespace}}/{{name}}",
|
||||
"commitsWithPageRevisionAndNamespaceName": "Commits page {{page}} of {{total}} on {{revision}} in {{namespace}}/{{name}}",
|
||||
"commitsWithRevisionAndNamespaceName": "Commits on {{revision}} in {{namespace}}/{{name}}",
|
||||
"idWithNamespaceName": "{{id}} in {{namespace}}/{{name}}",
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Could not fetch changesets",
|
||||
"noChangesets": "No changesets found for this branch. The commits could have been removed.",
|
||||
@@ -420,7 +442,9 @@
|
||||
"notBound": "No extension bound."
|
||||
},
|
||||
"loadMore": "Load",
|
||||
"moreFilesAvailable": "These are just the first {{count}} files. There are more files available."
|
||||
"moreFilesAvailable": "These are just the first {{count}} files. There are more files available.",
|
||||
"pathWithRevisionAndNamespaceName": "{{path}} on {{revision}} in {{namespace}}/{{name}}",
|
||||
"sourcesWithRevisionAndNamespaceName": "Sources on {{revision}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"permission": {
|
||||
"title": "Permissions",
|
||||
@@ -523,6 +547,17 @@
|
||||
"cancel": "No"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
"tooltip": "Read only. The archive cannot be changed."
|
||||
},
|
||||
"exporting": {
|
||||
"tooltip": "Read only. The repository is currently being exported."
|
||||
},
|
||||
"healthCheckFailure": {
|
||||
"tooltip": "This repository has health check failures. Click to get details.",
|
||||
"title": "Health Check Failures",
|
||||
"close": "Close"
|
||||
},
|
||||
"runHealthCheck": {
|
||||
"button": "Run Health Checks",
|
||||
"subtitle": "Health Checks",
|
||||
@@ -535,17 +570,6 @@
|
||||
"description": "Deletes all existing search indices for this repository and recreates them from scratch. This may take a while.",
|
||||
"started": "Reindexing has been started successfully. This is an asynchronous operation and may take a while."
|
||||
},
|
||||
"archive": {
|
||||
"tooltip": "Read only. The archive cannot be changed."
|
||||
},
|
||||
"exporting": {
|
||||
"tooltip": "Read only. The repository is currently being exported."
|
||||
},
|
||||
"healthCheckFailure": {
|
||||
"tooltip": "This repository has health check failures. Click to get details.",
|
||||
"title": "Health Check Failures",
|
||||
"close": "Close"
|
||||
},
|
||||
"diff": {
|
||||
"changes": {
|
||||
"add": "added",
|
||||
@@ -594,7 +618,8 @@
|
||||
"notifications": {
|
||||
"queryToShort": "Type at least two characters to start the search",
|
||||
"emptyResult": "Nothing found for query <0>{{query}}</0>"
|
||||
}
|
||||
},
|
||||
"searchWithRevisionAndNamespaceName": "Search on {{revision}} in {{namespace}}/{{name}}"
|
||||
},
|
||||
"shortcuts": {
|
||||
"info": "Switch to repository info",
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"createButton": "Create User"
|
||||
},
|
||||
"singleUser": {
|
||||
"settingsTitle": "General Settings",
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown user error",
|
||||
"menu": {
|
||||
|
||||
@@ -19,6 +19,7 @@ import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { devices, ErrorNotification, Image, Loading, Subtitle, Title } from "@scm-manager/ui-components";
|
||||
import { useUpdateInfo, useVersion } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
const BoxShadowBox = styled.div`
|
||||
box-shadow: 0 2px 3px rgba(40, 177, 232, 0.1), 0 0 0 2px rgba(40, 177, 232, 0.2);
|
||||
@@ -41,6 +42,7 @@ const MobileWrapped = styled.article`
|
||||
|
||||
const AdminDetails: FC = () => {
|
||||
const [t] = useTranslation("admin");
|
||||
useDocumentTitle(t("admin.info.title"));
|
||||
const version = useVersion();
|
||||
const { data: updateInfo, error, isLoading } = useUpdateInfo();
|
||||
|
||||
@@ -64,7 +66,7 @@ const AdminDetails: FC = () => {
|
||||
<h3 className="has-text-weight-medium">{t("admin.info.newRelease.title")}</h3>
|
||||
<p>
|
||||
{t("admin.info.newRelease.description", {
|
||||
version: updateInfo?.latestVersion
|
||||
version: updateInfo?.latestVersion,
|
||||
})}
|
||||
</p>
|
||||
<a className="button is-warning is-pulled-right" target="_blank" href={updateInfo?.link} rel="noreferrer">
|
||||
|
||||
@@ -20,6 +20,7 @@ import { Link } from "@scm-manager/ui-types";
|
||||
import { ErrorNotification, Loading, Title } from "@scm-manager/ui-components";
|
||||
import ConfigForm from "../components/form/ConfigForm";
|
||||
import { useConfig, useIndexLinks, useNamespaceStrategies, useUpdateConfig } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
const GlobalConfig: FC = () => {
|
||||
const indexLinks = useIndexLinks();
|
||||
@@ -31,6 +32,7 @@ const GlobalConfig: FC = () => {
|
||||
isLoading: isLoadingNamespaceStrategies,
|
||||
} = useNamespaceStrategies();
|
||||
const [t] = useTranslation("config");
|
||||
useDocumentTitle(t("config.title"));
|
||||
const error = configLoadingError || namespaceStrategiesLoadingError || updateError || undefined;
|
||||
const isLoading = isLoadingNamespaceStrategies || isLoadingConfig;
|
||||
const canUpdateConfig = !!(config && (config._links.update as Link).href);
|
||||
|
||||
@@ -36,6 +36,7 @@ import CloudoguPlatformBanner from "../components/CloudoguPlatformBanner";
|
||||
import PluginCenterAuthInfo from "../components/PluginCenterAuthInfo";
|
||||
import styled from "styled-components";
|
||||
import { Button } from "@scm-manager/ui-buttons";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
export enum PluginAction {
|
||||
INSTALL = "install",
|
||||
@@ -70,6 +71,7 @@ const StickyHeader = styled.div`
|
||||
|
||||
const PluginsOverview: FC<Props> = ({ installed }) => {
|
||||
const [t] = useTranslation("admin");
|
||||
useDocumentTitle(installed ? t("plugins.installedSubtitle") : t("plugins.availableSubtitle"));
|
||||
const {
|
||||
data: availablePlugins,
|
||||
isLoading: isLoadingAvailablePlugins,
|
||||
|
||||
@@ -14,49 +14,54 @@
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { WithTranslation, withTranslation } from "react-i18next";
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import { Button, Level } from "@scm-manager/ui-components";
|
||||
import { Level, LinkButton, Title, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import PermissionRoleDetailsTable from "./PermissionRoleDetailsTable";
|
||||
|
||||
type Props = WithTranslation & {
|
||||
type Props = {
|
||||
role: RepositoryRole;
|
||||
url: string;
|
||||
};
|
||||
|
||||
class PermissionRoleDetails extends React.Component<Props> {
|
||||
renderEditButton() {
|
||||
const { t, url } = this.props;
|
||||
if (!!this.props.role._links.update) {
|
||||
const PermissionRoleDetails: FC<Props> = ({ role, url }) => {
|
||||
const [t] = useTranslation("admin");
|
||||
useDocumentTitle(t("repositoryRole.detailsTitle"));
|
||||
|
||||
const renderEditButton = () => {
|
||||
if (!!role._links.update) {
|
||||
return (
|
||||
<>
|
||||
<hr />
|
||||
<Level right={<Button label={t("repositoryRole.editButton")} link={`${url}/edit`} color="primary" />} />
|
||||
<Level
|
||||
right={
|
||||
<LinkButton to={`${url}/edit`} variant="primary" color="primary">
|
||||
{t("repositoryRole.editButton")}
|
||||
</LinkButton>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { role } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Title>{t("repositoryRole.detailsTitle")}</Title>
|
||||
<PermissionRoleDetailsTable role={role} />
|
||||
{renderEditButton()}
|
||||
<ExtensionPoint<extensionPoints.RepositoryRoleDetailsInformation>
|
||||
name="repositoryRole.role-details.information"
|
||||
renderAll={true}
|
||||
props={{
|
||||
role,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<PermissionRoleDetailsTable role={role} />
|
||||
{this.renderEditButton()}
|
||||
<ExtensionPoint<extensionPoints.RepositoryRoleDetailsInformation>
|
||||
name="repositoryRole.role-details.information"
|
||||
renderAll={true}
|
||||
props={{
|
||||
role
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTranslation("admin")(PermissionRoleDetails);
|
||||
export default PermissionRoleDetails;
|
||||
|
||||
@@ -20,9 +20,11 @@ import { ErrorNotification, Loading, Subtitle, Title } from "@scm-manager/ui-com
|
||||
import RepositoryRoleForm from "./RepositoryRoleForm";
|
||||
import { useCreateRepositoryRole } from "@scm-manager/ui-api";
|
||||
import { Redirect } from "react-router-dom";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
const CreateRepositoryRole: FC = () => {
|
||||
const [t] = useTranslation("admin");
|
||||
useDocumentTitle(t("repositoryRole.createSubtitle"));
|
||||
const { error, isLoading: loading, create, repositoryRole: created } = useCreateRepositoryRole();
|
||||
|
||||
if (created) {
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
import React, { FC } from "react";
|
||||
import RepositoryRoleForm from "./RepositoryRoleForm";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ErrorNotification, Loading, Subtitle } from "@scm-manager/ui-components";
|
||||
import { ErrorNotification, Loading, Subtitle, Title } from "@scm-manager/ui-components";
|
||||
import { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import DeleteRepositoryRole from "./DeleteRepositoryRole";
|
||||
import { useUpdateRepositoryRole } from "@scm-manager/ui-api";
|
||||
import { Redirect } from "react-router-dom";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = {
|
||||
role: RepositoryRole;
|
||||
@@ -29,6 +30,7 @@ type Props = {
|
||||
|
||||
const EditRepositoryRole: FC<Props> = ({ role }) => {
|
||||
const [t] = useTranslation("admin");
|
||||
useDocumentTitle(t("repositoryRole.editSubtitle"));
|
||||
const { isUpdated, update, error, isLoading: loading } = useUpdateRepositoryRole();
|
||||
|
||||
if (isUpdated) {
|
||||
@@ -43,6 +45,7 @@ const EditRepositoryRole: FC<Props> = ({ role }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title title={t("repositoryRole.detailsTitle")} />
|
||||
<Subtitle subtitle={t("repositoryRole.editSubtitle")} />
|
||||
<RepositoryRoleForm role={role} submitForm={update} />
|
||||
<DeleteRepositoryRole role={role} />
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
} from "@scm-manager/ui-components";
|
||||
import PermissionRoleTable from "../components/PermissionRoleTable";
|
||||
import { useRepositoryRoles } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type RepositoryRolesPageProps = {
|
||||
data?: RepositoryRoleCollection;
|
||||
@@ -62,6 +63,11 @@ const RepositoryRoles: FC<Props> = ({ baseUrl }) => {
|
||||
const page = urls.getPageFromMatch({ params });
|
||||
const { isLoading: loading, error, data } = useRepositoryRoles({ page: page - 1 });
|
||||
const [t] = useTranslation("admin");
|
||||
useDocumentTitle(
|
||||
data?.pageTotal && data.pageTotal > 1 && page
|
||||
? t("repositoryRole.titleWithPage", { page, total: data.pageTotal })
|
||||
: t("repositoryRole.title")
|
||||
);
|
||||
const canAddRoles = !!data?._links.create;
|
||||
|
||||
if (error) {
|
||||
@@ -79,7 +85,7 @@ const RepositoryRoles: FC<Props> = ({ baseUrl }) => {
|
||||
return (
|
||||
<>
|
||||
<Title title={t("repositoryRole.title")} />
|
||||
<Subtitle subtitle={t("repositoryRole.overview.title")} />
|
||||
<Subtitle subtitle={t("repositoryRole.overview.subtitle")} />
|
||||
<RepositoryRolesPage data={data} page={page} baseUrl={baseUrl} />
|
||||
{canAddRoles ? (
|
||||
<CreateButton label={t("repositoryRole.overview.createButton")} link={`${baseUrl}/create`} />
|
||||
|
||||
@@ -44,12 +44,11 @@ const SingleRepositoryRole: FC = () => {
|
||||
|
||||
const extensionProps = {
|
||||
role,
|
||||
url: escapedUrl
|
||||
url: escapedUrl,
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title title={t("repositoryRole.title")} />
|
||||
<Route path={`${escapedUrl}/info`}>
|
||||
<PermissionRoleDetail role={role} url={url} />
|
||||
</Route>
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import InfoBox from "./InfoBox";
|
||||
import LoginForm from "./LoginForm";
|
||||
import { Image, Loading } from "@scm-manager/ui-components";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { useLoginInfo } from "@scm-manager/ui-api";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Image, Loading } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import InfoBox from "./InfoBox";
|
||||
import LoginForm from "./LoginForm";
|
||||
|
||||
const TopMarginBox = styled.div`
|
||||
margin-top: 5rem;
|
||||
@@ -57,6 +58,7 @@ type Props = {
|
||||
const LoginInfo: FC<Props> = (props) => {
|
||||
const { isLoading: isLoadingLoginInfo, data: info } = useLoginInfo();
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("login.title"));
|
||||
|
||||
if (isLoadingLoginInfo) {
|
||||
return <Loading />;
|
||||
|
||||
@@ -15,13 +15,20 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { ButtonGroup, Checkbox, SubmitButton, Subtitle } from "@scm-manager/ui-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Me } from "@scm-manager/ui-types";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { ButtonGroup, Checkbox, SubmitButton, Subtitle } from "@scm-manager/ui-components";
|
||||
import { AccessibilityConfig, useAccessibilityConfig } from "../accessibilityConfig";
|
||||
|
||||
const Accessibility: FC = () => {
|
||||
type Props = {
|
||||
me: Me;
|
||||
};
|
||||
|
||||
const Accessibility: FC<Props> = ({ me }) => {
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("profile.accessibility.subtitle"), me.displayName);
|
||||
const { value: accessibilityConfig, setValue: setAccessibilityConfig, isLoading } = useAccessibilityConfig();
|
||||
const {
|
||||
register,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import React, { FC, FormEvent, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
ErrorNotification,
|
||||
InputField,
|
||||
@@ -22,9 +23,9 @@ import {
|
||||
Notification,
|
||||
PasswordConfirmation,
|
||||
SubmitButton,
|
||||
Subtitle
|
||||
Subtitle,
|
||||
} from "@scm-manager/ui-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { Me } from "@scm-manager/ui-types";
|
||||
import { useChangeUserPassword } from "@scm-manager/ui-api";
|
||||
|
||||
@@ -34,6 +35,7 @@ type Props = {
|
||||
|
||||
const ChangeUserPassword: FC<Props> = ({ me }) => {
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("password.subtitle"), me.displayName);
|
||||
const { isLoading, error, passwordChanged, changePassword, reset } = useChangeUserPassword(me);
|
||||
const [oldPassword, setOldPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
|
||||
@@ -18,6 +18,7 @@ import React from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Notification, Page } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type LocationState = {
|
||||
code: string;
|
||||
@@ -26,6 +27,7 @@ type LocationState = {
|
||||
const ExternalError = () => {
|
||||
const { code } = useParams<LocationState>();
|
||||
const [t] = useTranslation(["commons", "plugins"]);
|
||||
useDocumentTitle(`${t("app.error.title")}: ${t(`plugins:errors.${code}.displayName`)}`);
|
||||
|
||||
return (
|
||||
<Page title={t("app.error.title")} subtitle={t(`plugins:errors.${code}.displayName`)}>
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
import React, { FC, useState } from "react";
|
||||
import App from "./App";
|
||||
import { ErrorBoundary, Header, Loading } from "@scm-manager/ui-components";
|
||||
import { ErrorBoundary, Header } from "@scm-manager/ui-components";
|
||||
import { Loading } from "@scm-manager/ui-core";
|
||||
import PluginLoader from "./PluginLoader";
|
||||
import ScrollToTop from "./ScrollToTop";
|
||||
import IndexErrorPage from "./IndexErrorPage";
|
||||
|
||||
@@ -15,15 +15,17 @@
|
||||
*/
|
||||
|
||||
import React, { FC, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { ErrorPage, Loading } from "@scm-manager/ui-components";
|
||||
import { Redirect } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLogout } from "@scm-manager/ui-api";
|
||||
import { ErrorPage, Loading } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
const Logout: FC = () => {
|
||||
const { error, logout } = useLogout();
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("logout.title"));
|
||||
|
||||
useEffect(() => {
|
||||
if (logout) {
|
||||
logout();
|
||||
|
||||
@@ -75,10 +75,10 @@ const Profile: FC = () => {
|
||||
<ProfileInfo me={me} />
|
||||
</Route>
|
||||
<Route path={`${url}/settings/theme`} exact>
|
||||
<Theme />
|
||||
<Theme me={me} />
|
||||
</Route>
|
||||
<Route path={`${url}/settings/accessibility`} exact>
|
||||
<Accessibility />
|
||||
<Accessibility me={me} />
|
||||
</Route>
|
||||
{mayChangePassword && (
|
||||
<Route path={`${url}/settings/password`}>
|
||||
|
||||
@@ -22,8 +22,9 @@ import {
|
||||
AvatarWrapper,
|
||||
createAttributesForTesting,
|
||||
InfoTable,
|
||||
MailLink
|
||||
MailLink,
|
||||
} from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = {
|
||||
me: Me;
|
||||
@@ -31,6 +32,7 @@ type Props = {
|
||||
|
||||
const ProfileInfo: FC<Props> = ({ me }) => {
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("profile.subtitle"), me.displayName);
|
||||
const renderGroups = () => {
|
||||
let groups = null;
|
||||
if (me.groups.length > 0) {
|
||||
@@ -39,7 +41,7 @@ const ProfileInfo: FC<Props> = ({ me }) => {
|
||||
<th>{t("profile.groups")}</th>
|
||||
<td className="p-0">
|
||||
<ul>
|
||||
{me.groups.map(group => {
|
||||
{me.groups.map((group) => {
|
||||
return <li>{group}</li>;
|
||||
})}
|
||||
</ul>
|
||||
|
||||
@@ -20,6 +20,8 @@ import { useForm } from "react-hook-form";
|
||||
import styled from "styled-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import classNames from "classnames";
|
||||
import { Me } from "@scm-manager/ui-types";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
const LS_KEY = "scm.theme";
|
||||
|
||||
@@ -36,6 +38,10 @@ export const useThemeState = () => {
|
||||
return { theme, setTheme, isLoading };
|
||||
};
|
||||
|
||||
type Props = {
|
||||
me: Me;
|
||||
};
|
||||
|
||||
type ThemeForm = {
|
||||
theme: string;
|
||||
};
|
||||
@@ -47,21 +53,22 @@ const RadioColumn = styled.div`
|
||||
width: 2rem;
|
||||
`;
|
||||
|
||||
const Theme: FC = () => {
|
||||
const Theme: FC<Props> = ({ me }) => {
|
||||
const { theme, setTheme, isLoading } = useThemeState();
|
||||
const {
|
||||
register,
|
||||
setValue,
|
||||
handleSubmit,
|
||||
formState: { isDirty },
|
||||
watch
|
||||
watch,
|
||||
} = useForm<ThemeForm>({
|
||||
mode: "onChange",
|
||||
defaultValues: {
|
||||
theme
|
||||
}
|
||||
theme,
|
||||
},
|
||||
});
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("profile.theme.subtitle"), me.displayName);
|
||||
|
||||
const onSubmit = (values: ThemeForm) => {
|
||||
setTheme(values.theme);
|
||||
@@ -71,7 +78,7 @@ const Theme: FC = () => {
|
||||
<>
|
||||
<Subtitle>{t("profile.theme.subtitle")}</Subtitle>
|
||||
<form className="is-flex is-flex-direction-column" onSubmit={handleSubmit(onSubmit)}>
|
||||
{themes.map(theme => {
|
||||
{themes.map((theme) => {
|
||||
const a11yId = createA11yId("theme");
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -14,63 +14,23 @@
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { WithTranslation, withTranslation } from "react-i18next";
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Group } from "@scm-manager/ui-types";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { Checkbox, DateFromNow, InfoTable } from "@scm-manager/ui-components";
|
||||
import GroupMember from "./GroupMember";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
|
||||
type Props = WithTranslation & {
|
||||
type Props = {
|
||||
group: Group;
|
||||
};
|
||||
|
||||
class Details extends React.Component<Props> {
|
||||
render() {
|
||||
const { group, t } = this.props;
|
||||
return (
|
||||
<InfoTable className="content">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("group.name")}</th>
|
||||
<td>{group.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.description")}</th>
|
||||
<td>{group.description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.external")}</th>
|
||||
<td>
|
||||
<Checkbox checked={group.external} readOnly={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.type")}</th>
|
||||
<td>{group.type}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.creationDate")}</th>
|
||||
<td>
|
||||
<DateFromNow date={group.creationDate} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.lastModified")}</th>
|
||||
<td>
|
||||
<DateFromNow date={group.lastModified} />
|
||||
</td>
|
||||
</tr>
|
||||
{this.renderMembers()}
|
||||
<ExtensionPoint<extensionPoints.GroupInformationTableBottom> name="group.information.table.bottom" props={{group}} renderAll={true} />
|
||||
</tbody>
|
||||
</InfoTable>
|
||||
);
|
||||
}
|
||||
|
||||
renderMembers() {
|
||||
const { group, t } = this.props;
|
||||
const Details: FC<Props> = ({ group }) => {
|
||||
const [t] = useTranslation("groups");
|
||||
useDocumentTitle(t("singleGroup.menu.informationNavLink"), group.name);
|
||||
|
||||
const renderMembers = () => {
|
||||
let member = null;
|
||||
if (group.members.length > 0) {
|
||||
member = (
|
||||
@@ -87,7 +47,50 @@ class Details extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
return member;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default withTranslation("groups")(Details);
|
||||
return (
|
||||
<InfoTable className="content">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("group.name")}</th>
|
||||
<td>{group.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.description")}</th>
|
||||
<td>{group.description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.external")}</th>
|
||||
<td>
|
||||
<Checkbox checked={group.external} readOnly={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.type")}</th>
|
||||
<td>{group.type}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.creationDate")}</th>
|
||||
<td>
|
||||
<DateFromNow date={group.creationDate} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("group.lastModified")}</th>
|
||||
<td>
|
||||
<DateFromNow date={group.lastModified} />
|
||||
</td>
|
||||
</tr>
|
||||
{renderMembers()}
|
||||
<ExtensionPoint<extensionPoints.GroupInformationTableBottom>
|
||||
name="group.information.table.bottom"
|
||||
props={{ group }}
|
||||
renderAll={true}
|
||||
/>
|
||||
</tbody>
|
||||
</InfoTable>
|
||||
);
|
||||
};
|
||||
|
||||
export default Details;
|
||||
|
||||
@@ -18,11 +18,13 @@ import React, { FC } from "react";
|
||||
import { Redirect, useLocation } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useCreateGroup, urls } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { Page } from "@scm-manager/ui-components";
|
||||
import GroupForm from "../components/GroupForm";
|
||||
|
||||
const CreateGroup: FC = () => {
|
||||
const [t] = useTranslation("groups");
|
||||
useDocumentTitle(t("addGroup.title"));
|
||||
const { isLoading, create, error, group } = useCreateGroup();
|
||||
const location = useLocation();
|
||||
|
||||
|
||||
@@ -15,18 +15,22 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Group } from "@scm-manager/ui-types";
|
||||
import { useUpdateGroup, useUserSuggestions } from "@scm-manager/ui-api";
|
||||
import { useUpdateGroup } from "@scm-manager/ui-api";
|
||||
import { ErrorNotification } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import UpdateNotification from "../../components/UpdateNotification";
|
||||
import GroupForm from "../components/GroupForm";
|
||||
import DeleteGroup from "./DeleteGroup";
|
||||
import UpdateNotification from "../../components/UpdateNotification";
|
||||
|
||||
type Props = {
|
||||
group: Group;
|
||||
};
|
||||
|
||||
const EditGroup: FC<Props> = ({ group }) => {
|
||||
const [t] = useTranslation("groups");
|
||||
useDocumentTitle(t("singleGroup.settingsTitle"), group.name);
|
||||
const { error, isLoading, update, isUpdated } = useUpdateGroup();
|
||||
|
||||
return (
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
import React, { FC } from "react";
|
||||
import { Redirect, useLocation, useParams } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useGroups } from "@scm-manager/ui-api";
|
||||
import { Group, GroupCollection } from "@scm-manager/ui-types";
|
||||
import { useGroups } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import {
|
||||
CreateButton,
|
||||
LinkPaginator,
|
||||
@@ -59,6 +60,7 @@ const Groups: FC = () => {
|
||||
const page = urls.getPageFromMatch({ params });
|
||||
const { isLoading, error, data } = useGroups({ search, page: page - 1 });
|
||||
const [t] = useTranslation("groups");
|
||||
useDocumentTitle(t("groups.title"));
|
||||
const groups = data?._embedded?.groups;
|
||||
const canCreateGroups = !!data?._links.create;
|
||||
if (data && data.pageTotal < page && page > 1) {
|
||||
|
||||
@@ -14,24 +14,30 @@
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import { Group } from "@scm-manager/ui-types";
|
||||
import React, { FC } from "react";
|
||||
import SetPermissions from "./SetPermissions";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Group } from "@scm-manager/ui-types";
|
||||
import { useGroupPermissions, useSetGroupPermissions } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import SetPermissions from "./SetPermissions";
|
||||
|
||||
type Props = {
|
||||
group: Group;
|
||||
};
|
||||
|
||||
const SetGroupPermissions: FC<Props> = ({ group }) => {
|
||||
const { data: selectedPermissions, isLoading: loadingPermissions, error: permissionsLoadError } = useGroupPermissions(
|
||||
group
|
||||
);
|
||||
const [t] = useTranslation("groups");
|
||||
useDocumentTitle(t("singleGroup.menu.setPermissionsNavLink"), group.name);
|
||||
const {
|
||||
data: selectedPermissions,
|
||||
isLoading: loadingPermissions,
|
||||
error: permissionsLoadError,
|
||||
} = useGroupPermissions(group);
|
||||
const {
|
||||
isLoading: isUpdatingPermissions,
|
||||
isUpdated: permissionsUpdated,
|
||||
setPermissions,
|
||||
error: permissionsUpdateError
|
||||
error: permissionsUpdateError,
|
||||
} = useSetGroupPermissions(group, selectedPermissions);
|
||||
return (
|
||||
<SetPermissions
|
||||
|
||||
@@ -16,22 +16,28 @@
|
||||
|
||||
import { User } from "@scm-manager/ui-types";
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SetPermissions from "./SetPermissions";
|
||||
import { useSetUserPermissions, useUserPermissions } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
const SetUserPermissions: FC<Props> = ({ user }) => {
|
||||
const { data: selectedPermissions, isLoading: loadingPermissions, error: permissionsLoadError } = useUserPermissions(
|
||||
user
|
||||
);
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("singleUser.menu.setPermissionsNavLink"), user.displayName);
|
||||
const {
|
||||
data: selectedPermissions,
|
||||
isLoading: loadingPermissions,
|
||||
error: permissionsLoadError,
|
||||
} = useUserPermissions(user);
|
||||
const {
|
||||
isLoading: isUpdatingPermissions,
|
||||
isUpdated: permissionsUpdated,
|
||||
setPermissions,
|
||||
error: permissionsUpdateError
|
||||
error: permissionsUpdateError,
|
||||
} = useSetUserPermissions(user, selectedPermissions);
|
||||
return (
|
||||
<SetPermissions
|
||||
|
||||
@@ -18,7 +18,8 @@ import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import classNames from "classnames";
|
||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||
import {SmallLoadingSpinner, Subtitle, useGeneratedId} from "@scm-manager/ui-components";
|
||||
import { SmallLoadingSpinner, Subtitle, useGeneratedId } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import BranchButtonGroup from "./BranchButtonGroup";
|
||||
import DefaultBranchTag from "./DefaultBranchTag";
|
||||
import AheadBehindTag from "./AheadBehindTag";
|
||||
@@ -33,6 +34,13 @@ type Props = {
|
||||
|
||||
const BranchDetail: FC<Props> = ({ repository, branch }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitle(
|
||||
t("branch.branchWithNamespaceName", {
|
||||
branch: branch.name,
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
})
|
||||
);
|
||||
const { data, isLoading } = useBranchDetails(repository, branch);
|
||||
const labelId = useGeneratedId();
|
||||
let aheadBehind;
|
||||
@@ -70,7 +78,10 @@ const BranchDetail: FC<Props> = ({ repository, branch }) => {
|
||||
<BranchButtonGroup repository={repository} branch={branch} />
|
||||
</div>
|
||||
</div>
|
||||
<span id={labelId} className="is-size-7 has-text-secondary">{t("branch.aheadBehind.label")}</span>{aheadBehind}
|
||||
<span id={labelId} className="is-size-7 has-text-secondary">
|
||||
{t("branch.aheadBehind.label")}
|
||||
</span>
|
||||
{aheadBehind}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { FC } from "react";
|
||||
import BranchDetail from "./BranchDetail";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||
@@ -25,27 +25,24 @@ type Props = {
|
||||
branch: Branch;
|
||||
};
|
||||
|
||||
class BranchView extends React.Component<Props> {
|
||||
render() {
|
||||
const { repository, branch } = this.props;
|
||||
return (
|
||||
<>
|
||||
<BranchDetail repository={repository} branch={branch} />
|
||||
<hr />
|
||||
<div className="content">
|
||||
<ExtensionPoint<extensionPoints.ReposBranchDetailsInformation>
|
||||
name="repos.branch-details.information"
|
||||
renderAll={true}
|
||||
props={{
|
||||
repository,
|
||||
branch
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<BranchDangerZone repository={repository} branch={branch} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
const BranchView: FC<Props> = ({ repository, branch }) => {
|
||||
return (
|
||||
<>
|
||||
<BranchDetail repository={repository} branch={branch} />
|
||||
<hr />
|
||||
<div className="content">
|
||||
<ExtensionPoint<extensionPoints.ReposBranchDetailsInformation>
|
||||
name="repos.branch-details.information"
|
||||
renderAll={true}
|
||||
props={{
|
||||
repository,
|
||||
branch,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<BranchDangerZone repository={repository} branch={branch} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BranchView;
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Repository } from "@scm-manager/ui-types";
|
||||
import { ErrorNotification, Loading } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitleForRepository } from "@scm-manager/ui-core";
|
||||
import { useBranches } from "@scm-manager/ui-api";
|
||||
import BranchTableWrapper from "./BranchTableWrapper";
|
||||
|
||||
@@ -27,6 +29,8 @@ type Props = {
|
||||
|
||||
const BranchesOverview: FC<Props> = ({ repository, baseUrl }) => {
|
||||
const { isLoading, error, data } = useBranches(repository);
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitleForRepository(repository, t("branches.overview.title"));
|
||||
|
||||
if (error) {
|
||||
return <ErrorNotification error={error} />;
|
||||
|
||||
@@ -19,10 +19,11 @@ import { Redirect, useLocation } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import queryString from "query-string";
|
||||
import { Repository } from "@scm-manager/ui-types";
|
||||
import { ErrorNotification, Loading, Subtitle } from "@scm-manager/ui-components";
|
||||
import BranchForm from "../components/BranchForm";
|
||||
import { useBranches, useCreateBranch } from "@scm-manager/ui-api";
|
||||
import { ErrorNotification, Loading, Subtitle } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitleForRepository } from "@scm-manager/ui-core";
|
||||
import { encodePart } from "../../sources/components/content/FileLink";
|
||||
import BranchForm from "../components/BranchForm";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
@@ -33,6 +34,7 @@ const CreateBranch: FC<Props> = ({ repository }) => {
|
||||
const { isLoading: isLoadingList, error: errorList, data: branches } = useBranches(repository);
|
||||
const location = useLocation();
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitleForRepository(repository, t("branches.create.title"));
|
||||
|
||||
const transmittedName = (url: string): string | undefined => {
|
||||
const paramsName = queryString.parse(url).name;
|
||||
@@ -48,7 +50,9 @@ const CreateBranch: FC<Props> = ({ repository }) => {
|
||||
if (createdBranch) {
|
||||
return (
|
||||
<Redirect
|
||||
to={`/repo/${repository.namespace}/${repository.name}/branch/${encodeURIComponent(encodePart(createdBranch.name))}/info`}
|
||||
to={`/repo/${repository.namespace}/${repository.name}/branch/${encodeURIComponent(
|
||||
encodePart(createdBranch.name)
|
||||
)}/info`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import styled from "styled-components";
|
||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||
import { urls, usePaths } from "@scm-manager/ui-api";
|
||||
import { createA11yId, ErrorNotification, FilterInput, Help, Icon, Loading } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import CodeActionBar from "../components/CodeActionBar";
|
||||
import FileSearchResults from "../components/FileSearchResults";
|
||||
import { filepathSearch } from "../utils/filepathSearch";
|
||||
@@ -60,7 +61,14 @@ const FileSearch: FC<Props> = ({ repository, baseUrl, branches, selectedBranch }
|
||||
const query = urls.getQueryStringFromLocation(location) || "";
|
||||
const prevSourcePath = urls.getPrevSourcePathFromLocation(location) || "";
|
||||
const [t] = useTranslation("repos");
|
||||
const [firstSelectedBranch, setBranchChanged] = useState<string | undefined>(selectedBranch);
|
||||
useDocumentTitle(
|
||||
t("fileSearch.searchWithRevisionAndNamespaceName", {
|
||||
revision: decodeURIComponent(revision),
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
})
|
||||
);
|
||||
const [firstSelectedBranch] = useState<string | undefined>(selectedBranch);
|
||||
|
||||
useEffect(() => {
|
||||
if (query.length > 1 && data) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { Repository } from "@scm-manager/ui-types";
|
||||
import { devices, Icon } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import CompareSelector from "./CompareSelector";
|
||||
import { CompareBranchesParams } from "./CompareView";
|
||||
|
||||
@@ -59,12 +60,22 @@ const CompareSelectBar: FC<Props> = ({ repository, baseUrl }) => {
|
||||
const history = useHistory();
|
||||
const [source, setSource] = useState<CompareProps>({
|
||||
type: params?.sourceType,
|
||||
name: decodeURIComponent(params?.sourceName)
|
||||
name: decodeURIComponent(params?.sourceName),
|
||||
});
|
||||
const [target, setTarget] = useState<CompareProps>({
|
||||
type: params?.targetType,
|
||||
name: decodeURIComponent(params?.targetName)
|
||||
name: decodeURIComponent(params?.targetName),
|
||||
});
|
||||
useDocumentTitle(
|
||||
t("compare.compareSourceAndTargetWithNamespaceName", {
|
||||
sourceType: t(`compare.selector.type.${source.type}`),
|
||||
source: source.name,
|
||||
targetType: t(`compare.selector.type.${target.type}`),
|
||||
target: target.name,
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
})
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const tabUriComponent = location.pathname.split("/")[9];
|
||||
|
||||
@@ -85,17 +85,6 @@ const CompareSelector: FC<Props> = ({ onSelect, selected, label, repository }) =
|
||||
};
|
||||
});
|
||||
|
||||
const getActionTypeName = (type: CompareTypes) => {
|
||||
switch (type) {
|
||||
case "b":
|
||||
return "Branch";
|
||||
case "t":
|
||||
return "Tag";
|
||||
case "r":
|
||||
return "Revision";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ResponsiveWrapper className="field mb-0 is-flex is-flex-direction-column is-fullwidth">
|
||||
<label className="label">{label}</label>
|
||||
@@ -107,7 +96,7 @@ const CompareSelector: FC<Props> = ({ onSelect, selected, label, repository }) =
|
||||
onClick={() => setShowDropdown(!showDropdown)}
|
||||
>
|
||||
<span className="is-ellipsis-overflow">
|
||||
<strong>{getActionTypeName(selection.type)}:</strong> {selection.name}
|
||||
<strong>{t(`compare.selector.typeTitle.${selection.type}`)}:</strong> {selection.name}
|
||||
</span>
|
||||
<span className="icon is-small">
|
||||
<Icon>angle-down</Icon>
|
||||
|
||||
@@ -14,34 +14,36 @@
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Repository } from "@scm-manager/ui-types";
|
||||
import RepositoryDetailTable from "./RepositoryDetailTable";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import { useDocumentTitleForRepository } from "@scm-manager/ui-core";
|
||||
import RepositoryDetailTable from "./RepositoryDetailTable";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
};
|
||||
|
||||
class RepositoryDetails extends React.Component<Props> {
|
||||
render() {
|
||||
const { repository } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<RepositoryDetailTable repository={repository} />
|
||||
<hr />
|
||||
<div className="content">
|
||||
<ExtensionPoint<extensionPoints.RepositoryDetailsInformation>
|
||||
name="repos.repository-details.information"
|
||||
renderAll={true}
|
||||
props={{
|
||||
repository
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
const RepositoryDetails: FC<Props> = ({ repository }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitleForRepository(repository, t("repositoryRoot.menu.informationNavLink"));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<RepositoryDetailTable repository={repository} />
|
||||
<hr />
|
||||
<div className="content">
|
||||
<ExtensionPoint<extensionPoints.RepositoryDetailsInformation>
|
||||
name="repos.repository-details.information"
|
||||
renderAll={true}
|
||||
props={{
|
||||
repository,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RepositoryDetails;
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Changeset, Repository } from "@scm-manager/ui-types";
|
||||
import { ErrorPage, Loading } from "@scm-manager/ui-components";
|
||||
import ChangesetDetails from "../components/changesets/ChangesetDetails";
|
||||
import { FileControlFactory } from "@scm-manager/ui-components";
|
||||
import { RepositoryRevisionContextProvider, useChangeset } from "@scm-manager/ui-api";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
@@ -36,6 +37,18 @@ const ChangesetView: FC<Props> = ({ repository, fileControlFactoryFactory }) =>
|
||||
const { id } = useParams<Params>();
|
||||
const { isLoading, error, data: changeset } = useChangeset(repository, id);
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitle(
|
||||
changeset?.id
|
||||
? t("changesets.idWithNamespaceName", {
|
||||
id: changeset.id.slice(0, 7),
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
})
|
||||
: t("changesets.changesetsWithNamespaceName", {
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
})
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return <ErrorPage title={t("changesets.errorTitle")} subtitle={t("changesets.errorSubtitle")} error={error} />;
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
Notification,
|
||||
urls,
|
||||
} from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
export const usePage = () => {
|
||||
const match = useRouteMatch();
|
||||
@@ -39,12 +40,54 @@ type Props = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
const Changesets: FC<Props> = ({ repository, branch, url }) => {
|
||||
const Changesets: FC<Props> = ({ repository, branch, ...props }) => {
|
||||
const page = usePage();
|
||||
|
||||
const { isLoading, error, data } = useChangesets(repository, { branch, page: page - 1 });
|
||||
const [t] = useTranslation("repos");
|
||||
const getDocumentTitle = () => {
|
||||
if (data?.pageTotal && data.pageTotal > 1 && page) {
|
||||
if (branch) {
|
||||
return t("changesets.commitsWithPageRevisionAndNamespaceName", {
|
||||
page,
|
||||
total: data.pageTotal,
|
||||
revision: branch.name,
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
});
|
||||
} else {
|
||||
return t("changesets.commitsWithPageAndNamespaceName", {
|
||||
page,
|
||||
total: data.pageTotal,
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
});
|
||||
}
|
||||
} else if (branch) {
|
||||
return t("changesets.commitsWithRevisionAndNamespaceName", {
|
||||
revision: branch.name,
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
});
|
||||
} else {
|
||||
return t("changesets.commitsWithNamespaceName", {
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
});
|
||||
}
|
||||
};
|
||||
useDocumentTitle(getDocumentTitle());
|
||||
|
||||
return <ChangesetsPanel repository={repository} error={error} isLoading={isLoading} data={data} url={url} />;
|
||||
return (
|
||||
<ChangesetsPanel
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
data={data}
|
||||
repository={repository}
|
||||
branch={branch}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type ChangesetsPanelProps = Props & {
|
||||
@@ -53,7 +96,7 @@ type ChangesetsPanelProps = Props & {
|
||||
data?: ChangesetCollection;
|
||||
};
|
||||
|
||||
export const ChangesetsPanel: FC<ChangesetsPanelProps> = ({ repository, error, isLoading, data, url }) => {
|
||||
export const ChangesetsPanel: FC<ChangesetsPanelProps> = ({ repository, error, isLoading, data, url, branch }) => {
|
||||
const page = usePage();
|
||||
const [t] = useTranslation("repos");
|
||||
const changesets = data?._embedded?.changesets;
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import CreateRepository from "./CreateRepository";
|
||||
import ImportRepository from "./ImportRepository";
|
||||
import { useBinder } from "@scm-manager/ui-extensions";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Notification, Page, urls } from "@scm-manager/ui-components";
|
||||
import RepositoryFormSwitcher from "../components/form/RepositoryFormSwitcher";
|
||||
import { useIndex, useNamespaceStrategies, useRepositoryTypes } from "@scm-manager/ui-api";
|
||||
import { Page, urls } from "@scm-manager/ui-components";
|
||||
import { Notification, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { extensionPoints, useBinder } from "@scm-manager/ui-extensions";
|
||||
import NamespaceAndNameFields from "../components/NamespaceAndNameFields";
|
||||
import RepositoryInformationForm from "../components/RepositoryInformationForm";
|
||||
import { extensionPoints } from "@scm-manager/ui-extensions/";
|
||||
import RepositoryFormSwitcher from "../components/form/RepositoryFormSwitcher";
|
||||
import CreateRepository from "./CreateRepository";
|
||||
import ImportRepository from "./ImportRepository";
|
||||
|
||||
type CreatorRouteProps = {
|
||||
creator: extensionPoints.RepositoryCreatorExtension;
|
||||
@@ -41,13 +41,14 @@ const useCreateRepositoryData = () => {
|
||||
pageLoadingError: errorNS || errorRT || errorIdx || undefined,
|
||||
namespaceStrategies,
|
||||
repositoryTypes,
|
||||
index
|
||||
index,
|
||||
};
|
||||
};
|
||||
|
||||
const CreatorRoute: FC<CreatorRouteProps> = ({ creator, creators }) => {
|
||||
const { isPageLoading, pageLoadingError, namespaceStrategies, repositoryTypes, index } = useCreateRepositoryData();
|
||||
const [t] = useTranslation(["repos", "plugins"]);
|
||||
useDocumentTitle(creator.subtitle);
|
||||
|
||||
const Component = creator.component;
|
||||
|
||||
@@ -88,15 +89,15 @@ const CreateRepositoryRoot: FC = () => {
|
||||
path: "",
|
||||
icon: "plus",
|
||||
label: t("repositoryForm.createButton"),
|
||||
component: CreateRepository
|
||||
component: CreateRepository,
|
||||
},
|
||||
{
|
||||
subtitle: t("import.subtitle"),
|
||||
path: "import",
|
||||
icon: "file-upload",
|
||||
label: t("repositoryForm.importButton"),
|
||||
component: ImportRepository
|
||||
}
|
||||
component: ImportRepository,
|
||||
},
|
||||
];
|
||||
|
||||
const extCreators = binder.getExtensions<extensionPoints.RepositoryCreator>("repos.creator");
|
||||
@@ -106,7 +107,7 @@ const CreateRepositoryRoot: FC = () => {
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
{creators.map(creator => (
|
||||
{creators.map((creator) => (
|
||||
<Route key={creator.path} exact path={urls.concat("/repos/create", creator.path)}>
|
||||
<CreatorRoute creator={creator} creators={creators} />
|
||||
</Route>
|
||||
|
||||
@@ -16,18 +16,19 @@
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { useRouteMatch } from "react-router-dom";
|
||||
import RepositoryForm from "../components/form";
|
||||
import { Repository } from "@scm-manager/ui-types";
|
||||
import { ErrorNotification, Subtitle, urls } from "@scm-manager/ui-components";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import RepositoryDangerZone from "./RepositoryDangerZone";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ExportRepository from "./ExportRepository";
|
||||
import { Repository } from "@scm-manager/ui-types";
|
||||
import { useUpdateRepository } from "@scm-manager/ui-api";
|
||||
import { ErrorNotification, Subtitle, urls } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitleForRepository } from "@scm-manager/ui-core";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import UpdateNotification from "../../components/UpdateNotification";
|
||||
import RepositoryForm from "../components/form";
|
||||
import Reindex from "../components/Reindex";
|
||||
import RepositoryDangerZone from "./RepositoryDangerZone";
|
||||
import ExportRepository from "./ExportRepository";
|
||||
import HealthCheckWarning from "./HealthCheckWarning";
|
||||
import RunHealthCheck from "./RunHealthCheck";
|
||||
import UpdateNotification from "../../components/UpdateNotification";
|
||||
import Reindex from "../components/Reindex";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
@@ -37,11 +38,12 @@ const EditRepo: FC<Props> = ({ repository }) => {
|
||||
const match = useRouteMatch();
|
||||
const { isLoading, error, update, isUpdated } = useUpdateRepository();
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitleForRepository(repository, t("repositoryRoot.settingsTitle"));
|
||||
|
||||
const url = urls.matchedUrlFromMatch(match);
|
||||
const extensionProps = {
|
||||
repository,
|
||||
url
|
||||
url,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
PageActions,
|
||||
urls,
|
||||
} from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import RepositoryList from "../components/list";
|
||||
import { useNamespaceAndNameContext, useNamespaces, useRepositories } from "@scm-manager/ui-api";
|
||||
import { NamespaceCollection, RepositoryCollection } from "@scm-manager/ui-types";
|
||||
@@ -170,6 +171,20 @@ const Overview: FC = () => {
|
||||
const { isLoading, error, namespace, namespaces, repositories, search, page } = useOverviewData();
|
||||
const history = useHistory();
|
||||
const [t] = useTranslation("repos");
|
||||
const getDocumentTitle = () => {
|
||||
if (repositories?.pageTotal && repositories.pageTotal > 1 && page) {
|
||||
if (namespace) {
|
||||
return t("overview.titleWithNamespaceAndPage", { page, total: repositories.pageTotal, namespace });
|
||||
} else {
|
||||
return t("overview.titleWithPage", { page, total: repositories.pageTotal });
|
||||
}
|
||||
} else if (namespace) {
|
||||
return t("overview.titleWithNamespace", { namespace });
|
||||
} else {
|
||||
return t("overview.title");
|
||||
}
|
||||
};
|
||||
useDocumentTitle(getDocumentTitle());
|
||||
const binder = useBinder();
|
||||
const context = useNamespaceAndNameContext();
|
||||
useEffect(() => {
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { useImportLog } from "@scm-manager/ui-api";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Page } from "@scm-manager/ui-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useImportLog } from "@scm-manager/ui-api";
|
||||
import { Page } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Params = {
|
||||
logId: string;
|
||||
@@ -28,6 +29,7 @@ const ImportLog: FC = () => {
|
||||
const { logId } = useParams<Params>();
|
||||
const { isLoading, data, error } = useImportLog(logId);
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("importLog.title"));
|
||||
|
||||
return (
|
||||
<Page title={t("importLog.title")} loading={isLoading} error={error}>
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import { Namespace } from "@scm-manager/ui-types";
|
||||
import React, { FC } from "react";
|
||||
import { ErrorNotification, Loading, Subtitle } from "@scm-manager/ui-core";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useRepositories } from "@scm-manager/ui-api";
|
||||
import { DateFromNow } from "@scm-manager/ui-components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { ErrorNotification, Loading, Subtitle, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { Namespace } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
namespace: Namespace;
|
||||
@@ -28,6 +28,7 @@ type Props = {
|
||||
|
||||
const NamespaceInformation: FC<Props> = ({ namespace }) => {
|
||||
const [t] = useTranslation("namespaces");
|
||||
useDocumentTitle(t("namespaceRoot.infoPage.subtitle"), namespace.namespace);
|
||||
const { data: repositories, error, isLoading } = useRepositories({ namespace: namespace, pageSize: 9999, page: 0 });
|
||||
|
||||
if (error) {
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAvailablePermissions, usePermissions } from "@scm-manager/ui-api";
|
||||
import { ErrorPage, Loading, Subtitle } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { Namespace, Repository } from "@scm-manager/ui-types";
|
||||
import CreatePermissionForm from "./CreatePermissionForm";
|
||||
import PermissionsTable from "../components/PermissionsTable";
|
||||
import { useAvailablePermissions, usePermissions } from "@scm-manager/ui-api";
|
||||
|
||||
type Props = {
|
||||
namespaceOrRepository: Namespace | Repository;
|
||||
@@ -37,13 +38,17 @@ const usePermissionData = (namespaceOrRepository: Namespace | Repository) => {
|
||||
isLoading: permissions.isLoading || availablePermissions.isLoading,
|
||||
error: permissions.error || availablePermissions.error,
|
||||
permissions: permissions.data,
|
||||
availablePermissions: availablePermissions.data
|
||||
availablePermissions: availablePermissions.data,
|
||||
};
|
||||
};
|
||||
|
||||
const Permissions: FC<Props> = ({ namespaceOrRepository }) => {
|
||||
const { isLoading, error, permissions, availablePermissions } = usePermissionData(namespaceOrRepository);
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitle(
|
||||
t("repositoryRoot.menu.permissionsNavLink"),
|
||||
namespaceOrRepository.namespace + (isRepository(namespaceOrRepository) ? "/" + namespaceOrRepository.name : "")
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return <ErrorPage title={t("permission.error-title")} subtitle={t("permission.error-subtitle")} error={error} />;
|
||||
|
||||
@@ -20,7 +20,7 @@ import { useHistory, useLocation, useParams } from "react-router-dom";
|
||||
import { RepositoryRevisionContextProvider, urls, useSources } from "@scm-manager/ui-api";
|
||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||
import { Breadcrumb } from "@scm-manager/ui-components";
|
||||
import { Notification, ErrorNotification, Loading } from "@scm-manager/ui-core";
|
||||
import { Notification, ErrorNotification, Loading, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import FileTree from "../components/FileTree";
|
||||
import Content from "./Content";
|
||||
import CodeActionBar from "../../codeSection/components/CodeActionBar";
|
||||
@@ -57,6 +57,30 @@ const Sources: FC<Props> = ({ repository, branches, selectedBranch, baseUrl }) =
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [t] = useTranslation("repos");
|
||||
const getDocumentTitle = () => {
|
||||
if (revision) {
|
||||
const getRevision = () => {
|
||||
return branches?.some((branch) => branch.name === revision) ? revision : revision.slice(0, 7);
|
||||
};
|
||||
if (path) {
|
||||
return t("sources.pathWithRevisionAndNamespaceName", {
|
||||
path: path,
|
||||
revision: getRevision(),
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
});
|
||||
} else {
|
||||
return t("sources.sourcesWithRevisionAndNamespaceName", {
|
||||
revision: getRevision(),
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return repository.namespace + "/" + repository.name;
|
||||
}
|
||||
};
|
||||
useDocumentTitle(getDocumentTitle());
|
||||
const [contentRef, setContentRef] = useState<HTMLElement | null>();
|
||||
|
||||
useScrollToElement(contentRef, () => location.hash, location.hash);
|
||||
@@ -72,7 +96,6 @@ const Sources: FC<Props> = ({ repository, branches, selectedBranch, baseUrl }) =
|
||||
);
|
||||
}
|
||||
}, [branches, selectedBranch, history, baseUrl, location.hash]);
|
||||
|
||||
const {
|
||||
isLoading,
|
||||
error,
|
||||
|
||||
@@ -19,6 +19,7 @@ import { useTranslation } from "react-i18next";
|
||||
import classNames from "classnames";
|
||||
import { Repository, Tag } from "@scm-manager/ui-types";
|
||||
import { Subtitle, DateFromNow, SignatureIcon } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import TagButtonGroup from "./TagButtonGroup";
|
||||
import CompareLink from "../../compare/CompareLink";
|
||||
|
||||
@@ -29,6 +30,13 @@ type Props = {
|
||||
|
||||
const TagDetail: FC<Props> = ({ repository, tag }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitle(
|
||||
t("tag.tagWithNamespaceName", {
|
||||
tag: tag.name,
|
||||
namespace: repository.namespace,
|
||||
name: repository.name,
|
||||
})
|
||||
);
|
||||
|
||||
const encodedTag = encodeURIComponent(tag.name);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import React, { FC, useMemo, useState } from "react";
|
||||
import { Repository } from "@scm-manager/ui-types";
|
||||
import { ErrorNotification, Loading, Notification, Subtitle } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitleForRepository } from "@scm-manager/ui-core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import orderTags, { SORT_OPTIONS, SortOption } from "../orderTags";
|
||||
import TagTable from "../components/TagTable";
|
||||
@@ -31,6 +32,7 @@ type Props = {
|
||||
const TagsOverview: FC<Props> = ({ repository, baseUrl }) => {
|
||||
const { isLoading, error, data } = useTags(repository);
|
||||
const [t] = useTranslation("repos");
|
||||
useDocumentTitleForRepository(repository, t("tags.overview.title"));
|
||||
const [sort, setSort] = useState<SortOption | undefined>();
|
||||
const tags = useMemo(() => orderTags(data?._embedded?.tags || [], sort), [data, sort]);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
Tag,
|
||||
urls,
|
||||
} from "@scm-manager/ui-components";
|
||||
import { Notification, Level } from "@scm-manager/ui-core";
|
||||
import { Notification, Level, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { Link, useLocation, useParams } from "react-router-dom";
|
||||
import { useIndex, useNamespaceAndNameContext, useSearch, useSearchCounts, useSearchTypes } from "@scm-manager/ui-api";
|
||||
import Results from "./Results";
|
||||
@@ -163,9 +163,22 @@ const InvalidSearch: FC = () => {
|
||||
|
||||
const Search: FC = () => {
|
||||
const { data: index } = useIndex();
|
||||
const [t] = useTranslation(["commons", "plugins"]);
|
||||
const [showHelp, setShowHelp] = useState(false);
|
||||
const { query, selectedType, page, namespace, name } = usePageParams();
|
||||
const searchOptions = {
|
||||
type: selectedType,
|
||||
page: page - 1,
|
||||
pageSize: 25,
|
||||
namespaceContext: namespace,
|
||||
repositoryNameContext: name,
|
||||
};
|
||||
const { data, isLoading, error } = useSearch(query, searchOptions);
|
||||
const [t] = useTranslation(["commons", "plugins"]);
|
||||
useDocumentTitle(
|
||||
data?.pageTotal && data.pageTotal > 1 && page
|
||||
? t("search.titleWithPage", { page, total: data.pageTotal })
|
||||
: t("search.title")
|
||||
);
|
||||
const [showHelp, setShowHelp] = useState(false);
|
||||
const context = useNamespaceAndNameContext();
|
||||
useEffect(() => {
|
||||
context.setNamespace(namespace || "");
|
||||
@@ -176,14 +189,6 @@ const Search: FC = () => {
|
||||
context.setName("");
|
||||
};
|
||||
}, [namespace, name, context]);
|
||||
const searchOptions = {
|
||||
type: selectedType,
|
||||
page: page - 1,
|
||||
pageSize: 25,
|
||||
namespaceContext: namespace,
|
||||
repositoryNameContext: name,
|
||||
};
|
||||
const { data, isLoading, error } = useSearch(query, searchOptions);
|
||||
const types = useSearchTypes(searchOptions);
|
||||
types.sort(orderTypes(t));
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
|
||||
import React, { FC, useState } from "react";
|
||||
import { useSearchableTypes, useSearchSyntaxContent } from "@scm-manager/ui-api";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { copyToClipboard, InputField, Loading, MarkdownView, Page } from "@scm-manager/ui-components";
|
||||
import { ErrorNotification, Icon, Tooltip, Button } from "@scm-manager/ui-core";
|
||||
import classNames from "classnames";
|
||||
import { parse } from "date-fns";
|
||||
import styled from "styled-components";
|
||||
import classNames from "classnames";
|
||||
import { useSearchableTypes, useSearchSyntaxContent } from "@scm-manager/ui-api";
|
||||
import { copyToClipboard, InputField, MarkdownView, Page } from "@scm-manager/ui-components";
|
||||
import { ErrorNotification, Icon, Loading, Tooltip, Button, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { SearchableType } from "@scm-manager/ui-types";
|
||||
|
||||
const StyledTooltip = styled(Tooltip)`
|
||||
@@ -41,7 +41,9 @@ type ExpandableProps = {
|
||||
|
||||
const Expandable: FC<ExpandableProps> = ({ header, children, className }) => {
|
||||
const [t] = useTranslation("commons");
|
||||
useDocumentTitle(t("search.syntax.title"));
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
return (
|
||||
<div className={classNames("card search-syntax-accordion", className)}>
|
||||
<header>
|
||||
@@ -88,18 +90,20 @@ const Examples: FC<ExampleProps> = ({ searchableType }) => {
|
||||
<h5 className="title mt-5">{t("search.syntax.exampleQueries.title")}</h5>
|
||||
<div className="mb-2">{t("search.syntax.exampleQueries.description")}</div>
|
||||
<table>
|
||||
<tr>
|
||||
<th>{t("search.syntax.exampleQueries.table.description")}</th>
|
||||
<th>{t("search.syntax.exampleQueries.table.query")}</th>
|
||||
<th>{t("search.syntax.exampleQueries.table.explanation")}</th>
|
||||
</tr>
|
||||
{examples.map((example) => (
|
||||
<tr key={example.description}>
|
||||
<td>{example.description}</td>
|
||||
<td>{example.query}</td>
|
||||
<td>{example.explanation}</td>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("search.syntax.exampleQueries.table.description")}</th>
|
||||
<th>{t("search.syntax.exampleQueries.table.query")}</th>
|
||||
<th>{t("search.syntax.exampleQueries.table.explanation")}</th>
|
||||
</tr>
|
||||
))}
|
||||
{examples.map((example) => (
|
||||
<tr key={example.description}>
|
||||
<td>{example.description}</td>
|
||||
<td>{example.query}</td>
|
||||
<td>{example.explanation}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
@@ -126,28 +130,30 @@ const SearchableTypes: FC = () => {
|
||||
header={t(`plugins:search.types.${searchableType.name}.title`, searchableType.name)}
|
||||
>
|
||||
<table>
|
||||
<tr>
|
||||
<th>{t("search.syntax.fields.name")}</th>
|
||||
<th>{t("search.syntax.fields.type")}</th>
|
||||
<th>{t("search.syntax.fields.exampleValue")}</th>
|
||||
<th>{t("search.syntax.fields.hints")}</th>
|
||||
</tr>
|
||||
{searchableType.fields.map((searchableField) => (
|
||||
<tr key={searchableField.name}>
|
||||
<th>{searchableField.name}</th>
|
||||
<td>{searchableField.type}</td>
|
||||
<td>
|
||||
{t(`plugins:search.types.${searchableType.name}.fields.${searchableField.name}.exampleValue`, {
|
||||
defaultValue: "",
|
||||
})}
|
||||
</td>
|
||||
<td>
|
||||
{t(`plugins:search.types.${searchableType.name}.fields.${searchableField.name}.hints`, {
|
||||
defaultValue: "",
|
||||
})}
|
||||
</td>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("search.syntax.fields.name")}</th>
|
||||
<th>{t("search.syntax.fields.type")}</th>
|
||||
<th>{t("search.syntax.fields.exampleValue")}</th>
|
||||
<th>{t("search.syntax.fields.hints")}</th>
|
||||
</tr>
|
||||
))}
|
||||
{searchableType.fields.map((searchableField) => (
|
||||
<tr key={searchableField.name}>
|
||||
<th>{searchableField.name}</th>
|
||||
<td>{searchableField.type}</td>
|
||||
<td>
|
||||
{t(`plugins:search.types.${searchableType.name}.fields.${searchableField.name}.exampleValue`, {
|
||||
defaultValue: "",
|
||||
})}
|
||||
</td>
|
||||
<td>
|
||||
{t(`plugins:search.types.${searchableType.name}.fields.${searchableField.name}.hints`, {
|
||||
defaultValue: "",
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<Examples searchableType={searchableType} />
|
||||
</Expandable>
|
||||
|
||||
@@ -23,9 +23,10 @@ import {
|
||||
Notification,
|
||||
PasswordConfirmation,
|
||||
SubmitButton,
|
||||
Subtitle
|
||||
Subtitle,
|
||||
} from "@scm-manager/ui-components";
|
||||
import { useSetUserPassword } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = {
|
||||
user: User;
|
||||
@@ -33,6 +34,7 @@ type Props = {
|
||||
|
||||
const SetUserPassword: FC<Props> = ({ user }) => {
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("singleUser.menu.setPasswordNavLink"), user.displayName);
|
||||
const { passwordOverwritten, setPassword, error, isLoading, reset } = useSetUserPassword(user);
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [passwordValid, setPasswordValid] = useState(false);
|
||||
|
||||
@@ -22,6 +22,7 @@ import AddApiKey from "./AddApiKey";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useApiKeys, useDeleteApiKey } from "@scm-manager/ui-api";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = {
|
||||
user: User | Me;
|
||||
@@ -29,6 +30,7 @@ type Props = {
|
||||
|
||||
const SetApiKeys: FC<Props> = ({ user }) => {
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("singleUser.menu.setApiKeyNavLink"), user.displayName);
|
||||
const { isLoading, data: apiKeys, error: fetchError } = useApiKeys(user);
|
||||
const { error: deletionError, remove } = useDeleteApiKey(user);
|
||||
const error = deletionError || fetchError;
|
||||
|
||||
@@ -21,6 +21,7 @@ import AddPublicKey from "./AddPublicKey";
|
||||
import PublicKeyTable from "./PublicKeyTable";
|
||||
import { ErrorNotification, Loading, Subtitle } from "@scm-manager/ui-components";
|
||||
import { useDeletePublicKey, usePublicKeys } from "@scm-manager/ui-api";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = {
|
||||
user: User | Me;
|
||||
@@ -28,6 +29,7 @@ type Props = {
|
||||
|
||||
const SetPublicKeys: FC<Props> = ({ user }) => {
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("singleUser.menu.setPublicKeyNavLink"), user.displayName);
|
||||
const { error: fetchingError, isLoading, data: publicKeys } = usePublicKeys(user);
|
||||
const { error: deletionError, remove } = useDeletePublicKey(user);
|
||||
const error = fetchingError || deletionError;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React, { FC, useState } from "react";
|
||||
import { useTranslation, WithTranslation } from "react-i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { User } from "@scm-manager/ui-types";
|
||||
import {
|
||||
Checkbox,
|
||||
@@ -23,18 +23,20 @@ import {
|
||||
DateFromNow,
|
||||
Help,
|
||||
InfoTable,
|
||||
MailLink
|
||||
MailLink,
|
||||
} from "@scm-manager/ui-components";
|
||||
import { Icon } from "@scm-manager/ui-components";
|
||||
import PermissionOverview from "../PermissionOverview";
|
||||
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
|
||||
type Props = WithTranslation & {
|
||||
type Props = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
const Details: FC<Props> = ({ user }) => {
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("singleUser.menu.informationNavLink"), user.displayName);
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const toggleCollapse = () => setCollapsed(!collapsed);
|
||||
|
||||
@@ -96,7 +98,11 @@ const Details: FC<Props> = ({ user }) => {
|
||||
<DateFromNow date={user.lastModified} />
|
||||
</td>
|
||||
</tr>
|
||||
<ExtensionPoint<extensionPoints.UserInformationTableBottom> name="user.information.table.bottom" props={{user}} renderAll={true} />
|
||||
<ExtensionPoint<extensionPoints.UserInformationTableBottom>
|
||||
name="user.information.table.bottom"
|
||||
props={{ user }}
|
||||
renderAll={true}
|
||||
/>
|
||||
</tbody>
|
||||
</InfoTable>
|
||||
{permissionOverview}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Page } from "@scm-manager/ui-components";
|
||||
import { Form, useCreateResource } from "@scm-manager/ui-forms";
|
||||
import * as userValidator from "../components/userValidation";
|
||||
import { Link, User, UserCollection, UserCreation } from "@scm-manager/ui-types";
|
||||
import { ErrorNotification, Loading, Notification } from "@scm-manager/ui-core";
|
||||
import { ErrorNotification, Loading, Notification, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { useUsers } from "@scm-manager/ui-api";
|
||||
|
||||
type UserCreationForm = Pick<UserCreation, "password" | "name" | "displayName" | "active" | "external" | "mail"> & {
|
||||
@@ -30,6 +30,7 @@ type UserCreationForm = Pick<UserCreation, "password" | "name" | "displayName" |
|
||||
|
||||
const CreateUserForm: FC<{ users: UserCollection }> = ({ users }) => {
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("createUser.title"));
|
||||
const { submit, submissionResult: createdUser } = useCreateResource<UserCreationForm, User>(
|
||||
(users._links.create as Link).href,
|
||||
["user", "users"],
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import DeleteUser from "./DeleteUser";
|
||||
import { User } from "@scm-manager/ui-types";
|
||||
import UserConverter from "../components/UserConverter";
|
||||
import { Form, useUpdateResource } from "@scm-manager/ui-forms";
|
||||
import * as userValidator from "../components/userValidation";
|
||||
import { Subtitle } from "@scm-manager/ui-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { User } from "@scm-manager/ui-types";
|
||||
import { Subtitle } from "@scm-manager/ui-components";
|
||||
import { useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { Form, useUpdateResource } from "@scm-manager/ui-forms";
|
||||
import UserConverter from "../components/UserConverter";
|
||||
import * as userValidator from "../components/userValidation";
|
||||
import DeleteUser from "./DeleteUser";
|
||||
|
||||
type Props = {
|
||||
user: User;
|
||||
@@ -29,6 +30,7 @@ type Props = {
|
||||
|
||||
const EditUser: FC<Props> = ({ user }) => {
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("singleUser.settingsTitle"), user.displayName);
|
||||
const { submit } = useUpdateResource<User>(user, (user) => user.name, {
|
||||
contentType: "application/vnd.scmm-user+json;v=2",
|
||||
collectionName: ["user", "users"],
|
||||
|
||||
@@ -20,7 +20,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { useUsers } from "@scm-manager/ui-api";
|
||||
import { User, UserCollection } from "@scm-manager/ui-types";
|
||||
import { CreateButton, LinkPaginator, OverviewPageActions, Page, PageActions, urls } from "@scm-manager/ui-components";
|
||||
import { Notification } from "@scm-manager/ui-core";
|
||||
import { Notification, useDocumentTitle } from "@scm-manager/ui-core";
|
||||
import { UserTable } from "./../components/table";
|
||||
|
||||
type UserPageProps = {
|
||||
@@ -52,6 +52,7 @@ const Users: FC = () => {
|
||||
const page = urls.getPageFromMatch({ params });
|
||||
const { isLoading, error, data } = useUsers({ page: page - 1, search });
|
||||
const [t] = useTranslation("users");
|
||||
useDocumentTitle(t("users.title"));
|
||||
const users = data?._embedded?.users;
|
||||
const canAddUsers = !!data?._links.create;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user