kopia lustrzana https://github.com/OpenDroneMap/WebODM
Autocomplete
rodzic
0db85bba66
commit
31006b9373
|
@ -27,8 +27,8 @@ tasks_router = routers.NestedSimpleRouter(router, r'projects', lookup='project')
|
||||||
tasks_router.register(r'tasks', TaskViewSet, base_name='projects-tasks')
|
tasks_router.register(r'tasks', TaskViewSet, base_name='projects-tasks')
|
||||||
|
|
||||||
admin_router = routers.DefaultRouter()
|
admin_router = routers.DefaultRouter()
|
||||||
admin_router.register(r'admin/users', UserViewSet, basename='user')
|
admin_router.register(r'admin/users', UserViewSet, base_name='admin-users')
|
||||||
admin_router.register(r'admin/groups', GroupViewSet, basename='group')
|
admin_router.register(r'admin/groups', GroupViewSet, base_name='admin-groups')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'processingnodes/options/$', ProcessingNodeOptionsView.as_view()),
|
url(r'processingnodes/options/$', ProcessingNodeOptionsView.as_view()),
|
||||||
|
|
|
@ -26,10 +26,14 @@ class EditPermissionsPanel extends React.Component {
|
||||||
loading: false,
|
loading: false,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
validUsernames: {},
|
validUsernames: {},
|
||||||
validatingUser: false
|
validatingUser: false,
|
||||||
|
validationUnavailable: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.backgroundFailedColor = Css.getValue('btn-danger', 'backgroundColor');
|
this.backgroundFailedColor = Css.getValue('btn-danger', 'backgroundColor');
|
||||||
|
this.autocompleteBorderColor = Css.getValue('btn-default', 'backgroundColor');
|
||||||
|
this.backgroundColor = Css.getValue('theme-secondary', 'backgroundColor');
|
||||||
|
this.highlightColor = Css.getValue('theme-background-highlight', 'backgroundColor');
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPermissions = () => {
|
loadPermissions = () => {
|
||||||
|
@ -49,7 +53,7 @@ class EditPermissionsPanel extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
validateUsername = (username) => {
|
autocomplete = (perm) => {
|
||||||
if (this.validateReq){
|
if (this.validateReq){
|
||||||
this.validateReq.abort();
|
this.validateReq.abort();
|
||||||
this.validateReq = null;
|
this.validateReq = null;
|
||||||
|
@ -60,18 +64,29 @@ class EditPermissionsPanel extends React.Component {
|
||||||
this.validateTimeout = null;
|
this.validateTimeout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({validatingUser: true});
|
|
||||||
|
|
||||||
|
// Empty case
|
||||||
|
if (perm.username === ""){
|
||||||
|
delete(perm.autocomplete);
|
||||||
|
this.setState({permissions: this.state.permissions});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({validatingUser: true});
|
||||||
this.validateTimeout = setTimeout(() => {
|
this.validateTimeout = setTimeout(() => {
|
||||||
this.validateReq = $.getJSON(`/api/users/?limit=30&search=${encodeURIComponent(username)}`)
|
this.validateReq = $.getJSON(`/api/users/?limit=30&search=${encodeURIComponent(perm.username)}`)
|
||||||
.done((json) => {
|
.done((json) => {
|
||||||
json.forEach(u => {
|
json.forEach(u => {
|
||||||
this.state.validUsernames[u.username] = true;
|
this.state.validUsernames[u.username] = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState({validUsernames: this.state.validUsernames});
|
this.state.permissions.forEach(p => delete(p.autocomplete));
|
||||||
}).fail(() => {
|
perm.autocomplete = json;
|
||||||
|
|
||||||
|
this.setState({validUsernames: this.state.validUsernames, permissions: this.state.permissions});
|
||||||
|
}).fail(() => {
|
||||||
|
// Perhaps the user API is not enabled
|
||||||
|
this.setState({validationUnavailable: true});
|
||||||
}).always(() => {
|
}).always(() => {
|
||||||
this.setState({validatingUser: false});
|
this.setState({validatingUser: false});
|
||||||
});
|
});
|
||||||
|
@ -88,15 +103,18 @@ class EditPermissionsPanel extends React.Component {
|
||||||
if (this.validateTimeout) clearTimeout(this.validateTimeout);
|
if (this.validateTimeout) clearTimeout(this.validateTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangePermissionRole = e => {
|
handleChangePermissionRole = perm => {
|
||||||
|
return e => {
|
||||||
|
perm.permissions = this.extendedPermissions(e.target.value);
|
||||||
|
this.setState({permissions: this.state.permissions});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangePermissionUser = perm => {
|
handleChangePermissionUser = perm => {
|
||||||
return e => {
|
return e => {
|
||||||
perm.username = e.target.value;
|
perm.username = e.target.value;
|
||||||
|
|
||||||
this.validateUsername(perm.username);
|
this.autocomplete(perm);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
this.setState({permissions: this.state.permissions});
|
this.setState({permissions: this.state.permissions});
|
||||||
|
@ -111,6 +129,14 @@ class EditPermissionsPanel extends React.Component {
|
||||||
else return "";
|
else return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extendedPermissions = simPerm => {
|
||||||
|
if (simPerm == "rw"){
|
||||||
|
return ["add", "change", "delete", "view"];
|
||||||
|
}else if (simPerm == "r"){
|
||||||
|
return ["view"];
|
||||||
|
}else return [];
|
||||||
|
}
|
||||||
|
|
||||||
permissionLabel = simPerm => {
|
permissionLabel = simPerm => {
|
||||||
if (simPerm === "rw") return _("Read/Write");
|
if (simPerm === "rw") return _("Read/Write");
|
||||||
else if (simPerm === "r") return _("Read");
|
else if (simPerm === "r") return _("Read");
|
||||||
|
@ -122,7 +148,7 @@ class EditPermissionsPanel extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
getColorFor = (username) => {
|
getColorFor = (username) => {
|
||||||
if (this.state.validatingUser || this.state.validUsernames[username]) return "";
|
if (this.state.validationUnavailable || this.state.validatingUser || this.state.validUsernames[username]) return "";
|
||||||
else return this.backgroundFailedColor;
|
else return this.backgroundFailedColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +170,31 @@ class EditPermissionsPanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
acOnMouseEnter = e => {
|
||||||
|
e.target.style.backgroundColor = this.highlightColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
acOnMouseLeave = e => {
|
||||||
|
e.target.style.backgroundColor = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
acOnClick = (perm, acEntry) => {
|
||||||
|
return e => {
|
||||||
|
perm.username = acEntry.username;
|
||||||
|
delete(perm.autocomplete);
|
||||||
|
this.setState({permissions: this.state.permissions});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur = perm => {
|
||||||
|
return e => {
|
||||||
|
setTimeout(() => {
|
||||||
|
delete(perm.autocomplete);
|
||||||
|
this.setState({permissions: this.state.permissions});
|
||||||
|
}, 150);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const permissions = this.state.permissions.map((p, i) => <form autoComplete="off" key={i}>
|
const permissions = this.state.permissions.map((p, i) => <form autoComplete="off" key={i}>
|
||||||
<div className="permission">
|
<div className="permission">
|
||||||
|
@ -154,17 +205,24 @@ class EditPermissionsPanel extends React.Component {
|
||||||
onChange={this.handleChangePermissionUser(p)}
|
onChange={this.handleChangePermissionUser(p)}
|
||||||
type="text"
|
type="text"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
onBlur={this.onBlur(p)}
|
||||||
disabled={p.owner}
|
disabled={p.owner}
|
||||||
value={p.username}
|
value={p.username}
|
||||||
className="form-control username"
|
className="form-control username"
|
||||||
placeholder={_("Username")}
|
placeholder={_("Username")}
|
||||||
ref={(domNode) => this.lastTextbox = domNode} />
|
ref={(domNode) => this.lastTextbox = domNode} />
|
||||||
|
{p.autocomplete ? <div className="autocomplete" style={{borderColor: this.autocompleteBorderColor, backgroundColor: this.backgroundColor}}>
|
||||||
|
{p.autocomplete.map(ac => <div key={ac.username} onClick={this.acOnClick(p, ac)} className="ac-entry" onMouseEnter={this.acOnMouseEnter} onMouseLeave={this.acOnMouseLeave} style={{borderColor: this.autocompleteBorderColor}}>
|
||||||
|
<div className="ac-user">{ac.username}</div>
|
||||||
|
<div className="ac-email">{ac.email}</div>
|
||||||
|
</div>)}
|
||||||
|
</div> : ""}
|
||||||
</div>
|
</div>
|
||||||
<div className="remove">
|
<div className="remove">
|
||||||
{!p.owner ? <a onClick={this.handleDeletePermission(p)}><i className="fa fa-times"></i></a> : ""}
|
{!p.owner ? <a onClick={this.handleDeletePermission(p)}><i className="fa fa-times"></i></a> : ""}
|
||||||
</div>
|
</div>
|
||||||
<div className="role-container">
|
<div className="role-container">
|
||||||
<select disabled={p.owner} className="form-control" value={this.simplifiedPermission(p.permissions)} onChange={this.handleChangePermissionRole}>
|
<select disabled={p.owner} className="form-control" value={this.simplifiedPermission(p.permissions)} onChange={this.handleChangePermissionRole(p)}>
|
||||||
{this.allPermissions().map(p => <option key={p.key} value={p.key}>{p.label}</option>)}
|
{this.allPermissions().map(p => <option key={p.key} value={p.key}>{p.label}</option>)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
.user-indicator{
|
.user-indicator{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 12px;
|
left: 12px;
|
||||||
top: 15px;
|
top: 16px;
|
||||||
}
|
}
|
||||||
.remove{
|
.remove{
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -33,6 +33,39 @@
|
||||||
|
|
||||||
.username-container{
|
.username-container{
|
||||||
flex-grow: 0.66;
|
flex-grow: 0.66;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.autocomplete{
|
||||||
|
left: 0;
|
||||||
|
top: 44px;
|
||||||
|
z-index: 2;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 2px;
|
||||||
|
max-height: 240px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
.ac-entry{
|
||||||
|
padding: 10px 15px 10px 15px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ac-entry:last-child{
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ac-email{
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.role-container{
|
.role-container{
|
||||||
flex-grow: 0.33;
|
flex-grow: 0.33;
|
||||||
|
|
Ładowanie…
Reference in New Issue