Skip to content

Commit

Permalink
Core api preference setting support (#228)
Browse files Browse the repository at this point in the history
* #223: added preferences setting to my profile section

* #223: added initial public user profile page

* #223: added user public profile link to project personnel table

* #223: added full content to public user profile page

* #223: merged Account Info and My Profile into one section in User Profile Page

* #223: added profile info to public user profile page

* #223: added conditional rendering to public user profile page based user's preference setting

* #223: added full preference setting to user profile page

* #222: added preference setting to project form

* #222: updated public project profile page

* #222: fixed public project profile rendering issue

* #223: updated user preference/ public user profile page based on feedback

* #222: removed project permissions from public profile

* #223: added email addresses selection for user profile page

* #223: fixed common component - Select issue

* #226: updated search placeholder text based on API enhancements

* #226: added enter key search event to project list

* #226: added search triggered by enter key for all search bars with search button

* #222&#223: added helper text to project form and user profile form

* #222: fixed new project form search by key issue

* #222: updated project list to always show link to a project

* #223: removed global roles table from public user profile page
  • Loading branch information
yaxue1123 authored Nov 7, 2022
1 parent 01c9134 commit b58a54a
Show file tree
Hide file tree
Showing 21 changed files with 687 additions and 267 deletions.
2 changes: 2 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Experiments from "./pages/Experiments";
import SliceViewer from "./pages/SliceViewer";
import NewSliceForm from "./pages/NewSliceForm";
import User from "./pages/User";
import PublicUserProfile from "./components/UserProfile/PublicUserProfile.jsx";
import NotFound from "./pages/NotFound";
import Help from "./pages/Help";
import Header from "./components/Header";
Expand Down Expand Up @@ -89,6 +90,7 @@ class App extends React.Component {
<ProtectedRoute path="/projects/:id" component={ProjectForm} />
<ProtectedRoute path="/projects" component={Projects} />
<ProtectedRoute path="/experiments" component={Experiments} />
<ProtectedRoute path="/users/:id" component={PublicUserProfile} />
<ProtectedRoute path="/user" component={User} />
<Route component={NotFound} />
</Switch>
Expand Down
26 changes: 17 additions & 9 deletions src/components/Project/NewProjectForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,9 @@ class NewProjectForm extends Form {
uuid: "",
description: "",
facility: portalData.defaultFacility,
is_public: "Yes",
is_public: "Yes"
},
publicOptions: [
{ "_id": 1, "name": "Yes" },
{ "_id": 2, "name": "No" }
],
publicOptions: ["Yes", "No"],
errors: {},
owners: [],
addedOwners: [],
Expand Down Expand Up @@ -121,6 +118,13 @@ class NewProjectForm extends Form {
}
};

raiseInputKeyDown = (e) => {
const query = e.target.value;
if ((e.key === "Enter") && query) {
this.handleSearch(query);
}
};

handleInputChange = (input, type) => {
if (type === "po") {
this.setState({ ownerSearchInput: input });
Expand Down Expand Up @@ -176,7 +180,7 @@ class NewProjectForm extends Form {
{this.renderInput("name", "Name", true)}
{this.renderTextarea("description", "Description", true)}
{this.renderSelect("facility", "Facility", true, portalData.defaultFacility, portalData.facilityOptions)}
{this.renderSelect("is_public", "Public", true, "", publicOptions)}
{this.renderSelect("is_public", "Public", true, "Yes", publicOptions, portalData.helperText.publicProjectDescription)}
{this.renderButton("Create")}
</form>
<div className="mt-4">
Expand Down Expand Up @@ -211,8 +215,9 @@ class NewProjectForm extends Form {
<input
className="form-control search-owner-input mb-4"
value={this.stateownerSearchInput}
placeholder="Search by name or email (at least 4 letters) to add project owners..."
placeholder="Search by name/email (at least 4 letters) or UUID to add project owners..."
onChange={(e) => this.handleInputChange(e.currentTarget.value, "po")}
onKeyDown={this.raiseInputKeyDown}
/>
<button
className="btn btn-primary"
Expand Down Expand Up @@ -257,9 +262,10 @@ class NewProjectForm extends Form {
<div className="toolbar">
<input
className="form-control search-member-input mb-4"
placeholder="Search by name or email (at least 4 letters) to add project members..."
placeholder="Search by name/email (at least 4 letters) or UUID to add project members..."
value={memberSearchInput}
onChange={(e) => this.handleInputChange(e.currentTarget.value, "pm")}
onKeyDown={this.raiseInputKeyDown}
/>
<button
className="btn btn-primary"
Expand Down Expand Up @@ -288,7 +294,9 @@ class NewProjectForm extends Form {
<FontAwesomeIcon icon={faPlus} size="xs"/>
</button>
<br></br>
<span>{user.email}</span>
{
user.email && <span>{user.email}</span>
}
</li>
);
})}
Expand Down
15 changes: 13 additions & 2 deletions src/components/Project/ProjectPersonnel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ class ProjectPersonnel extends Component {
}
};

raiseInputKeyDown = (e) => {
const query = e.target.value;
if ((e.key === "Enter") && query) {
this.handleSearch(query);
}
};

handleDeleteUser = (user) => {
const { personnelType } = this.props;
this.props.onSinglePersonnelUpdate(personnelType, user, "remove");
Expand All @@ -65,8 +72,9 @@ class ProjectPersonnel extends Component {
<input
className="form-control search-owner-input"
value={searchInput}
placeholder={`Search by name or email (at least 4 letters) to add ${personnelType}...`}
placeholder={`Search by name/email (at least 4 letters) or UUID to add ${personnelType}...`}
onChange={(e) => this.handleInputChange(e.currentTarget.value)}
onKeyDown={this.raiseInputKeyDown}
/>
<button
className="btn btn-primary"
Expand All @@ -91,7 +99,10 @@ class ProjectPersonnel extends Component {
key={`search-user-result-${index}`}
className="list-group-item d-flex flex-row justify-content-between"
>
<div className="mt-1">{`${user.name} (${user.email})`}</div>
{
user.email ? <div className="mt-1">{`${user.name} (${user.email})`}</div> :
<div className="mt-1">{user.name}</div>
}
<button
className="btn btn-sm btn-primary ml-2"
onClick={() => this.handleAddUser(user)}
Expand Down
89 changes: 59 additions & 30 deletions src/components/Project/ProjectProfile.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { Component } from "react";
import CopyButton from "../common/CopyButton";
import Table from "../common/Table";
import toLocaleTime from "../../utils/toLocaleTime";
import _ from "lodash";
import { Link } from "react-router-dom";
import { default as portalData } from "../../services/portalData.json";

class ProjectProfile extends Component {
state = {
Expand All @@ -15,23 +15,22 @@ class ProjectProfile extends Component {
{ label: "Creator Name", path: "creator_name" },
{ label: "Creator Email", path: "creator_email" },
{ label: "Creator ID", path: "creator_id" }
]
}

renderTags(tags) {
return <ul className="input-tag__tags">
],
projectPersonnelColumns: [
{
tags && tags.length > 0 && tags.map((tag, index) =>
<li key={`project-tag-${index}`}>
{tag}
</li>
path: "name",
label: "Name",
content: (user) => (
<Link to={`/users/${user.uuid}`}>{user.name}</Link>
)
}
</ul>;
},
{ path: "email", label: "Email" },
{ path: "uuid", label: "ID" },
]
}

render() {
const { basicInfoRows } = this.state;
const { basicInfoRows, projectPersonnelColumns } = this.state;
const { project } = this.props;
return (
<div>
Expand All @@ -46,7 +45,7 @@ class ProjectProfile extends Component {
</button>
</Link>
</div>
<table className="table table-striped table-bordered mt-4">
<table className="table table-sm table-striped table-bordered mt-4">
<tbody>
<tr>
<td>Project ID</td>
Expand All @@ -60,37 +59,67 @@ class ProjectProfile extends Component {
/>
</td>
</tr>
<tr>
<td>
Project Permissions <a
href={`${portalData.learnArticles.guideToProjectPermissions}#project-permissions`}
target="_blank" rel="noreferrer" className="ml-1">
<i className="fa fa-question-circle mx-2"></i>
</a>
</td>
<td>
{ project.tags.length > 0 ? this.renderTags(project.tags) : "No permissions assigned" }
</td>
</tr>
{basicInfoRows.map((row, index) => {
return (
project[row.path] &&
<tr key={`project-basic-info-${index}`}>
<td>
{row.label}
</td>
<td className="project-detail-form-td">
{
row.path === "created" && toLocaleTime(_.get(project, row.path))
}
{
row.path !== "created" && _.get(project, row.path)
row.label.includes("Time") ?
toLocaleTime(_.get(project, row.path)) :
_.get(project, row.path)
}
</td>
</tr>
);
})}
</tbody>
</table>
<div className="mt-4">
<h2>Project Owners</h2>
{
!project.project_owners && <div className="alert alert-primary mb-2" role="alert">
The <b>Project Owners</b> information is set as private.
</div>
}
{
project.project_owners && project.project_owners.length === 0 && <div className="alert alert-primary mb-2" role="alert">
This project doesn't have Project Owner.
</div>
}
{
project.project_owners && project.project_owners.length > 0 &&
<Table
columns={projectPersonnelColumns}
data={project.project_owners}
size={"sm"}
/>
}
</div>
<div className="mt-4">
<h2>Project Members</h2>
{
!project.project_members && <div className="alert alert-primary mb-2" role="alert">
The <b>Project Members</b> information is set as private.
</div>
}
{
project.project_members && project.project_members.length === 0 && <div className="alert alert-primary mb-2" role="alert">
This project doesn't have Project Member.
</div>
}
{
project.project_members && project.project_members.length > 0 &&
<Table
columns={projectPersonnelColumns}
data={project.project_members}
size={"sm"}
/>
}
</div>
</div>
);
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/Project/ProjectUserTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import Table from "../common/Table";
import Pagination from "../common/Pagination";
import _ from "lodash";
import paginate from "../../utils/paginate";
import { Link } from "react-router-dom";

class ProjectUserTable extends Component {
columns = [
{
path: "name",
label: "Name",
content: (user) => (
<Link to={`/users/${user.uuid}`}>{user.name}</Link>
)
},
{ path: "email", label: "Email" },
{ path: "uuid", label: "ID" },
Expand Down
58 changes: 4 additions & 54 deletions src/components/Project/ProjectsTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,7 @@ import Table from "../common/Table";
import _ from "lodash";

class ProjectsTable extends Component {
hasAccessToProject = (project) => {
const membership = project.membership;
if (membership) {
return project.is_public || membership.is_creator
|| membership.is_owner || membership.is_member;
} else {
return project.is_public;
}
}

columns = {
"alwaysShowLinks": [
columns = [
{
path: "name",
label: "Project Name",
Expand Down Expand Up @@ -48,54 +37,15 @@ class ProjectsTable extends Component {
</button>
</Link>
),
},
],
"onlyShowPublicLinks": [
{
path: "name",
label: "Project Name",
content: (project) => (
this.hasAccessToProject(project) ? <Link to={`/projects/${project.uuid}`}>{project.name}</Link> : <span>{project.name}</span>
)
},
{
path: "description",
label: "Description",
content: (project) => (
<span>
{_.truncate(project.description, {
'length': 250,
'separator': ' '
})}
</span>
)
},
{ path: "facility", label: "Facility" },
{
path: "created_time",
label: "Created Time",
},
{
content: (project) => (
<Link to={`/projects/${project.uuid}`}>
<button
className="btn btn-sm btn-primary"
disabled={!this.hasAccessToProject(project)}
>
View
</button>
</Link>
),
}
]
}

render() {
const { projects, type, isFacilityOperator } = this.props;
const cols = (isFacilityOperator || type === "myProjects") ? this.columns["alwaysShowLinks"] : this.columns["onlyShowPublicLinks"] ;
const { projects } = this.props;

return (
<Table
columns={cols}
columns={this.columns}
data={projects}
size={"md"}
/>
Expand Down
15 changes: 4 additions & 11 deletions src/components/SshKey/GenerateKey.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,11 @@ class GenerateKey extends Form {
getKeyTypeDropdown = (maxSliver, maxBastion) => {
let dropdownItems = [];
if (maxSliver) {
dropdownItems = [
{ "_id": 1, "name": "bastion" },
]
dropdownItems = ["bastion"]
} else if (maxBastion) {
dropdownItems = [
{ "_id": 1, "name": "sliver" },
]
dropdownItems = ["sliver"]
} else {
dropdownItems = [
{ "_id": 1, "name": "sliver" },
{ "_id": 2, "name": "bastion" }
]
dropdownItems = ["sliver", "bastion"]
}

return dropdownItems;
Expand Down Expand Up @@ -104,7 +97,7 @@ class GenerateKey extends Form {
<form onSubmit={this.handleSubmit}>
{this.renderInput("name", "Name", true, nameTooltip)}
{this.renderTextarea("description", "Description", true, descriptionTooltip)}
{this.renderSelect("keyType", "Key Type", true, "", this.getKeyTypeDropdown(maxSliver, maxBastion))}
{this.renderSelect("keyType", "Key Type", true, this.getKeyTypeDropdown(maxSliver, maxBastion)[0], this.getKeyTypeDropdown(maxSliver, maxBastion))}
{this.renderButton("Generate Key Pair")}
</form>
}
Expand Down
Loading

0 comments on commit b58a54a

Please sign in to comment.