Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MDS-5356] Actions Dropdown #2605

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions services/core-api/app/api/mines/response_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def format(self, value):
'document_manager_guid': fields.String,
'document_name': fields.String,
'upload_date': fields.String,
'update_timestamp': fields.String,
'create_user': fields.String,
'is_archived': fields.Boolean,
'archived_date': fields.String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const ArchiveDocumentModal: FC<ArchiveDocumentModalProps> = (props: ArchiveDocum
documents={props.documents}
view="minimal"
uploadDateIndex="upload_date"
excludedColumnKeys={["archive", "remove", "category"]}
excludedColumnKeys={["actions", "category"]}
/>

<div className="ant-modal-footer">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from "react";
import DocumentTable from "@/components/common/DocumentTable";
import { Typography } from "antd";
import { IMineDocument } from "@mds/common";
import { DeleteOutlined } from "@ant-design/icons";
import { Feature, isFeatureEnabled } from "@mds/common";
import { MineDocument } from "@common/models/documents/document";

interface ArchivedDocumentsSectionProps {
documents: IMineDocument;
documents: MineDocument[];
documentColumns: any;
titleLevel?: 1 | 2 | 3 | 4 | 5;
}
Expand All @@ -16,12 +16,6 @@ const ArchivedDocumentsSection = (props: ArchivedDocumentsSectionProps) => {
return <></>;
}

const docs = props.documents.map((d) => {
d.name = d.document_name;

return d;
});

return (
<div id="archived-documents">
<Typography.Title level={props.titleLevel || 4}>
Expand All @@ -33,7 +27,7 @@ const ArchivedDocumentsSection = (props: ArchivedDocumentsSectionProps) => {
</Typography.Paragraph>
<DocumentTable
documentColumns={props.documentColumns}
documents={docs}
documents={props.documents}
excludedColumnKeys={["archive", "remove"]}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { FC } from "react";
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is copied from ArchiveDocumentModal, with some word changes.


import DocumentTable from "@/components/common/DocumentTable";
import { Alert, Button, Form, Typography } from "antd";
import { MineDocument } from "@common/models/documents/document";

interface DeleteDocumentModalProps {
documents: MineDocument[];
handleSubmit(documents: MineDocument[]): Promise<void>;
closeModal(): void;
}

const DeleteDocumentModal: FC<DeleteDocumentModalProps> = (props: DeleteDocumentModalProps) => {
return (
<Form
layout="vertical"
onFinish={() => props.handleSubmit(props.documents).then(props.closeModal)}
>
<Typography.Paragraph>
<Alert
message="Deleted files are not reviewed as part of the submission"
showIcon
type="warning"
description="By deleting this file, you are deleting all of its previous versions. This action cannot be undone."
/>
</Typography.Paragraph>

<Typography.Paragraph strong>
You&apos;re about to delete the following file{props.documents?.length > 1 ? "s" : ""}:
</Typography.Paragraph>

<DocumentTable
documents={props.documents}
view="minimal"
uploadDateIndex="upload_date"
excludedColumnKeys={["actions", "category"]}
/>

<div className="ant-modal-footer">
<Button className="full-mobile" onClick={props.closeModal}>
Cancel
</Button>
<Button className="full-mobile" type="primary" htmlType="submit">
Delete
</Button>
</div>
</Form>
);
};

export default DeleteDocumentModal;
153 changes: 153 additions & 0 deletions services/core-web/common/models/documents/document.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { USER_ROLES } from "@mds/common";

export enum FileOperations {
View = "Open in document viewer",
Download = "Download file",
Replace = "Replace file",
Archive = "Archive file",
Delete = "Delete",
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made sense to me to put this here, but would make sense to put it in the documents directory instead


/*
A base class for Mine Documents

There is an issue with antd where sorting a table that has children (ie matchChildColumnsToParent)
will transform the records into type <any> (with versions still maintaining their type) so properties accessed
by the table should be *set* to the specific object, cannot expect to be able to consistently call its methods

include "user_roles" property in the json used in the constructor to set allowed actions based on the user
*/
export class MineDocument {
public mine_document_guid: string;

public mine_guid: string;

public document_manager_guid: string;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eslint added all these spaces on me and I was not feeling like changing eslint rules, even though it irritates me to look at it.


public document_name: string;

public create_user: string;

public update_user: string;

public upload_date: string;

public update_timestamp: string;

public is_archived: boolean;

public archived_by: string;

public archived_date: string;

public is_latest_version: boolean;

public category?: string;

// generated
public key: string;

public file_type: string;

public number_prev_versions: number;

public versions: MineDocument[]; // all versions, including latest

public allowed_actions: FileOperations[];

constructor(jsonObject: any) {
this.mine_document_guid = jsonObject.mine_document_guid;
this.mine_guid = jsonObject.mine_guid;
this.document_manager_guid = jsonObject.document_manager_guid;
this.document_name = jsonObject.document_name;
this.create_user = jsonObject.create_user;
this.update_user = jsonObject.update_user;
this.upload_date = jsonObject.upload_date;
this.update_timestamp = jsonObject.update_timestamp;
this.category = jsonObject.category;
this.is_archived = jsonObject.is_archived ?? false;
this.archived_by = jsonObject.archived_by;
this.archived_date = jsonObject.archived_date;
this.is_latest_version = jsonObject.is_latest_version ?? true;
this.setCalculatedProperties(jsonObject);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected makeChild(params: any, _constructorArgs: any) {
return new MineDocument(params);
}

protected setCalculatedProperties(jsonObject: any) {
this.key = this.is_latest_version
? this.mine_document_guid
: jsonObject.document_manager_version_guid;
this.file_type = this.getFileType();

const versions = jsonObject.versions ?? [];
if (this.is_latest_version && versions.length) {
this.number_prev_versions = versions.length - 1;
this.versions = versions
.slice(1)
.map((version) => this.makeChild({ ...version, is_latest_version: false }, jsonObject));
} else {
this.number_prev_versions = 0;
this.versions = [];
}
this.setAllowedActions(jsonObject.user_roles);
}

public getFileType() {
const index = this.document_name.lastIndexOf(".");
return index === -1 ? null : this.document_name.substring(index).toLocaleLowerCase();
}

public setAllowedActions(userRoles: string[] = []) {
this.allowed_actions = this.getAllowedActions(userRoles).filter(Boolean);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://bcmines.atlassian.net/browse/MDS-5356?focusedCommentId=22159 <-- some explanation of why things are set up this way (with functions setting a value instead of returning it)

}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public getAllowedActions(_userRoles: string[] = []) {
const canModify = this.is_latest_version && !this.is_archived;
return [
this.file_type === ".pdf" && FileOperations.View,
FileOperations.Download,
canModify && FileOperations.Replace,
canModify && FileOperations.Archive,
canModify && FileOperations.Delete,
];
}
}

export class MajorMineApplicationDocument extends MineDocument {
public major_mine_application_document_type_code: string;

public versions: MajorMineApplicationDocument[];

constructor(jsonObject: any) {
super(jsonObject);
this.major_mine_application_document_type_code =
jsonObject.major_mine_application_document_type_code;
}

protected makeChild(params: any, constructorArgs: any) {
return new MajorMineApplicationDocument({
...params,
major_mine_application_document_type_code:
constructorArgs.major_mine_application_document_type_code,
});
}

public getAllowedActions(userRoles: string[] = []) {
const allowedActions = super.getAllowedActions();

const canModifyRoles = [
USER_ROLES.role_edit_major_mine_applications,
USER_ROLES.role_minespace_proponent,
];
const canModify = userRoles.some((role) => canModifyRoles.includes(role));

return allowedActions.filter(
(action) => canModify || [FileOperations.View, FileOperations.Download].includes(action)
);
}
}
47 changes: 22 additions & 25 deletions services/core-web/src/components/common/CoreTable.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import React from "react";
import { Table, TableProps, Tooltip } from "antd";
import { ColumnType } from "antd/es/table";
import { ColumnsType } from "antd/es/table";
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to ColumnsType was just because of my struggles with type (see above) and attempt to fix it by getting rid of differences between what we had and antd demos. It didn't seem to affect anything.

import { MinusSquareFilled, PlusSquareFilled } from "@ant-design/icons";
import { ExpandableConfig } from "antd/lib/table/interface";

interface CoreTableExpandConfig<T> extends ExpandableConfig<T> {
getDataSource: (record: T) => any[];
getDataSource?: (record: T) => any[];
rowKey?: string | ((record: any) => string);
recordDescription?: string;
subTableColumns?: ColumnType<any>[];
subTableColumns?: ColumnsType<any>;
matchChildColumnsToParent?: boolean;
// and any other props from expandable https://4x.ant.design/components/table/#expandable
}

interface CoreTableProps<T> extends TableProps<T> {
columns: ColumnType<T>[];
columns: ColumnsType<T>;
dataSource: T[];
condition?: boolean;
rowKey?: string | ((record: T) => string | number); // defaults to "key"
Expand Down Expand Up @@ -94,29 +94,26 @@ const CoreTable = <T,>(props: CoreTableProps<T>) => {
);
};

const expansionProps = expandProps
? {
rowExpandable:
expandProps.rowExpandable ?? ((record) => expandProps.getDataSource(record).length > 0),
expandIcon: renderTableExpandIcon,
expandRowByClick: true,
expandedRowRender: expandProps.expandedRowRender ?? renderExpandedRow,
...expandProps,
}
: null;

const matchChildColumnsToParentProps = expandProps
? {
expandIcon: renderTableExpandIcon,
indentSize: 0,
}
: null;
const getExpansionProps = () => {
if (expandProps) {
return expandProps.matchChildColumnsToParent
? { expandIcon: renderTableExpandIcon, indentSize: 0, ...expandProps }
: {
rowExpandable:
expandProps.rowExpandable ??
((record) => expandProps.getDataSource(record).length > 0),
expandIcon: renderTableExpandIcon,
expandRowByClick: true,
expandedRowRender: expandProps.expandedRowRender ?? renderExpandedRow,
...expandProps,
};
}
return { showExpandColumn: false };
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ran into an issue where if the dataSource had children, it would show the expand icon even if I didn't want it to. Forced it to be deliberate.

};

return condition ? (
<Table
expandable={
expandProps?.matchChildColumnsToParent ? matchChildColumnsToParentProps : expansionProps
}
expandable={getExpansionProps()}
pagination={pagination}
locale={{ emptyText }}
className={`${tableClass} core-table`}
Expand All @@ -126,8 +123,8 @@ const CoreTable = <T,>(props: CoreTableProps<T>) => {
? "table-row-align-middle no-sub-table-expandable-rows fade-in"
: "fade-in"
}
{...tableProps}
columns={columns}
{...tableProps}
></Table>
) : (
<Table
Expand Down
Loading
Loading