Skip to content

Commit 36acf13

Browse files
jjgriff93hizni
andauthored
Airlock UI: add title to airlock request (#2731)
* added title textbox * modified airlock request models to add title * added requestTitle to UI * modified airlock_request api model * additions for airlock import title task Co-authored-by: James Griffin <jjgriff93@users.noreply.github.com> * added request title to db * added request title to sample airlock req * Added title field to table * Fix warnings * Amended tests * Update version & changelog Co-authored-by: Hizni Salih <hizni.salih@gmail.com> Co-authored-by: James Griffin <jjgriff93@users.noreply.github.com> Co-authored-by: Hizni Salih <4255268+hizni@users.noreply.github.com> Co-authored-by: jjgriff93 <jamesgr@microsoft.com>
1 parent 680d35a commit 36acf13

14 files changed

Lines changed: 142 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
FEATURES:
88
* Added filtering and sorting to Airlock UI ([#2511](https://github.com/microsoft/AzureTRE/issues/2511))
9+
* Added title field to Airlock requests ([#2731](https://github.com/microsoft/AzureTRE/pull/2731))
910

1011
ENHANCEMENTS:
1112

api_app/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.4.52"
1+
__version__ = "0.4.53"

api_app/db/repositories/airlock_requests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def create_airlock_request_item(self, airlock_request_input: AirlockRequestInCre
9292
airlock_request = AirlockRequest(
9393
id=full_airlock_request_id,
9494
workspaceId=workspace_id,
95+
requestTitle=airlock_request_input.requestTitle,
9596
businessJustification=airlock_request_input.businessJustification,
9697
requestType=airlock_request_input.requestType,
9798
creationTime=datetime.utcnow().timestamp(),

api_app/models/domain/airlock_request.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class AirlockRequest(AzureTREModel):
7878
workspaceId: str = Field("", title="Workspace ID", description="Service target Workspace id")
7979
requestType: AirlockRequestType = Field("", title="Airlock request type")
8080
files: List[AirlockFile] = Field([], title="Files of the request")
81+
requestTitle: str = Field("Airlock Request", title="Brief title for the request")
8182
businessJustification: str = Field("Business Justifications", title="Explanation that will be provided to the request reviewer")
8283
status = AirlockRequestStatus.Draft
8384
creationTime: float = Field(None, title="Creation time of the request")

api_app/models/schemas/airlock_request.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def get_sample_airlock_request(workspace_id: str, airlock_request_id: str) -> di
2020
"status": "draft",
2121
"requestType": "import",
2222
"files": [],
23+
"requestTitle": "a request title",
2324
"businessJustification": "some business justification",
2425
"creationTime": datetime.utcnow().timestamp(),
2526
"reviews": [
@@ -72,13 +73,15 @@ class Config:
7273

7374
class AirlockRequestInCreate(BaseModel):
7475
requestType: AirlockRequestType = Field("", title="Airlock request type", description="Specifies if this is an import or an export request")
76+
requestTitle: str = Field("Airlock Request", title="Brief title for the request")
7577
businessJustification: str = Field("Business Justifications", title="Explanation that will be provided to the request reviewer")
7678
properties: dict = Field({}, title="Airlock request parameters", description="Values for the parameters required by the Airlock request specification")
7779

7880
class Config:
7981
schema_extra = {
8082
"example": {
8183
"requestType": "import",
84+
"requestTitle": "a request title",
8285
"businessJustification": "some business justification"
8386
}
8487
}

api_app/tests_ma/test_api/test_routes/test_airlock.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def sample_airlock_request_object(status=AirlockRequestStatus.Draft, airlock_req
3434
airlock_request = AirlockRequest(
3535
id=airlock_request_id,
3636
workspaceId=workspace_id,
37+
requestTitle="test title",
3738
businessJustification="test business justification",
3839
requestType="import",
3940
status=status
@@ -45,6 +46,7 @@ def sample_airlock_request_object_with_review(status=AirlockRequestStatus.Draft,
4546
airlock_request = AirlockRequest(
4647
id=airlock_request_id,
4748
workspaceId=workspace_id,
49+
requestTitle="test title",
4850
businessJustification="test business justification",
4951
requestType="import",
5052
status=status,

ui/app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"@azure/msal-browser": "^2.24.0",
77
"@azure/msal-react": "^1.4.0",
88
"@fluentui/react": "^8.68.2",
9+
"@fluentui/react-file-type-icons": "^8.7.9",
910
"@reduxjs/toolkit": "^1.8.6",
1011
"@rjsf/core": "^4.2.0",
1112
"@rjsf/fluent-ui": "^4.2.0",

ui/app/src/App.scss

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,17 @@ ul.tre-notifications-steps-list li {
106106
}
107107
}
108108

109+
.tre-table {
110+
.ms-Persona-primaryText {
111+
font-size: 12px;
112+
color: rgb(108, 108, 108);
113+
}
114+
115+
.ms-DetailsRow-cell {
116+
align-self: baseline;
117+
}
118+
}
119+
109120
.tre-hide-chevron i[data-icon-name=ChevronDown] {
110121
display: none;
111122
}
@@ -158,12 +169,6 @@ ul.tre-notifications-steps-list li {
158169
background-color: #fff;
159170
}
160171

161-
.tre-table-rows-align-centre {
162-
.ms-DetailsRow-cell {
163-
align-self: baseline;
164-
}
165-
}
166-
167172
.ms-Pivot {
168173
margin-bottom: 10px;
169174
}

ui/app/src/App.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { CreateUpdateResource } from './components/shared/create-update-resource
1717
import { CreateUpdateResourceContext } from './contexts/CreateUpdateResourceContext';
1818
import { CreateFormResource, ResourceType } from './models/resourceType';
1919
import { Footer } from './components/shared/Footer';
20+
import { initializeFileTypeIcons } from '@fluentui/react-file-type-icons';
2021

2122
export const App: React.FunctionComponent = () => {
2223
const [appRoles, setAppRoles] = useState([] as Array<string>);
@@ -38,6 +39,9 @@ export const App: React.FunctionComponent = () => {
3839
setAppRolesOnLoad();
3940
}, [apiCall]);
4041

42+
// initiliase filetype icons
43+
useEffect(() => initializeFileTypeIcons(), []);
44+
4145
return (
4246
<>
4347
<Routes>

ui/app/src/components/shared/airlock/Airlock.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useCallback, useContext, useEffect, useState } from 'react';
2-
import { ColumnActionsMode, CommandBar, CommandBarButton, ContextualMenu, DirectionalHint, getTheme, IColumn, ICommandBarItemProps, IContextualMenuItem, IContextualMenuProps, Label, Persona, PersonaSize, SelectionMode, ShimmeredDetailsList, Stack } from '@fluentui/react';
2+
import { ColumnActionsMode, CommandBar, CommandBarButton, ContextualMenu, DirectionalHint, getTheme, IColumn, ICommandBarItemProps, Icon, IContextualMenuItem, IContextualMenuProps, Persona, PersonaSize, SelectionMode, ShimmeredDetailsList, Stack } from '@fluentui/react';
33
import { HttpMethod, useAuthApiCall } from '../../../hooks/useAuthApiCall';
44
import { ApiEndpoint } from '../../../models/apiEndpoints';
55
import { WorkspaceContext } from '../../../contexts/WorkspaceContext';
@@ -13,6 +13,7 @@ import { ExceptionLayout } from '../ExceptionLayout';
1313
import { AirlockNewRequest } from './AirlockNewRequest';
1414
import { WorkspaceRoleName } from '../../../models/roleNames';
1515
import { useAccount, useMsal } from '@azure/msal-react';
16+
import { getFileTypeIconProps } from '@fluentui/react-file-type-icons';
1617

1718
export const Airlock: React.FunctionComponent = () => {
1819
const [airlockRequests, setAirlockRequests] = useState([] as AirlockRequest[]);
@@ -27,7 +28,7 @@ export const Airlock: React.FunctionComponent = () => {
2728
const apiCall = useAuthApiCall();
2829
const theme = getTheme();
2930
const navigate = useNavigate();
30-
const { instance, accounts } = useMsal();
31+
const { accounts } = useMsal();
3132
const account = useAccount(accounts[0] || {});
3233

3334
// Get the airlock request data from API
@@ -151,15 +152,31 @@ export const Airlock: React.FunctionComponent = () => {
151152

152153
const columns: IColumn[] = [
153154
{
154-
key: 'avatar',
155-
name: '',
155+
key: 'fileIcon',
156+
name: 'fileIcon',
156157
minWidth: 16,
157158
maxWidth: 16,
158159
isIconOnly: true,
159160
onRender: (request: AirlockRequest) => {
160-
return <Persona size={ PersonaSize.size24 } text={ request.user?.name } />
161+
if (request.status === AirlockRequestStatus.Draft) {
162+
return <Icon iconName="FolderOpen" style={{verticalAlign:'bottom', fontSize: 14}} />
163+
} else if (request.files?.length > 0 && request.files[0].name) {
164+
const fileType = request.files[0].name.split('.').pop();
165+
return <Icon {...getFileTypeIconProps({ extension: fileType })} style={{verticalAlign:'bottom'}} />
166+
} else {
167+
return <Icon iconName="Page" style={{verticalAlign:'bottom', fontSize: 14}} />
168+
}
161169
}
162170
},
171+
{
172+
key: 'title',
173+
name: 'Title',
174+
ariaLabel: 'Title of the airlock request',
175+
minWidth: 150,
176+
maxWidth: 300,
177+
isResizable: true,
178+
fieldName: 'requestTitle'
179+
},
163180
{
164181
key: 'creator_user_id',
165182
name: 'Initiator',
@@ -168,7 +185,7 @@ export const Airlock: React.FunctionComponent = () => {
168185
maxWidth: 200,
169186
isResizable: true,
170187
fieldName: 'initiator',
171-
onRender: (request: AirlockRequest) => request.user?.name,
188+
onRender: (request: AirlockRequest) => <Persona size={ PersonaSize.size24 } text={ request.user?.name } />,
172189
isFiltered: filters.has('creator_user_id')
173190
},
174191
{
@@ -310,7 +327,7 @@ export const Airlock: React.FunctionComponent = () => {
310327
selectionMode={SelectionMode.none}
311328
getKey={(item) => item?.id}
312329
onItemInvoked={(item) => navigate(item.id)}
313-
className="tre-table-rows-align-centre"
330+
className="tre-table"
314331
enableShimmer={loadingState === LoadingState.Loading}
315332
/>
316333
{

0 commit comments

Comments
 (0)