mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
make team members page work
This commit is contained in:
@@ -51,6 +51,10 @@ module.exports = {
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: ['style-loader', 'css-loader', "sass-loader"]
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
loader: 'file-loader'
|
||||
|
||||
@@ -3,8 +3,6 @@ import {
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
} from 'typeorm';
|
||||
import BaseModel from './BaseModel';
|
||||
@@ -18,7 +16,6 @@ import TableColumn from '../Types/Database/TableColumn';
|
||||
import ColumnType from '../Types/Database/ColumnType';
|
||||
import ObjectID from '../Types/ObjectID';
|
||||
import ColumnLength from '../Types/Database/ColumnLength';
|
||||
import TeamPermission from './TeamPermission';
|
||||
import TableAccessControl from '../Types/Database/AccessControl/TableAccessControl';
|
||||
import Permission from '../Types/Permission';
|
||||
import ColumnAccessControl from '../Types/Database/AccessControl/ColumnAccessControl';
|
||||
@@ -230,12 +227,6 @@ export default class Team extends BaseModel {
|
||||
})
|
||||
public deletedByUserId?: ObjectID = undefined;
|
||||
|
||||
@ManyToMany(() => {
|
||||
return TeamPermission;
|
||||
})
|
||||
@JoinTable()
|
||||
public permissions?: Array<TeamPermission> = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [
|
||||
|
||||
@@ -130,6 +130,12 @@ export class PermissionHelper {
|
||||
description: 'Owner of this project, manages billing, inviting other admins to this project, and can delete this project.',
|
||||
isAssignableToProject: true
|
||||
},
|
||||
{
|
||||
permission: Permission.ProjectMember,
|
||||
title: 'Project Member',
|
||||
description: 'Member of this project. Can view most resources unless restricted.',
|
||||
isAssignableToProject: true
|
||||
},
|
||||
{
|
||||
permission: Permission.ProjectAdmin,
|
||||
title: 'Project Admin',
|
||||
|
||||
@@ -26,6 +26,8 @@ import SettingsApiKeys from './Pages/Settings/APIKeys';
|
||||
import SettingsApiKeyView from './Pages/Settings/APIKeyView';
|
||||
import SettingLabels from './Pages/Settings/Labels';
|
||||
import SettingCustomSMTP from './Pages/Settings/CustomSMTP';
|
||||
import SettingsTeams from './Pages/Settings/Teams';
|
||||
import SettingsTeamView from './Pages/Settings/TeamView';
|
||||
|
||||
// Import CSS
|
||||
import 'CommonUI/src/Styles/theme.scss';
|
||||
@@ -223,6 +225,30 @@ const App: FunctionComponent = () => {
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteMap[PageMap.SETTINGS_TEAMS]?.toString()}
|
||||
element={
|
||||
<SettingsTeams
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_TEAMS] as Route
|
||||
}
|
||||
currentProject={selectedProject}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteMap[PageMap.SETTINGS_TEAM_VIEW]?.toString()}
|
||||
element={
|
||||
<SettingsTeamView
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_TEAM_VIEW] as Route
|
||||
}
|
||||
currentProject={selectedProject}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Misc Routes */}
|
||||
<PageRoute
|
||||
path={RouteMap[PageMap.LOGOUT]?.toString()}
|
||||
|
||||
@@ -64,7 +64,9 @@ const DashboardSideMenu: FunctionComponent = (): ReactElement => {
|
||||
<SideMenuItem
|
||||
link={{
|
||||
title: 'Teams and Members',
|
||||
to: new Route('/:projectSlug/home'),
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[PageMap.SETTINGS_TEAMS] as Route
|
||||
),
|
||||
}}
|
||||
icon={IconProp.User}
|
||||
/>
|
||||
|
||||
279
Dashboard/src/Pages/Settings/TeamView.tsx
Normal file
279
Dashboard/src/Pages/Settings/TeamView.tsx
Normal file
@@ -0,0 +1,279 @@
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import Page from 'CommonUI/src/Components/Page/Page';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import PageMap from '../../Utils/PageMap';
|
||||
import RouteMap from '../../Utils/RouteMap';
|
||||
import PageComponentProps from '../PageComponentProps';
|
||||
import DashboardSideMenu from './SideMenu';
|
||||
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
|
||||
import TableColumnType from 'CommonUI/src/Components/Table/Types/TableColumnType';
|
||||
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
|
||||
import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
|
||||
import CardModelDetail from "CommonUI/src/Components/ModelDetail/CardModelDetail";
|
||||
import Team from 'Common/Models/Team';
|
||||
import TeamMember from 'Common/Models/TeamMember';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import PermissionUtil from 'CommonUI/src/Utils/Permission';
|
||||
import Label from 'Common/Models/Label';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import Permission, { PermissionHelper } from 'Common/Types/Permission';
|
||||
import ModelDelete from 'CommonUI/src/Components/ModelDelete/ModelDelete';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import Pill from 'CommonUI/src/Components/Pill/Pill';
|
||||
import Color from 'Common/Types/Color';
|
||||
import TeamPermission from 'Common/Models/TeamPermission';
|
||||
|
||||
const TeamView: FunctionComponent<PageComponentProps> = (
|
||||
props: PageComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<Page
|
||||
title={'Project Settings'}
|
||||
breadcrumbLinks={[
|
||||
{
|
||||
title: 'Project',
|
||||
to: RouteMap[PageMap.HOME] as Route,
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
to: RouteMap[PageMap.SETTINGS] as Route,
|
||||
},
|
||||
{
|
||||
title: 'Teams',
|
||||
to: RouteMap[PageMap.SETTINGS_TEAMS] as Route,
|
||||
},
|
||||
{
|
||||
title: 'View Team',
|
||||
to: RouteMap[PageMap.SETTINGS_TEAM_VIEW] as Route,
|
||||
},
|
||||
]}
|
||||
sideMenu={<DashboardSideMenu />}
|
||||
>
|
||||
|
||||
{/* API Key View */}
|
||||
<CardModelDetail
|
||||
cardProps={{
|
||||
title: "Team Details",
|
||||
description: "Here's more details on this team.",
|
||||
icon: IconProp.User,
|
||||
}
|
||||
}
|
||||
isEditable={true}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: 'Name',
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: 'Team Name',
|
||||
validation: {
|
||||
noSpaces: true,
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
description: true,
|
||||
},
|
||||
title: 'Description',
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: true,
|
||||
placeholder:
|
||||
'Team Description',
|
||||
},
|
||||
]}
|
||||
modelDetailProps={
|
||||
{
|
||||
type: Team,
|
||||
model: new Team(),
|
||||
id: "model-detail-team",
|
||||
fields: [
|
||||
{
|
||||
field: {
|
||||
name: true
|
||||
},
|
||||
title: "Name",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
description: true
|
||||
},
|
||||
title: "Description",
|
||||
}
|
||||
],
|
||||
modelId: Navigation.getLastParam(),
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{/* Team Members Table */}
|
||||
|
||||
<ModelTable<TeamMember>
|
||||
type={TeamMember}
|
||||
model={new TeamMember()}
|
||||
id="table-team-member"
|
||||
isDeleteable={true}
|
||||
isEditable={true}
|
||||
isCreateable={true}
|
||||
isViewable={false}
|
||||
cardProps={{
|
||||
icon: IconProp.User,
|
||||
title: 'Team Members',
|
||||
description:
|
||||
'See a list of members or invite them to this team. ',
|
||||
}}
|
||||
noItemsMessage={'No members found for this team.'}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
user: true,
|
||||
},
|
||||
title: 'User Email',
|
||||
description: 'Please enter the email of the user you would like to invite.',
|
||||
fieldType: FormFieldSchemaType.Email,
|
||||
required: false,
|
||||
placeholder:
|
||||
'member@company.com',
|
||||
}
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
showFilterButton={true}
|
||||
currentPageRoute={props.pageRoute}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
user: true,
|
||||
},
|
||||
title: 'User',
|
||||
type: TableColumnType.Text,
|
||||
getColumnElement: (item: JSONObject): ReactElement => {
|
||||
|
||||
if (item["user"]) {
|
||||
if (item["user"] && (item["user"] as JSONObject)['name'] && (item["user"] as JSONObject)['name']) {
|
||||
return <p>item["user"] as JSONObject)['name']</p>;
|
||||
}
|
||||
}
|
||||
|
||||
return <></>;
|
||||
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{/* Team Permisison Table */}
|
||||
|
||||
<ModelTable<TeamPermission>
|
||||
type={TeamPermission}
|
||||
model={new TeamPermission()}
|
||||
id="table-team-permission"
|
||||
isDeleteable={true}
|
||||
isEditable={true}
|
||||
isCreateable={true}
|
||||
isViewable={false}
|
||||
cardProps={{
|
||||
icon: IconProp.Lock,
|
||||
title: 'Team Permissions',
|
||||
description:
|
||||
'Add different permisisons to this team to make it more granular.',
|
||||
}}
|
||||
noItemsMessage={'No permisisons created for this team so far.'}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
permission: true,
|
||||
},
|
||||
title: 'Permission',
|
||||
fieldType: FormFieldSchemaType.Dropdown,
|
||||
required: true,
|
||||
placeholder: 'Permission',
|
||||
dropdownOptions: PermissionUtil.projectPermissionsAsDropdownOptions()
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: true,
|
||||
},
|
||||
title: 'Labels (Optional)',
|
||||
description: 'Labels on which this permissions will apply on. This is optional and an advanced feature.',
|
||||
fieldType: FormFieldSchemaType.MultiSelectDropdown,
|
||||
dropdownModal: {
|
||||
type: Label,
|
||||
labelField: "name",
|
||||
valueField: "_id"
|
||||
},
|
||||
required: false,
|
||||
placeholder:
|
||||
'Labels',
|
||||
}
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
showFilterButton={true}
|
||||
currentPageRoute={props.pageRoute}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
permission: true,
|
||||
},
|
||||
title: 'Permission',
|
||||
type: TableColumnType.Text,
|
||||
isFilterable: true,
|
||||
getColumnElement: (item: JSONObject): ReactElement => {
|
||||
return (
|
||||
<p>{PermissionHelper.getTitle(item["permission"] as Permission)}</p>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: true,
|
||||
},
|
||||
title: 'Labels',
|
||||
type: TableColumnType.Text,
|
||||
getColumnElement: (item: JSONObject): ReactElement => {
|
||||
const returnElements = [];
|
||||
if (item["labels"] && Array.isArray(item["labels"])) {
|
||||
let counter = 0;
|
||||
for (const label of item["labels"])
|
||||
if (label && (label as JSONObject)['color'] && (label as JSONObject)['name']) {
|
||||
returnElements.push(
|
||||
<Pill
|
||||
key={counter}
|
||||
color={(label as JSONObject)['color'] as Color}
|
||||
text={(label as JSONObject)['name'] as string}
|
||||
style={{
|
||||
marginRight: "5px"
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return <>{returnElements}</>;
|
||||
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
<ModelDelete
|
||||
type={Team}
|
||||
modelId={new ObjectID(Navigation.getLastParam()?.toString() || '')}
|
||||
onDeleteSuccess={() => {
|
||||
Navigation.navigate(RouteMap[PageMap.SETTINGS_TEAMS] as Route);
|
||||
}}
|
||||
/>
|
||||
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeamView;
|
||||
101
Dashboard/src/Pages/Settings/Teams.tsx
Normal file
101
Dashboard/src/Pages/Settings/Teams.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import Page from 'CommonUI/src/Components/Page/Page';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import PageMap from '../../Utils/PageMap';
|
||||
import RouteMap from '../../Utils/RouteMap';
|
||||
import PageComponentProps from '../PageComponentProps';
|
||||
import DashboardSideMenu from './SideMenu';
|
||||
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
|
||||
import Team from 'Common/Models/Team';
|
||||
import TableColumnType from 'CommonUI/src/Components/Table/Types/TableColumnType';
|
||||
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
|
||||
import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
|
||||
|
||||
const Teams: FunctionComponent<PageComponentProps> = (
|
||||
props: PageComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<Page
|
||||
title={'Project Settings'}
|
||||
breadcrumbLinks={[
|
||||
{
|
||||
title: 'Project',
|
||||
to: RouteMap[PageMap.HOME] as Route,
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
to: RouteMap[PageMap.SETTINGS] as Route,
|
||||
},
|
||||
{
|
||||
title: 'Teams',
|
||||
to: RouteMap[PageMap.SETTINGS_TEAMS] as Route,
|
||||
},
|
||||
]}
|
||||
sideMenu={<DashboardSideMenu />}
|
||||
>
|
||||
<ModelTable<Team>
|
||||
type={Team}
|
||||
model={new Team()}
|
||||
id="teams-table"
|
||||
isDeleteable={false}
|
||||
isEditable={true}
|
||||
isCreateable={true}
|
||||
isViewable={true}
|
||||
cardProps={{
|
||||
icon: IconProp.User,
|
||||
title: 'Teams',
|
||||
description:
|
||||
'Here is a list of all the teams in this project.',
|
||||
}}
|
||||
noItemsMessage={'No teams created for this project so far.'}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: 'Name',
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: 'Team Name',
|
||||
validation: {
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
description: true,
|
||||
},
|
||||
title: 'Description',
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: true,
|
||||
placeholder:
|
||||
'Team Description',
|
||||
}
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
showFilterButton={true}
|
||||
currentPageRoute={props.pageRoute}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: 'Name',
|
||||
type: TableColumnType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
description: true,
|
||||
},
|
||||
title: 'Description',
|
||||
type: TableColumnType.Text,
|
||||
isFilterable: true,
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default Teams;
|
||||
@@ -20,6 +20,11 @@ enum PageMap {
|
||||
SETTINGS_APIKEY_VIEW = 'SETTINGS_APIKEY_VIEW',
|
||||
SETTINGS_CUSTOM_SMTP = 'SETTINGS_CUSTOM_SMTP',
|
||||
|
||||
|
||||
// Team
|
||||
SETTINGS_TEAMS = 'SETTINGS_TEAMS',
|
||||
SETTINGS_TEAM_VIEW = 'SETTINGS_TEAM_VIEW',
|
||||
|
||||
// Labels.
|
||||
SETTINGS_LABELS = 'SETTINGS_LABELS',
|
||||
|
||||
|
||||
@@ -53,6 +53,14 @@ const RouteMap: Dictionary<Route> = {
|
||||
`/dashboard/${RouteParams.ProjectID}/settings/custom-smtp`
|
||||
),
|
||||
|
||||
[PageMap.SETTINGS_TEAMS]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/settings/teams`
|
||||
),
|
||||
|
||||
[PageMap.SETTINGS_TEAM_VIEW]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/settings/teams/${RouteParams.ModelID}`
|
||||
),
|
||||
|
||||
// labels.
|
||||
[PageMap.SETTINGS_LABELS]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/settings/labels`
|
||||
|
||||
Reference in New Issue
Block a user