@evoke-platform/ui-components 1.5.0-testing.2 → 1.5.0-testing.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ import { ApiServices, ObjectInstance } from '@evoke-platform/context';
2
+ import React from 'react';
3
+ export type DocumentViewerCellProps = {
4
+ instance: ObjectInstance;
5
+ propertyId: string;
6
+ apiServices: ApiServices;
7
+ setSnackbarError: (error: {
8
+ showAlert: boolean;
9
+ message?: string;
10
+ isError?: boolean;
11
+ }) => void;
12
+ };
13
+ export declare const DocumentViewerCell: (props: DocumentViewerCellProps) => React.JSX.Element;
@@ -0,0 +1,113 @@
1
+ import React, { useState } from 'react';
2
+ import { AutorenewRounded, FileWithExtension, LaunchRounded } from '../../../../../icons';
3
+ import { Button, Menu, MenuItem, Typography } from '../../../../core';
4
+ import { Grid } from '../../../../layout';
5
+ import { getPrefixedUrl } from '../../utils';
6
+ export const DocumentViewerCell = (props) => {
7
+ const { instance, propertyId, apiServices, setSnackbarError } = props;
8
+ const [anchorEl, setAnchorEl] = useState(null);
9
+ const [isLoading, setIsLoading] = useState(false);
10
+ const downloadDocument = async (doc, instance) => {
11
+ setIsLoading(true);
12
+ try {
13
+ const documentResponse = await apiServices.get(getPrefixedUrl(`/objects/${instance.objectId}/instances/${instance.id}/documents/${doc.id}/content`), { responseType: 'blob' });
14
+ const contentType = documentResponse.type;
15
+ const blob = new Blob([documentResponse], { type: contentType });
16
+ const url = URL.createObjectURL(blob);
17
+ // Let the browser handle whether to open the document to view in a new tab or download it.
18
+ window.open(url, '_blank');
19
+ setIsLoading(false);
20
+ URL.revokeObjectURL(url);
21
+ }
22
+ catch (error) {
23
+ const status = error.status;
24
+ let message = 'An error occurred while downloading the document.';
25
+ if (status === 403) {
26
+ message = 'You do not have permission to download this document.';
27
+ }
28
+ else if (status === 404) {
29
+ message = 'Document not found.';
30
+ }
31
+ setIsLoading(false);
32
+ setSnackbarError({
33
+ showAlert: true,
34
+ message,
35
+ isError: true,
36
+ });
37
+ }
38
+ };
39
+ return (React.createElement(React.Fragment, null, instance[propertyId]?.length ? (React.createElement(React.Fragment, null,
40
+ React.createElement(Button, { sx: {
41
+ display: 'flex',
42
+ alignItems: 'center',
43
+ justifyContent: 'flex-start',
44
+ padding: '6px 10px',
45
+ }, color: 'inherit', onClick: async (event) => {
46
+ event.stopPropagation();
47
+ const documents = instance[propertyId];
48
+ if (documents.length === 1) {
49
+ await downloadDocument(documents[0], instance);
50
+ }
51
+ else {
52
+ setAnchorEl(event.currentTarget);
53
+ }
54
+ }, variant: "text", "aria-haspopup": "menu", "aria-controls": `document-menu-${instance.id}-${propertyId}`, "aria-expanded": anchorEl ? 'true' : 'false' },
55
+ isLoading ? (React.createElement(AutorenewRounded, { sx: {
56
+ color: '#637381',
57
+ width: '20px',
58
+ height: '20px',
59
+ } })) : (React.createElement(LaunchRounded, { sx: {
60
+ color: '#637381',
61
+ width: '20px',
62
+ height: '20px',
63
+ } })),
64
+ React.createElement(Typography, { sx: {
65
+ marginLeft: '8px',
66
+ fontWeight: 400,
67
+ fontSize: '14px',
68
+ } }, isLoading ? 'Preparing document...' : 'View Document')),
69
+ React.createElement(Menu, { id: `document-menu-${instance.id}-${propertyId}`, anchorEl: anchorEl, open: Boolean(anchorEl), onClose: () => {
70
+ setAnchorEl(null);
71
+ }, sx: {
72
+ '& .MuiPaper-root': {
73
+ borderRadius: '12px',
74
+ boxShadow: 'rgba(145, 158, 171, 0.2)',
75
+ },
76
+ }, variant: 'menu', slotProps: {
77
+ paper: {
78
+ style: {
79
+ maxHeight: 200,
80
+ maxWidth: 300,
81
+ minWidth: 300,
82
+ },
83
+ },
84
+ } }, instance[propertyId].map((document) => (React.createElement(MenuItem, { key: document.id, onClick: async (e) => {
85
+ setAnchorEl(null);
86
+ await downloadDocument(document, instance);
87
+ }, "aria-label": document.name },
88
+ React.createElement(Grid, { item: true, sx: {
89
+ display: 'flex',
90
+ justifyContent: 'center',
91
+ padding: '7px',
92
+ } },
93
+ React.createElement(FileWithExtension, { fontFamily: "Arial", fileExtension: document.name?.split('.')?.pop() ?? '', sx: {
94
+ height: '1rem',
95
+ width: '1rem',
96
+ } })),
97
+ React.createElement(Grid, { item: true, xs: 12, sx: {
98
+ width: '100%',
99
+ overflow: 'hidden',
100
+ textOverflow: 'ellipsis',
101
+ } },
102
+ React.createElement(Typography, { noWrap: true, sx: {
103
+ fontSize: '14px',
104
+ fontWeight: 700,
105
+ color: '#212B36',
106
+ lineHeight: '15px',
107
+ width: '100%',
108
+ } }, document.name)))))))) : (React.createElement(Typography, { sx: {
109
+ fontStyle: 'italic',
110
+ marginLeft: '12px',
111
+ fontSize: '14px',
112
+ } }, "No documents"))));
113
+ };
@@ -9,6 +9,7 @@ import { Button, IconButton, Skeleton, Snackbar, Table, TableBody, TableCell, Ta
9
9
  import { Box } from '../../../../layout';
10
10
  import { getPrefixedUrl, normalizeDateTime } from '../../utils';
11
11
  import { ActionDialog } from './ActionDialog';
12
+ import { DocumentViewerCell } from './DocumentViewerCell';
12
13
  const styles = {
13
14
  addButton: {
14
15
  backgroundColor: 'rgba(0, 117, 167, 0.08)',
@@ -292,6 +293,7 @@ const RepeatableField = (props) => {
292
293
  `An error occurred while ${actionType === 'delete' ? ' deleting' : ' updating'} an instance`,
293
294
  isError: true,
294
295
  });
296
+ setSubmitting && setSubmitting(false);
295
297
  }
296
298
  }
297
299
  return { isSuccessful, error };
@@ -335,9 +337,9 @@ const RepeatableField = (props) => {
335
337
  };
336
338
  const getValue = (relatedInstance, propertyId, propertyType) => {
337
339
  const value = get(relatedInstance, propertyId);
338
- // If the property is not date-like or document then just return the
340
+ // If the property is not date-like then just return the
339
341
  // value found at the given path.
340
- if (!['date', 'date-time', 'time', 'document'].includes(propertyType)) {
342
+ if (!['date', 'date-time', 'time'].includes(propertyType)) {
341
343
  return value;
342
344
  }
343
345
  // If the date-like value is empty then there is no need to format.
@@ -357,9 +359,6 @@ const RepeatableField = (props) => {
357
359
  if (propertyType === 'time') {
358
360
  return DateTime.fromISO(stringValue).toLocaleString(DateTime.TIME_SIMPLE);
359
361
  }
360
- if (property.type === 'document') {
361
- return Array.isArray(value) ? value.map((v) => v.name).join(', ') : value;
362
- }
363
362
  };
364
363
  const columns = retrieveViewLayout();
365
364
  return loading ? (React.createElement(React.Fragment, null,
@@ -377,23 +376,22 @@ const RepeatableField = (props) => {
377
376
  React.createElement(TableHead, { sx: { backgroundColor: '#F4F6F8' } },
378
377
  React.createElement(TableRow, null,
379
378
  columns?.map((prop) => React.createElement(TableCell, { sx: styles.tableCell }, prop.name)),
380
- React.createElement(TableCell, { sx: { ...styles.tableCell, width: '80px' } }))),
379
+ canUpdateProperty && React.createElement(TableCell, { sx: { ...styles.tableCell, width: '80px' } }))),
381
380
  React.createElement(TableBody, null, relatedInstances?.map((relatedInstance, index) => (React.createElement(TableRow, { key: relatedInstance.id },
382
381
  columns?.map((prop) => {
383
- return (React.createElement(TableCell, { sx: { color: '#212B36', fontSize: '16px' } },
384
- React.createElement(Typography, { key: prop.id, sx: prop.id === 'name'
385
- ? {
386
- '&:hover': {
387
- textDecoration: 'underline',
388
- cursor: 'pointer',
389
- },
390
- }
391
- : {}, onClick: canUpdateProperty && prop.id === 'name'
392
- ? () => editRow(relatedInstance.id)
393
- : undefined },
394
- getValue(relatedInstance, prop.id, prop.type),
395
- prop.type === 'user' &&
396
- users?.find((user) => get(relatedInstance, `${prop.id.split('.')[0]}.id`) === user.id)?.status === 'Inactive' && React.createElement("span", null, ' (Inactive)'))));
382
+ return (React.createElement(TableCell, { sx: { color: '#212B36', fontSize: '16px' } }, prop.type === 'document' ? (React.createElement(DocumentViewerCell, { instance: relatedInstance, propertyId: prop.id, apiServices: apiServices, setSnackbarError: setSnackbarError })) : (React.createElement(Typography, { key: prop.id, sx: prop.id === 'name'
383
+ ? {
384
+ '&:hover': {
385
+ textDecoration: 'underline',
386
+ cursor: 'pointer',
387
+ },
388
+ }
389
+ : {}, onClick: canUpdateProperty && prop.id === 'name'
390
+ ? () => editRow(relatedInstance.id)
391
+ : undefined },
392
+ getValue(relatedInstance, prop.id, prop.type),
393
+ prop.type === 'user' &&
394
+ users?.find((user) => get(relatedInstance, `${prop.id.split('.')[0]}.id`) === user.id)?.status === 'Inactive' && (React.createElement("span", null, ' (Inactive)'))))));
397
395
  }),
398
396
  canUpdateProperty && (React.createElement(TableCell, { sx: { width: '80px' } },
399
397
  React.createElement(IconButton, { "aria-label": `edit-collection-instance-${index}`, onClick: () => editRow(relatedInstance.id) },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evoke-platform/ui-components",
3
- "version": "1.5.0-testing.2",
3
+ "version": "1.5.0-testing.4",
4
4
  "description": "",
5
5
  "main": "dist/published/index.js",
6
6
  "module": "dist/published/index.js",