mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-05-06 11:46:10 +02:00
fix autocompletion
This commit is contained in:
@@ -4,7 +4,6 @@ import { AsyncCreatable, Async } from "react-select";
|
||||
import type { AutocompleteObject, SelectValue } from "@scm-manager/ui-types";
|
||||
import LabelWithHelpIcon from "./forms/LabelWithHelpIcon";
|
||||
|
||||
|
||||
type Props = {
|
||||
loadSuggestions: string => Promise<AutocompleteObject>,
|
||||
valueSelected: SelectValue => void,
|
||||
@@ -17,12 +16,9 @@ type Props = {
|
||||
creatable?: boolean
|
||||
};
|
||||
|
||||
|
||||
type State = {};
|
||||
|
||||
class Autocomplete extends React.Component<Props, State> {
|
||||
|
||||
|
||||
static defaultProps = {
|
||||
placeholder: "Type here",
|
||||
loadingMessage: "Loading...",
|
||||
@@ -34,7 +30,11 @@ class Autocomplete extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
// We overwrite this to avoid running into a bug (https://github.com/JedWatson/react-select/issues/2944)
|
||||
isValidNewOption = (inputValue: string, selectValue: SelectValue, selectOptions: SelectValue[]) => {
|
||||
isValidNewOption = (
|
||||
inputValue: string,
|
||||
selectValue: SelectValue,
|
||||
selectOptions: SelectValue[]
|
||||
) => {
|
||||
const isNotDuplicated = !selectOptions
|
||||
.map(option => option.label)
|
||||
.includes(inputValue);
|
||||
@@ -43,12 +43,21 @@ class Autocomplete extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { label, helpText, value, placeholder, loadingMessage, noOptionsMessage, loadSuggestions, creatable } = this.props;
|
||||
const {
|
||||
label,
|
||||
helpText,
|
||||
value,
|
||||
placeholder,
|
||||
loadingMessage,
|
||||
noOptionsMessage,
|
||||
loadSuggestions,
|
||||
creatable
|
||||
} = this.props;
|
||||
return (
|
||||
<div className="field">
|
||||
<LabelWithHelpIcon label={label} helpText={helpText} />
|
||||
<div className="control">
|
||||
{creatable?
|
||||
{creatable ? (
|
||||
<AsyncCreatable
|
||||
cacheOptions
|
||||
loadOptions={loadSuggestions}
|
||||
@@ -65,7 +74,7 @@ class Autocomplete extends React.Component<Props, State> {
|
||||
});
|
||||
}}
|
||||
/>
|
||||
:
|
||||
) : (
|
||||
<Async
|
||||
cacheOptions
|
||||
loadOptions={loadSuggestions}
|
||||
@@ -75,13 +84,11 @@ class Autocomplete extends React.Component<Props, State> {
|
||||
loadingMessage={() => loadingMessage}
|
||||
noOptionsMessage={() => noOptionsMessage}
|
||||
/>
|
||||
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Autocomplete;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type { SelectValue } from "@scm-manager/ui-types";
|
||||
import UserGroupAutocomplete from "./UserGroupAutocomplete";
|
||||
|
||||
type Props = {
|
||||
groupAutocompleteLink: string,
|
||||
valueSelected: SelectValue => void,
|
||||
value?: SelectValue,
|
||||
|
||||
// Context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
class GroupAutocomplete extends React.Component<Props> {
|
||||
selectName = (selection: SelectValue) => {
|
||||
this.props.valueSelected(selection);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { groupAutocompleteLink, t, value } = this.props;
|
||||
return (
|
||||
<UserGroupAutocomplete
|
||||
autocompleteLink={groupAutocompleteLink}
|
||||
label={t("autocomplete.group")}
|
||||
noOptionsMessage={t("autocomplete.noGroupOptions")}
|
||||
loadingMessage={t("autocomplete.loading")}
|
||||
placeholder={t("autocomplete.groupPlaceholder")}
|
||||
valueSelected={this.selectName}
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("commons")(GroupAutocomplete);
|
||||
@@ -0,0 +1,37 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type { SelectValue } from "@scm-manager/ui-types";
|
||||
import UserGroupAutocomplete from "./UserGroupAutocomplete";
|
||||
|
||||
type Props = {
|
||||
userAutocompleteLink: string,
|
||||
valueSelected: SelectValue => void,
|
||||
value?: SelectValue,
|
||||
|
||||
// Context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
class UserAutocomplete extends React.Component<Props> {
|
||||
selectName = (selection: SelectValue) => {
|
||||
this.props.valueSelected(selection);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { userAutocompleteLink, t, value } = this.props;
|
||||
return (
|
||||
<UserGroupAutocomplete
|
||||
autocompleteLink={userAutocompleteLink}
|
||||
label={t("autocomplete.user")}
|
||||
noOptionsMessage={t("autocomplete.noUserOptions")}
|
||||
loadingMessage={t("autocomplete.loading")}
|
||||
placeholder={t("autocomplete.userPlaceholder")}
|
||||
valueSelected={this.selectName}
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("commons")(UserAutocomplete);
|
||||
@@ -0,0 +1,57 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import type { SelectValue } from "@scm-manager/ui-types";
|
||||
import Autocomplete from "./Autocomplete";
|
||||
|
||||
type Props = {
|
||||
autocompleteLink: string,
|
||||
label: string,
|
||||
noOptionsMessage: string,
|
||||
loadingMessage: string,
|
||||
placeholder: string,
|
||||
valueSelected: SelectValue => void,
|
||||
value?: SelectValue
|
||||
};
|
||||
|
||||
class UserGroupAutocomplete extends React.Component<Props> {
|
||||
loadSuggestions = (inputValue: string) => {
|
||||
const url = this.props.autocompleteLink;
|
||||
const link = url + "?q=";
|
||||
return fetch(link + inputValue)
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
return json.map(element => {
|
||||
const label = element.displayName
|
||||
? `${element.displayName} (${element.id})`
|
||||
: element.id;
|
||||
return {
|
||||
value: element,
|
||||
label
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
selectName = (selection: SelectValue) => {
|
||||
this.props.valueSelected(selection);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { autocompleteLink, label, noOptionsMessage, loadingMessage, placeholder, value } = this.props;
|
||||
return (
|
||||
<Autocomplete
|
||||
autocompleteLink={autocompleteLink}
|
||||
label={label}
|
||||
noOptionsMessage={noOptionsMessage}
|
||||
loadingMessage={loadingMessage}
|
||||
placeholder={placeholder}
|
||||
loadSuggestions={this.loadSuggestions}
|
||||
valueSelected={this.selectName}
|
||||
value={value}
|
||||
creatable={true}
|
||||
/>
|
||||
); // {...this.props}
|
||||
}
|
||||
}
|
||||
|
||||
export default UserGroupAutocomplete;
|
||||
@@ -40,6 +40,15 @@
|
||||
"config": "Einstellungen"
|
||||
},
|
||||
"filterEntries": "Einträge filtern",
|
||||
"autocomplete": {
|
||||
"group": "Gruppe",
|
||||
"user": "Benutzer",
|
||||
"noGroupOptions": "Kein Gruppenname als Vorschlag verfügbar",
|
||||
"groupPlaceholder": "Gruppe eingeben",
|
||||
"noUserOptions": "Kein Benutzername als Vorschlag verfügbar",
|
||||
"userPlaceholder": "Benutzer eingeben",
|
||||
"loading": "suche..."
|
||||
},
|
||||
"paginator": {
|
||||
"next": "Weiter",
|
||||
"previous": "Zurück"
|
||||
|
||||
@@ -150,13 +150,6 @@
|
||||
"roleHelpText": "READ = read; WRITE = read und write; OWNER = read, write und auch die Möglichkeit Einstellungen und Berechtigungen zu verwalten. Wenn hier nichts angezeigt wird, den Erweitert-Button benutzen, um Details zu sehen.",
|
||||
"permissionsHelpText": "Hier können individuelle Berechtigungen unabhängig von vordefinierten Rollen vergeben werden."
|
||||
},
|
||||
"autocomplete": {
|
||||
"no-group-options": "Kein Gruppenname als Vorschlag verfügbar",
|
||||
"group-placeholder": "Gruppe eingeben",
|
||||
"no-user-options": "Kein Benutzername als Vorschlag verfügbar",
|
||||
"user-placeholder": "Benutzer eingeben",
|
||||
"loading": "suche..."
|
||||
},
|
||||
"advanced": {
|
||||
"dialog": {
|
||||
"title": "Erweiterte Berechtigungen",
|
||||
|
||||
@@ -40,6 +40,15 @@
|
||||
"config": "Configuration"
|
||||
},
|
||||
"filterEntries": "filter entries",
|
||||
"autocomplete": {
|
||||
"group": "Group",
|
||||
"user": "User",
|
||||
"noGroupOptions": "No group suggestion available",
|
||||
"groupPlaceholder": "Enter group",
|
||||
"noUserOptions": "No user suggestion available",
|
||||
"userPlaceholder": "Enter user",
|
||||
"loading": "Loading..."
|
||||
},
|
||||
"paginator": {
|
||||
"next": "Next",
|
||||
"previous": "Previous"
|
||||
|
||||
@@ -153,13 +153,6 @@
|
||||
"roleHelpText": "READ = read; WRITE = read and write; OWNER = read, write and also the ability to manage the properties and permissions. If nothing is selected here, use the 'Advanced' Button to see detailed permissions.",
|
||||
"permissionsHelpText": "Use this to specify your own set of permissions regardless of predefined roles."
|
||||
},
|
||||
"autocomplete": {
|
||||
"no-group-options": "No group suggestion available",
|
||||
"group-placeholder": "Enter group",
|
||||
"no-user-options": "No user suggestion available",
|
||||
"user-placeholder": "Enter user",
|
||||
"loading": "Loading..."
|
||||
},
|
||||
"advanced": {
|
||||
"dialog": {
|
||||
"title": "Advanced Permissions",
|
||||
|
||||
@@ -9,11 +9,12 @@ import type {
|
||||
} from "@scm-manager/ui-types";
|
||||
import {
|
||||
Subtitle,
|
||||
Autocomplete,
|
||||
SubmitButton,
|
||||
Button,
|
||||
LabelWithHelpIcon,
|
||||
Radio
|
||||
Radio,
|
||||
GroupAutocomplete,
|
||||
UserAutocomplete
|
||||
} from "@scm-manager/ui-components";
|
||||
import * as validator from "../components/permissionValidation";
|
||||
import RoleSelector from "../components/RoleSelector";
|
||||
@@ -26,8 +27,8 @@ type Props = {
|
||||
createPermission: (permission: PermissionCreateEntry) => void,
|
||||
loading: boolean,
|
||||
currentPermissions: PermissionCollection,
|
||||
groupAutoCompleteLink: string,
|
||||
userAutoCompleteLink: string,
|
||||
groupAutocompleteLink: string,
|
||||
userAutocompleteLink: string,
|
||||
|
||||
// Context props
|
||||
t: string => string
|
||||
@@ -68,65 +69,27 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
loadUserAutocompletion = (inputValue: string) => {
|
||||
return this.loadAutocompletion(this.props.userAutoCompleteLink, inputValue);
|
||||
};
|
||||
|
||||
loadGroupAutocompletion = (inputValue: string) => {
|
||||
return this.loadAutocompletion(
|
||||
this.props.groupAutoCompleteLink,
|
||||
inputValue
|
||||
);
|
||||
};
|
||||
|
||||
loadAutocompletion(url: string, inputValue: string) {
|
||||
const link = url + "?q=";
|
||||
return fetch(link + inputValue)
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
return json.map(element => {
|
||||
const label = element.displayName
|
||||
? `${element.displayName} (${element.id})`
|
||||
: element.id;
|
||||
return {
|
||||
value: element,
|
||||
label
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderAutocompletionField = () => {
|
||||
const { t } = this.props;
|
||||
if (this.state.groupPermission) {
|
||||
const group = this.state.groupPermission;
|
||||
if (group) {
|
||||
return (
|
||||
<Autocomplete
|
||||
loadSuggestions={this.loadGroupAutocompletion}
|
||||
valueSelected={this.groupOrUserSelected}
|
||||
<GroupAutocomplete
|
||||
groupAutocompleteLink={this.props.groupAutocompleteLink}
|
||||
valueSelected={this.selectName}
|
||||
value={this.state.value ? this.state.value : ""}
|
||||
label={t("permission.group")}
|
||||
noOptionsMessage={t("permission.autocomplete.no-group-options")}
|
||||
loadingMessage={t("permission.autocomplete.loading")}
|
||||
placeholder={t("permission.autocomplete.group-placeholder")}
|
||||
creatable={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Autocomplete
|
||||
loadSuggestions={this.loadUserAutocompletion}
|
||||
valueSelected={this.groupOrUserSelected}
|
||||
<UserAutocomplete
|
||||
userAutocompleteLink={this.props.userAutocompleteLink}
|
||||
valueSelected={this.selectName}
|
||||
value={this.state.value ? this.state.value : ""}
|
||||
label={t("permission.user")}
|
||||
noOptionsMessage={t("permission.autocomplete.no-user-options")}
|
||||
loadingMessage={t("permission.autocomplete.loading")}
|
||||
placeholder={t("permission.autocomplete.user-placeholder")}
|
||||
creatable={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
groupOrUserSelected = (value: SelectValue) => {
|
||||
selectName = (value: SelectValue) => {
|
||||
this.setState({
|
||||
value,
|
||||
name: value.value.id,
|
||||
@@ -150,15 +113,17 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
<AdvancedPermissionsDialog
|
||||
availableVerbs={availableVerbs}
|
||||
selectedVerbs={selectedVerbs}
|
||||
onClose={this.closeAdvancedPermissionsDialog}
|
||||
onClose={this.toggleAdvancedPermissionsDialog}
|
||||
onSubmit={this.submitAdvancedPermissionsDialog}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<hr />
|
||||
<Subtitle subtitle={t("permission.add-permission.add-permission-heading")} />
|
||||
<Subtitle
|
||||
subtitle={t("permission.add-permission.add-permission-heading")}
|
||||
/>
|
||||
{advancedDialog}
|
||||
<form onSubmit={this.submit}>
|
||||
<div className="field is-grouped">
|
||||
@@ -201,7 +166,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
/>
|
||||
<Button
|
||||
label={t("permission.advanced-button.label")}
|
||||
action={this.handleDetailedPermissionsPressed}
|
||||
action={this.toggleAdvancedPermissionsDialog}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -217,16 +182,14 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
handleDetailedPermissionsPressed = () => {
|
||||
this.setState({ showAdvancedDialog: true });
|
||||
};
|
||||
|
||||
closeAdvancedPermissionsDialog = () => {
|
||||
this.setState({ showAdvancedDialog: false });
|
||||
toggleAdvancedPermissionsDialog = () => {
|
||||
this.setState(prevState => ({
|
||||
showAdvancedDialog: !prevState.showAdvancedDialog
|
||||
}));
|
||||
};
|
||||
|
||||
submitAdvancedPermissionsDialog = (newVerbs: string[]) => {
|
||||
|
||||
@@ -60,8 +60,8 @@ type Props = {
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string,
|
||||
permissionsLink: string,
|
||||
groupAutoCompleteLink: string,
|
||||
userAutoCompleteLink: string,
|
||||
groupAutocompleteLink: string,
|
||||
userAutocompleteLink: string,
|
||||
|
||||
//dispatch functions
|
||||
fetchAvailablePermissionsIfNeeded: (
|
||||
@@ -129,8 +129,8 @@ class Permissions extends React.Component<Props> {
|
||||
repoName,
|
||||
loadingCreatePermission,
|
||||
hasPermissionToCreate,
|
||||
userAutoCompleteLink,
|
||||
groupAutoCompleteLink
|
||||
userAutocompleteLink,
|
||||
groupAutocompleteLink
|
||||
} = this.props;
|
||||
if (error) {
|
||||
return (
|
||||
@@ -153,8 +153,8 @@ class Permissions extends React.Component<Props> {
|
||||
createPermission={permission => this.createPermission(permission)}
|
||||
loading={loadingCreatePermission}
|
||||
currentPermissions={permissions}
|
||||
userAutoCompleteLink={userAutoCompleteLink}
|
||||
groupAutoCompleteLink={groupAutoCompleteLink}
|
||||
userAutocompleteLink={userAutocompleteLink}
|
||||
groupAutocompleteLink={groupAutocompleteLink}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
@@ -163,41 +163,41 @@ class Permissions extends React.Component<Props> {
|
||||
<Subtitle subtitle={t("permission.title")} />
|
||||
<table className="card-table table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.name")}
|
||||
helpText={t("permission.help.nameHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.role")}
|
||||
helpText={t("permission.help.roleHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.permissions")}
|
||||
helpText={t("permission.help.permissionsHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.name")}
|
||||
helpText={t("permission.help.nameHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.role")}
|
||||
helpText={t("permission.help.roleHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.permissions")}
|
||||
helpText={t("permission.help.permissionsHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{permissions.map(permission => {
|
||||
return (
|
||||
<SinglePermission
|
||||
availableRepositoryRoles={availableRepositoryRoles}
|
||||
availableRepositoryVerbs={availableVerbs}
|
||||
key={permission.name + permission.groupPermission.toString()}
|
||||
namespace={namespace}
|
||||
repoName={repoName}
|
||||
permission={permission}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{permissions.map(permission => {
|
||||
return (
|
||||
<SinglePermission
|
||||
availableRepositoryRoles={availableRepositoryRoles}
|
||||
availableRepositoryVerbs={availableVerbs}
|
||||
key={permission.name + permission.groupPermission.toString()}
|
||||
namespace={namespace}
|
||||
repoName={repoName}
|
||||
permission={permission}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
{createPermissionForm}
|
||||
@@ -228,8 +228,8 @@ const mapStateToProps = (state, ownProps) => {
|
||||
const repositoryRolesLink = getRepositoryRolesLink(state);
|
||||
const repositoryVerbsLink = getRepositoryVerbsLink(state);
|
||||
const permissionsLink = getPermissionsLink(state, namespace, repoName);
|
||||
const groupAutoCompleteLink = getGroupAutoCompleteLink(state);
|
||||
const userAutoCompleteLink = getUserAutoCompleteLink(state);
|
||||
const groupAutocompleteLink = getGroupAutoCompleteLink(state);
|
||||
const userAutocompleteLink = getUserAutoCompleteLink(state);
|
||||
const availablePermissions = getAvailablePermissions(state);
|
||||
const availableRepositoryRoles = getAvailableRepositoryRoles(state);
|
||||
const availableVerbs = getAvailableRepositoryVerbs(state);
|
||||
@@ -248,8 +248,8 @@ const mapStateToProps = (state, ownProps) => {
|
||||
hasPermissionToCreate,
|
||||
loadingCreatePermission,
|
||||
permissionsLink,
|
||||
groupAutoCompleteLink,
|
||||
userAutoCompleteLink
|
||||
groupAutocompleteLink,
|
||||
userAutocompleteLink
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user