Skip to content

Commit 8bfae69

Browse files
authored
DPO3DPKRT-772/internal publishing to EDAN (#592)
(fix) layout for ingest Subject search (fix) model inspection details hidden by default (fix) Docker failed pull alpine when building. added 'extra_hosts' to config (fix) Publishing with lcoal proxy not working. invalid paths (fix) remove toast when uploading a file (fix) updated comments and logging (new) 'Internal' publishing button on Scene details page (new) 'Internal' publishing for Scenes (new) JSONParse helper routine, which wraps JSON.parse. returns undefined on failure.
1 parent 43f287c commit 8bfae69

File tree

11 files changed

+1092
-1352
lines changed

11 files changed

+1092
-1352
lines changed

client/src/pages/Ingestion/components/SubjectItem/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const useStyles = makeStyles(({ palette }) => ({
3131
content: {
3232
display: 'flex',
3333
flex: 1,
34-
// width: '52vw',
34+
marginRight: '1rem',
3535
flexDirection: 'column',
3636
padding: 20,
3737
paddingBottom: 0

client/src/pages/Repository/components/DetailsView/ObjectDetails.tsx

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ interface ObjectDetailsProps {
105105
originalFields?: GetSystemObjectDetailsResult;
106106
onRetiredUpdate?: (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => void;
107107
onLicenseUpdate?: (event) => void;
108+
onPublishUpdate?: (event) => void;
108109
path?: RepositoryPath[][] | null;
109110
updateData?: () => Promise<boolean>;
110111
idSystemObject: number;
@@ -129,6 +130,7 @@ function ObjectDetails(props: ObjectDetailsProps): React.ReactElement {
129130
originalFields,
130131
onRetiredUpdate,
131132
onLicenseUpdate,
133+
// onPublishUpdate,
132134
idSystemObject,
133135
license,
134136
licenseInheritance,
@@ -195,6 +197,7 @@ function ObjectDetails(props: ObjectDetailsProps): React.ReactElement {
195197
const onPublish = async () => { onPublishWorker(ePublishedState.ePublished, 'Publish'); };
196198
const onAPIOnly = async () => { onPublishWorker(ePublishedState.eAPIOnly, 'Publish for API Only'); };
197199
const onUnpublish = async () => { onPublishWorker(ePublishedState.eNotPublished, 'Unpublish'); };
200+
const onInternal = async () => { onPublishWorker(ePublishedState.eInternal, 'Publish for Internal Only'); };
198201
const onSyncToEdan = async () => { onPublishWorker(ePublishedState.ePublished, 'Sync to Edan'); };
199202

200203
const onPublishWorker = async (eState: number, action: string) => {
@@ -233,8 +236,15 @@ function ObjectDetails(props: ObjectDetailsProps): React.ReactElement {
233236
<Typography className={classes.value}>{publishedState}</Typography>
234237
&nbsp;<LoadingButton onClick={onPublish} className={classes.loadingBtn} loading={loading} disabled={!publishable}>Publish</LoadingButton>
235238
&nbsp;<LoadingButton onClick={onAPIOnly} className={classes.loadingBtn} loading={loading} disabled={!publishable}>API Only</LoadingButton>
239+
&nbsp;<LoadingButton onClick={onInternal} className={classes.loadingBtn} loading={loading} disabled={!publishable}>Internal</LoadingButton>
236240
&nbsp;{(publishedEnum !== ePublishedState.eNotPublished) && (<LoadingButton onClick={onUnpublish} className={classes.loadingBtn} loading={loading}>Unpublish</LoadingButton>)}
237241
&nbsp;<Tooltip arrow title={ <ToolTip text={scenePublishNotes} />}><HelpOutline fontSize='small' style={{ alignSelf: 'center', cursor: 'pointer' }} /></Tooltip>
242+
{/* <Select name='PublishedState' className={classes.select} style={{ width: '16rem' }} onChange={onPublishUpdate} value={publishedState}>
243+
<MenuItem value={0}>Unpublished</MenuItem>
244+
<MenuItem value={1}>Unlisted (API)</MenuItem>
245+
<MenuItem value={2}>Public Site</MenuItem>
246+
<MenuItem value={3}>Internal</MenuItem>
247+
</Select> */}
238248
</Box>
239249
}
240250
/>
@@ -250,23 +260,6 @@ function ObjectDetails(props: ObjectDetailsProps): React.ReactElement {
250260
}
251261
/>
252262
)}
253-
{!hideRetired && (
254-
<Detail
255-
label='Retired'
256-
name='retired'
257-
valueComponent={
258-
<CheckboxNoPadding
259-
id='retired'
260-
name='retired'
261-
disabled={disabled}
262-
checked={withDefaultValueBoolean(retired, false)}
263-
onChange={onRetiredUpdate}
264-
{...getUpdatedCheckboxProps(isRetiredUpdated)}
265-
color='primary'
266-
/>
267-
}
268-
/>
269-
)}
270263
{licenseSource ? (
271264
<Detail
272265
label='License'
@@ -290,7 +283,7 @@ function ObjectDetails(props: ObjectDetailsProps): React.ReactElement {
290283
label='License'
291284
valueComponent={
292285
<Box className={classes.assignedLicense}>
293-
<Select name='License' className={classes.select} onChange={onLicenseUpdate} value={license}>
286+
<Select name='License' className={classes.select} style={{ width: '16rem' }} onChange={onLicenseUpdate} value={license}>
294287
<MenuItem value={0}>None</MenuItem>
295288
{licenseList.map(license => (
296289
<MenuItem value={license.idLicense} key={license.idLicense}>
@@ -305,6 +298,23 @@ function ObjectDetails(props: ObjectDetailsProps): React.ReactElement {
305298
}
306299
/>
307300
)}
301+
{!hideRetired && (
302+
<Detail
303+
label='Retired'
304+
name='retired'
305+
valueComponent={
306+
<CheckboxNoPadding
307+
id='retired'
308+
name='retired'
309+
disabled={disabled}
310+
checked={withDefaultValueBoolean(retired, false)}
311+
onChange={onRetiredUpdate}
312+
{...getUpdatedCheckboxProps(isRetiredUpdated)}
313+
color='primary'
314+
/>
315+
}
316+
/>
317+
)}
308318
</Box>
309319
);
310320
}

client/src/pages/Repository/components/DetailsView/index.tsx

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
UpdateIdentifier,
3535
UpdateObjectDetailsDataInput
3636
} from '../../../../types/graphql';
37-
import { eSystemObjectType, eVocabularySetID } from '@dpo-packrat/common';
37+
import { ePublishedState, eSystemObjectType, eVocabularySetID, PublishedStateEnumToString } from '@dpo-packrat/common';
3838
import { withDefaultValueBoolean, withDefaultValueNumber } from '../../../../utils/shared';
3939
import ObjectSelectModal from '../../../Ingestion/components/Metadata/Model/ObjectSelectModal';
4040
import { updateDetailsTabData, useObjectDetails, deleteIdentifier, getDetailsTabDataForObject } from '../../hooks/useDetailsView';
@@ -114,6 +114,7 @@ function DetailsView(): React.ReactElement {
114114
const [updatedIdentifiers, setUpdatedIdentifiers] = useState(false);
115115
const [updatedMetadata, setUpdatedMetadata] = useState(false);
116116
const [uploadReferences, setUploadReferences] = useState<UploadReferences | null>(null);
117+
117118
const getEntries = useVocabularyStore(state => state.getEntries);
118119
const [
119120
stateIdentifiers,
@@ -175,11 +176,10 @@ function DetailsView(): React.ReactElement {
175176
const verifyGenerateDownloads = async (): Promise<boolean> => {
176177
// check whether we can actually generate downloads
177178
// TODO: check QC checkbox status, (ideally) if a generate downloads is already running, ...
178-
console.log('Verifying Generate Downloads...');
179+
console.log('[PACKRAT] Verifying Generate Downloads...');
179180

180181
// make a call to our generate downloads endpoint with the current scene id
181182
const response: RequestResponse = await API.generateDownloads(idSystemObject, true);
182-
console.log(response);
183183
if(response.success === false) {
184184
console.log(`[Packrat - ERROR] cannot verify if generate downloads is available. (${response.message})`);
185185
setCanGenerateDownloads(false);
@@ -191,7 +191,7 @@ function DetailsView(): React.ReactElement {
191191
const canRun: boolean = (response.data.isJobRunning === false) && (response.data.isSceneValid === true);
192192

193193
// we have success so enable it
194-
console.log(`[PACKRAT - DEBUG] can generate downloads: ${canRun}`);
194+
// console.log(`[PACKRAT - DEBUG] can generate downloads: ${canRun}`);
195195
setCanGenerateDownloads(canRun);
196196
return canRun;
197197
};
@@ -348,6 +348,26 @@ function DetailsView(): React.ReactElement {
348348
setUpdatedData(updatedDataFields);
349349
};
350350

351+
const onPublishUpdate = ({ target }): void => {
352+
console.log(`[PACKRAT] ${JSON.stringify(target)}`);
353+
console.log(`[PACKRAT] value: ${target.value} | enum: ${PublishedStateEnumToString(target.value)} | name: ${target.name} | ${ePublishedState[parseInt(target.value)]}:${typeof(ePublishedState[parseInt(target.value)])} | data: ${publishedState}`);
354+
355+
// const pState: ePublishedState = ePublishedState[parseInt(target.value)];
356+
// if(pState.toString() != publishedState) {
357+
// console.warn('published states diff. updating...');
358+
// } else {
359+
// console.info('published states are identical. skipping update');
360+
// return;
361+
// }
362+
// switch(pState) {
363+
// case ePublishedState.eNotPublished: {
364+
// console.info('[PACKRAT] un-publishing...');
365+
// }
366+
367+
// case
368+
// }
369+
};
370+
351371
const onUpdateDetail = (objectType: number, data: UpdateDataFields): void => {
352372
// console.log('onUpdateDetail', objectType, data);
353373
const updatedDataFields: UpdateObjectDetailsDataInput = {
@@ -566,7 +586,7 @@ function DetailsView(): React.ReactElement {
566586
const generateDownloads = async (): Promise<boolean> => {
567587
// fire off download generation for the scene. (UI element, ln. 593)
568588
// TODO: move into 'Assets' tab (currently lacking context/details on if we're a scene)
569-
console.log('Generating Downloads...');
589+
console.log('[PACKRAT] Generating Downloads...');
570590
if(isGeneratingDownloads === true || canGenerateDownloads === false) {
571591
console.error('[Packrat] cannot generate downloads. not sure how you got here...');
572592
return false;
@@ -599,9 +619,6 @@ function DetailsView(): React.ReactElement {
599619
return false;
600620
}
601621

602-
console.log(params);
603-
console.log(data);
604-
605622
// wait for a period of time before resetting our buttons
606623
// setting a minimal time improves UX and shows spinning logo
607624
const diffTime = Math.max(1,2000-(Date.now()-startTime));
@@ -648,6 +665,7 @@ function DetailsView(): React.ReactElement {
648665
objectType={objectType}
649666
onRetiredUpdate={onRetiredUpdate}
650667
onLicenseUpdate={onLicenseUpdate}
668+
onPublishUpdate={onPublishUpdate}
651669
originalFields={data.getSystemObjectDetails}
652670
license={withDefaultValueNumber(details.idLicense, 0)}
653671
idSystemObject={idSystemObject}

common/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ export enum ePublishedState {
351351
eNotPublished = 0, // 'Not Published', default
352352
eAPIOnly = 1, // 'API Only',
353353
ePublished = 2, // 'Published'
354+
eInternal = 3, // 'Internal' use only. similar to eNotPublished for EDAN flags
354355
}
355356

356357
export function LicenseEnumToString(eState: eLicense): string {
@@ -367,6 +368,7 @@ export function PublishedStateEnumToString(eState: ePublishedState): string {
367368
switch (eState) {
368369
case ePublishedState.eAPIOnly: return 'API Only';
369370
case ePublishedState.ePublished: return 'Published';
371+
case ePublishedState.eInternal: return 'Internal';
370372
default:
371373
case ePublishedState.eNotPublished: return 'Not Published';
372374
}

conf/docker/docker-compose.dev.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ services:
4141
target: server
4242
ports:
4343
- $PACKRAT_SERVER_PORT:4000
44+
extra_hosts:
45+
- "host.docker.internal:host-gateway"
4446
environment:
4547
- NODE_ENV=$NODE_ENV
4648
- REACT_APP_PACKRAT_SERVER_ENDPOINT=$REACT_APP_PACKRAT_SERVER_ENDPOINT

server/collections/impl/EdanCollection.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,13 @@ export class EdanCollection implements COL.ICollection {
172172

173173
async publish(idSystemObject: number, ePublishState: number): Promise<boolean> {
174174

175-
LOG.info(`EdanCollection.publish (idSystemObject: ${idSystemObject}`,LOG.LS.eDEBUG);
175+
LOG.info(`EdanCollection.publish (idSystemObject: ${idSystemObject} | state: ${COMMON.ePublishedState[ePublishState]})`,LOG.LS.eDEBUG);
176176

177177
switch (ePublishState) {
178178
case COMMON.ePublishedState.eNotPublished:
179179
case COMMON.ePublishedState.eAPIOnly:
180180
case COMMON.ePublishedState.ePublished:
181+
case COMMON.ePublishedState.eInternal:
181182
break;
182183
default:
183184
LOG.error(`EdanCollection.publish called with invalid ePublishState ${ePublishState} for idSystemObject ${idSystemObject}`, LOG.LS.eCOLL);
@@ -216,14 +217,35 @@ export class EdanCollection implements COL.ICollection {
216217
}
217218

218219
async createEdan3DPackage(path: string, sceneFile?: string | undefined): Promise<COL.EdanRecord | null> {
220+
console.log(`createEdan3DPackage input: ${path}`);
221+
// const body: any = sceneFile ? { resource: path.replace(/\.zip|-zip$/, ''), document: sceneFile } : { resource: path.replace(/\.zip|-zip$/, '') };
219222
const body: any = sceneFile ? { resource: path, document: sceneFile } : { resource: path };
220-
return this.upsertResource(body, 'createEdan3DPackage');
223+
LOG.info(`body:\n${H.Helpers.JSONStringify(body)}`,LOG.LS.eDEBUG);
224+
225+
const edanRecord: COL.EdanRecord | null = await this.upsertResource(body, 'createEdan3DPackage');
226+
if(!edanRecord)
227+
return null;
228+
229+
// returned URL may include a zip extension so we clean that out
230+
// only seems to happen when running locally with a Proxy
231+
const packageUrl: string = edanRecord.url.replace(/\.zip|-zip$/, '');
232+
if(edanRecord.url!==packageUrl)
233+
LOG.info(`EdanCollection.createEdan3DPackage returned url needed correction. (${edanRecord.url} -> ${packageUrl})`,LOG.LS.eCOLL);
234+
235+
return { ...edanRecord, url: packageUrl };
221236
}
222237

223238
async updateEdan3DPackage(url: string, title: string | undefined, sceneContent: COL.Edan3DPackageContent,
224239
status: number, publicSearch: boolean): Promise<COL.EdanRecord | null> {
240+
241+
// make sure the url doesn't include file extensions
242+
// only seems to happen when running locally with a Proxy
243+
const packageUrl: string = url.replace(/\.zip|-zip$/, '');
244+
if(url!==packageUrl)
245+
LOG.info(`EdanCollection.updateEdan3DPackage incoming url needed correction. (${url} -> ${packageUrl})`,LOG.LS.eCOLL);
246+
225247
const body: any = {
226-
url,
248+
url: packageUrl,
227249
title,
228250
status,
229251
publicSearch,
@@ -236,10 +258,10 @@ export class EdanCollection implements COL.ICollection {
236258

237259
/** c.f. http://dev.3d.api.si.edu/apidocs/#api-admin-upsertContent */
238260
private async upsertContent(body: any, caller: string): Promise<COL.EdanRecord | null> {
239-
// LOG.info(`EdanCollection.upsertContent: ${JSON.stringify(body)}`, LOG.LS.eCOLL);
240-
LOG.info('EdanCollection.upsertContent', LOG.LS.eCOLL);
261+
LOG.info(`EdanCollection.upsertContent: ${JSON.stringify(body)}`, LOG.LS.eCOLL);
241262
const reqResult: HttpRequestResult = await this.sendRequest(eAPIType.eEDAN3dApi, eHTTPMethod.ePost, 'api/v1.0/admin/upsertContent', '', JSON.stringify(body), 'application/json');
242-
LOG.info(`EdanCollection.upsertContent:\n${JSON.stringify(body)}\n${reqResult.output}`, LOG.LS.eCOLL);
263+
LOG.info(`EdanCollection.upsertContent result:\n${H.Helpers.JSONStringify(H.Helpers.JSONParse(reqResult.output))}`, LOG.LS.eCOLL);
264+
243265
if (!reqResult.success) {
244266
LOG.error(`EdanCollection.${caller} failed with ${reqResult.statusText}: ${reqResult.output}`, LOG.LS.eCOLL);
245267
return null;
@@ -255,9 +277,10 @@ export class EdanCollection implements COL.ICollection {
255277

256278
/** c.f. http://dev.3d.api.si.edu/apidocs/#api-admin-upsertResource */
257279
private async upsertResource(body: any, caller: string): Promise<COL.EdanRecord | null> {
258-
LOG.info(`EdanCollection.upsertResource: ${JSON.stringify(body)}`, LOG.LS.eCOLL);
280+
// LOG.info(`EdanCollection.upsertResource: ${JSON.stringify(body)}`, LOG.LS.eCOLL);
259281
const reqResult: HttpRequestResult = await this.sendRequest(eAPIType.eEDAN3dApi, eHTTPMethod.ePost, 'api/v1.0/admin/upsertResource', '', JSON.stringify(body), 'application/json');
260-
// LOG.info(`EdanCollection.upsertResource:\n${JSON.stringify(body)}:\n${reqResult.output}`, LOG.LS.eCOLL);
282+
LOG.info(`EdanCollection.upsertResource result:\n${H.Helpers.JSONStringify(H.Helpers.JSONParse(reqResult.output))}`, LOG.LS.eDEBUG);
283+
261284
if (!reqResult.success) {
262285
LOG.error(`EdanCollection.${caller} failed with ${reqResult.statusText}: ${reqResult.output}`, LOG.LS.eCOLL);
263286
return null;

0 commit comments

Comments
 (0)