mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
fix project invitation list
This commit is contained in:
0
Common/Utils/ObjectUtil.ts
Normal file
0
Common/Utils/ObjectUtil.ts
Normal file
1
CommonUI/package-lock.json
generated
1
CommonUI/package-lock.json
generated
@@ -20,6 +20,7 @@
|
||||
"Common": "file:../Common",
|
||||
"formik": "^2.2.9",
|
||||
"history": "^5.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"Model": "file:../Model",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.1.0",
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
"@types/react-toggle": "^4.0.3",
|
||||
"bootstrap": "^5.2.0-beta1",
|
||||
"Common": "file:../Common",
|
||||
"Model": "file:../Model",
|
||||
"formik": "^2.2.9",
|
||||
"history": "^5.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"Model": "file:../Model",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.1.0",
|
||||
"react-color": "^2.19.3",
|
||||
|
||||
@@ -6,6 +6,7 @@ import OneUptimeDate from 'Common/Types/Date';
|
||||
import FieldType from '../Types/FieldType';
|
||||
import HiddenText from '../HiddenText/HiddenText';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import _ from 'lodash';
|
||||
|
||||
export interface ComponentProps {
|
||||
item: JSONObject;
|
||||
@@ -28,8 +29,8 @@ const Detail: Function = (
|
||||
|
||||
let data: string | ReactElement = '';
|
||||
|
||||
if ((props.item as any)[fieldKey]) {
|
||||
data = (props.item as any)[fieldKey]?.toString() || '';
|
||||
if (_.get(props.item, fieldKey)) {
|
||||
data = _.get(props.item, fieldKey, '')?.toString() || '';
|
||||
}
|
||||
|
||||
if (field.fieldType === FieldType.Date) {
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface ActionButton {
|
||||
|
||||
export default interface Columns<TEntity> {
|
||||
field?: SelectEntityField<TEntity>;
|
||||
selectedProperty?: string;
|
||||
title: string;
|
||||
disableSort?: boolean;
|
||||
type: FieldType;
|
||||
|
||||
@@ -65,7 +65,9 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
query?: Query<TBaseModel>;
|
||||
onBeforeCreate?: ((item: TBaseModel) => Promise<TBaseModel>) | undefined;
|
||||
createVerb?: string;
|
||||
showAsList?: boolean | undefined
|
||||
showAsList?: boolean | undefined;
|
||||
singularName?: string | undefined;
|
||||
pluralName?: string | undefined;
|
||||
}
|
||||
|
||||
enum ModalType {
|
||||
@@ -234,7 +236,7 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
|
||||
if (props.isCreateable && hasPermissionToCreate) {
|
||||
headerbuttons.push({
|
||||
title: `${props.createVerb || 'Create'} ${model.singularName}`,
|
||||
title: `${props.createVerb || 'Create'} ${props.singularName || model.singularName}`,
|
||||
buttonStyle: ButtonStyleType.OUTLINE,
|
||||
onClick: () => {
|
||||
setModalType(ModalType.Create);
|
||||
@@ -372,7 +374,7 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
columns.push({
|
||||
...column,
|
||||
disableSort: column.disableSort || shouldDisableSort(key),
|
||||
key,
|
||||
key: column.selectedProperty ? key+"."+column.selectedProperty: key,
|
||||
});
|
||||
|
||||
if (key) {
|
||||
@@ -511,8 +513,8 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
setSortBy(sortBy);
|
||||
setSortOrder(sortOrder);
|
||||
}}
|
||||
singularLabel={model.singularName || 'Item'}
|
||||
pluralLabel={model.pluralName || 'Items'}
|
||||
singularLabel={props.singularName || model.singularName || 'Item'}
|
||||
pluralLabel={props.pluralName || model.pluralName || 'Items'}
|
||||
error={error}
|
||||
currentPageNumber={currentPageNumber}
|
||||
isLoading={isLoading}
|
||||
@@ -603,8 +605,8 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
setSortBy(sortBy);
|
||||
setSortOrder(sortOrder);
|
||||
}}
|
||||
singularLabel={model.singularName || 'Item'}
|
||||
pluralLabel={model.pluralName || 'Items'}
|
||||
singularLabel={props.singularName || model.singularName || 'Item'}
|
||||
pluralLabel={props.pluralName || model.pluralName || 'Items'}
|
||||
error={error}
|
||||
currentPageNumber={currentPageNumber}
|
||||
isLoading={isLoading}
|
||||
@@ -696,9 +698,9 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
title={
|
||||
modalType === ModalType.Create
|
||||
? `${props.createVerb || 'Create'} New ${
|
||||
model.singularName
|
||||
props.singularName || model.singularName
|
||||
}`
|
||||
: `Edit ${model.singularName}`
|
||||
: `Edit ${props.singularName || model.singularName}`
|
||||
}
|
||||
onClose={() => {
|
||||
setShowModal(false);
|
||||
@@ -706,7 +708,7 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
submitButtonText={
|
||||
modalType === ModalType.Create
|
||||
? `${props.createVerb || 'Create'} ${
|
||||
model.singularName
|
||||
props.singularName || model.singularName
|
||||
}`
|
||||
: `Save Changes`
|
||||
}
|
||||
@@ -739,9 +741,9 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
|
||||
{showDeleteConfirmModal && (
|
||||
<ConfirmModal
|
||||
title={`Delete ${model.singularName}`}
|
||||
title={`Delete ${props.singularName || model.singularName}`}
|
||||
description={`Are you sure you want to delete this ${(
|
||||
model.singularName || 'item'
|
||||
props.singularName || model.singularName || 'item'
|
||||
)?.toLowerCase()}?`}
|
||||
onClose={() => {
|
||||
setShowDeleteConfirmModal(false);
|
||||
|
||||
@@ -54,15 +54,10 @@ const List: FunctionComponent<ComponentProps> = (
|
||||
|
||||
if (props.data.length === 0) {
|
||||
return (
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colSpan={props.columns.length}>
|
||||
<ErrorMessage error={props.noItemsMessage
|
||||
? props.noItemsMessage
|
||||
: `No ${props.singularLabel.toLocaleLowerCase()}`} onRefreshClick={props.onRefreshClick} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<ErrorMessage error={props.noItemsMessage
|
||||
? props.noItemsMessage
|
||||
: `No ${props.singularLabel.toLocaleLowerCase()}`} onRefreshClick={props.onRefreshClick} />
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const ListBody: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<div id={props.id}>
|
||||
<div id={props.id} >
|
||||
{props.data &&
|
||||
props.data.map((item: JSONObject, i: number) => {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import React, { FunctionComponent, ReactElement, useEffect, useState } from 'react';
|
||||
import Button, { ButtonSize } from '../Button/Button';
|
||||
import Detail from '../Detail/Detail';
|
||||
import Field from '../Detail/Field';
|
||||
import ActionButtonSchema, { ActionType } from './Types/ActionButtonSchema';
|
||||
@@ -9,8 +10,8 @@ export interface ComponentProps {
|
||||
item: JSONObject;
|
||||
columns: Columns;
|
||||
onActionEvent?:
|
||||
| ((actionType: ActionType, item: JSONObject) => void)
|
||||
| undefined;
|
||||
| ((actionType: ActionType, item: JSONObject) => void)
|
||||
| undefined;
|
||||
actionButtons?: Array<ActionButtonSchema> | undefined;
|
||||
}
|
||||
|
||||
@@ -18,15 +19,15 @@ const ListRow: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
|
||||
|
||||
|
||||
// convert column to field
|
||||
const [fields, setFields] = useState<Array<Field>>([]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const detailFields:Array<Field> = [];
|
||||
const detailFields: Array<Field> = [];
|
||||
for (const column of props.columns) {
|
||||
|
||||
|
||||
if (!column.key) {
|
||||
// if its an action column, ignore.
|
||||
continue;
|
||||
@@ -44,8 +45,52 @@ const ListRow: FunctionComponent<ComponentProps> = (
|
||||
}, [props.columns])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="padding-15 list-item">
|
||||
<Detail item={props.item} fields={fields} />
|
||||
|
||||
<div>
|
||||
{props.actionButtons?.map(
|
||||
(
|
||||
button: ActionButtonSchema,
|
||||
i: number
|
||||
) => {
|
||||
return (
|
||||
<span
|
||||
style={
|
||||
i > 0
|
||||
? {
|
||||
marginLeft:
|
||||
'10px',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
key={i}
|
||||
>
|
||||
<Button
|
||||
buttonSize={
|
||||
ButtonSize.Small
|
||||
}
|
||||
title={button.title}
|
||||
icon={button.icon}
|
||||
buttonStyle={
|
||||
button.buttonStyleType
|
||||
}
|
||||
onClick={() => {
|
||||
if (
|
||||
props.onActionEvent
|
||||
) {
|
||||
props.onActionEvent(
|
||||
button.actionType,
|
||||
props.item
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import ActionButtonSchema, { ActionType } from './Types/ActionButtonSchema';
|
||||
import Column from './Types/Column';
|
||||
import Columns from './Types/Columns';
|
||||
import FieldType from '../Types/FieldType';
|
||||
import _ from 'lodash';
|
||||
|
||||
export interface ComponentProps {
|
||||
item: JSONObject;
|
||||
@@ -58,9 +59,7 @@ const TableRow: FunctionComponent<ComponentProps> = (
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
(props.item[
|
||||
column.key
|
||||
]?.toString() as string)
|
||||
_.get(props.item, column.key, '')?.toString() || ''
|
||||
)
|
||||
) : (
|
||||
<></>
|
||||
|
||||
@@ -14,7 +14,8 @@ enum FieldType {
|
||||
Port,
|
||||
HiddenText,
|
||||
Actions,
|
||||
Boolean
|
||||
Boolean,
|
||||
Entity
|
||||
}
|
||||
|
||||
export default FieldType;
|
||||
|
||||
@@ -210,4 +210,26 @@
|
||||
|
||||
.vertical-center{
|
||||
margin-top: 20%;
|
||||
}
|
||||
|
||||
.padding-15{
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Lists
|
||||
|
||||
.list-item{
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
border-color: $color-very-light-grey;
|
||||
border-top: 0px;
|
||||
border-right: 0px;
|
||||
border-left: 0px;
|
||||
}
|
||||
|
||||
.modal-dialog{
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import TeamMember from 'Model/Models/TeamMember';
|
||||
import User from 'CommonUI/src/Utils/User';
|
||||
|
||||
import FullPageModal from "CommonUI/src/Components/FullPageModal/FullPageModal";
|
||||
import TeamPermission from 'Model/Models/TeamPermission';
|
||||
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
|
||||
import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
|
||||
import FieldType from 'CommonUI/src/Components/Types/FieldType';
|
||||
@@ -78,9 +77,9 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
{showProjectInvitationModal && <FullPageModal onClose={() => {
|
||||
setShowProjectInvitationModal(false);
|
||||
}}>
|
||||
<ModelTable<TeamPermission>
|
||||
modelType={TeamPermission}
|
||||
id="team-permission-table"
|
||||
<ModelTable<TeamMember>
|
||||
modelType={TeamMember}
|
||||
id="team-member-table"
|
||||
isDeleteable={true}
|
||||
query={{
|
||||
userId: User.getUserId(),
|
||||
@@ -91,29 +90,32 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
isViewable={false}
|
||||
cardProps={{
|
||||
icon: IconProp.User,
|
||||
title: 'Project Invitations',
|
||||
title: 'Pending Invitations',
|
||||
description:
|
||||
'Here is a list of projects and teams you have been invited to.',
|
||||
}}
|
||||
noItemsMessage={
|
||||
'No proejct or team invitations for you so far.'
|
||||
'No project or team invitations for you so far.'
|
||||
}
|
||||
showAsList={true}
|
||||
singularName="Project Invitation"
|
||||
pluralName="Project Invitations"
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
projectId: true,
|
||||
project: true,
|
||||
},
|
||||
title: 'Project',
|
||||
title: 'Project Invited to',
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
selectedProperty: "name"
|
||||
},
|
||||
{
|
||||
field: {
|
||||
teamId: true,
|
||||
team: true,
|
||||
},
|
||||
title: 'Team',
|
||||
title: 'Team Invited to',
|
||||
type: FieldType.Text,
|
||||
selectedProperty: "name"
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
11
package-lock.json
generated
11
package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "3.0.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.182",
|
||||
"eslint-plugin-progress": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -617,6 +618,11 @@
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz",
|
||||
@@ -5020,6 +5026,11 @@
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"main": "index.ts",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.182",
|
||||
"eslint-plugin-progress": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Reference in New Issue
Block a user