Skip to content

Commit

Permalink
fix(build): streamlined FileStore upload flow (#597)
Browse files Browse the repository at this point in the history
* rebuilding file upload

* do not push mqtt

* fix close

* error handle

* add safe filename

* update success message
  • Loading branch information
mwfarb authored Nov 15, 2023
1 parent 6008c76 commit 4470c68
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 61 deletions.
10 changes: 3 additions & 7 deletions build/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,12 @@ <h1>Scene Editor</h1>
title="Refresh Scene List from User Account"
><i class="icon-refresh"></i
></a>
<br />
<a class="btn btn-small" href="#" id="importscene" title="Import from JSON file">
{ } <i class="icon-upload"></i>
</a>
<a class="btn btn-small" href="#" id="exportscene" title="Export to JSON file" download>
{ } <i class="icon-download"></i>
</a>
<a class="btn btn-small" href="#" id="uploadmodel" title="Upload Model to Filestore and Scene">
<img src="assets/3dobj-icon.png" width="14" />
</a>
<a class="btn btn-small" href="#" id="uploadimage" title="Upload Image to Filestore and Scene">
<i class="icon-picture"></i>
</a>
</form>
<div id="scenelinks">
<p>
Expand Down Expand Up @@ -194,6 +187,9 @@ <h3>Add/Edit Object</h3>
<button class="btn btn-small" type="button" id="genid" title="Generate a Random object_id">
<i class="icon-tag"></i>Gen object_id
</button>
<button class="btn btn-small" type="button" id="uploadfilestore" title="Filestore Upload and Gen Url">
<i class="icon-file"></i>Filestore Upload/Gen Url
</button>
<button class="btn btn-primary btn-small addobj" type="button" title="Add or Update Object">
<i class="icon-plus"></i> Add/Update Object
</button>
Expand Down
106 changes: 52 additions & 54 deletions build/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ window.addEventListener('onauth', async (e) => {
const deleteSceneButton = document.getElementById('deletescene');
const importSceneButton = document.getElementById('importscene');
const exportSceneButton = document.getElementById('exportscene');
const uploadImageButton = document.getElementById('uploadimage');
const uploadModelButton = document.getElementById('uploadmodel');
const uploadFilestoreButton = document.getElementById('uploadfilestore');
const setValueButton = document.getElementById('setvalue');
const selectSchema = document.getElementById('objtype');
const genidButton = document.getElementById('genid');
Expand All @@ -67,6 +66,13 @@ window.addEventListener('onauth', async (e) => {
let saved_namespace;
let saved_scene;

const uploadFileTypes = {
image: 'image/*',
'gltf-model': '*.glb',
'pcd-model': '*.pcd',
'threejs-scene': '*.json',
};

// copy to clipboard buttons
new ClipboardJS(document.querySelector('#copy_json'), {
text() {
Expand Down Expand Up @@ -156,6 +162,8 @@ window.addEventListener('onauth', async (e) => {
validate.value = 'valid';
}
insertEulerRotationEditor(json);
uploadFilestoreButton.style.display =
uploadFileTypes[json.data.object_type] === undefined ? 'none' : 'inline';
});

const typeSel = document.getElementsByName('root[type]')[0];
Expand Down Expand Up @@ -383,49 +391,42 @@ window.addEventListener('onauth', async (e) => {
return cookieValue;
}

async function uploadSceneFileStore(model) {
const strType = model ? 'GLB' : 'Image';
const objType = model ? 'gltf-model' : 'image';
const accept = model ? '*/*' : 'image/*'; // 'model/gltf-binary, *.glb' not working on XRBrowser
const htmlopt = model
? `<div style="float: left;">
async function uploadSceneFileStore(objtype) {
const accept = uploadFileTypes[objtype];
const htmlopt =
objtype === 'gltf-model'
? `<div style="float: left;">
<input type="checkbox" id="cbhideinar" name="cbhideinar" >
<label for="cbhideinar" style="display: inline-block;">Room-scale digital-twin model? Hide in AR.</label>
</div>`
: '';
: '';
const htmlval = `${htmlopt}`;

await Swal.fire({
title: `Upload ${strType} to Filestore and Scene`,
title: `Upload ${objtype} to Filestore`,
html: htmlval,
input: 'file',
inputAttributes: {
accept: `${accept}`,
'aria-label': `Select ${strType}`,
'aria-label': `Select ${objtype}`,
},
confirmButtonText: 'Upload',
focusConfirm: false,
showCancelButton: true,
cancelButtonText: 'Cancel',
showLoaderOnConfirm: true,
preConfirm: (resultFileOpen) => {
if (model && !/\.glb$/i.test(resultFileOpen.name)) {
Swal.showValidationMessage(`${strType} file type only!`);
return;
}
const fn = resultFileOpen.name.substr(0, resultFileOpen.name.lastIndexOf('.'));
const safeFilename = fn.replace(/(\W+)/gi, '-');
const uploadObjectId = `${objType}-${safeFilename}`;
let hideinar = false;

const reader = new FileReader();
reader.onload = async (evt) => {
const file = document.querySelector('.swal2-file');
if (!file) {
Swal.showValidationMessage(`${strType} file not loaded!`);
Swal.showValidationMessage(`${objtype} file not loaded!`);
return;
}
if (model) {
if (objtype === 'gltf-model') {
// allow model checkboxes hide in ar/vr (recommendations)
hideinar = Swal.getPopup().querySelector('#cbhideinar').checked;
}
Expand All @@ -435,7 +436,7 @@ window.addEventListener('onauth', async (e) => {
try {
await ARENAUserAccount.requestStoreLogin();
} catch (err) {
Swal.showValidationMessage(`Error requesting filestore login: ${err.statusText}`);
Swal.showValidationMessage(`Error requesting file store login: ${err.statusText}`);
return;
}
token = getCookie('auth');
Expand All @@ -445,11 +446,10 @@ window.addEventListener('onauth', async (e) => {
const userFilePath = `scenes/${sceneinput.value}/${resultFileOpen.name}`;
const storeResPath = `${storeResPrefix}${userFilePath}`;
const storeExtPath = `store/users/${username}/${userFilePath}`;
// TODO: allow object id edit
Swal.fire({
title: 'Wait for Upload',
imageUrl: evt.target.result,
imageAlt: `The uploaded ${strType}`,
imageAlt: `The uploaded ${objtype}`,
showConfirmButton: false,
showCancelButton: true,
cancelButtonText: 'Cancel',
Expand All @@ -468,42 +468,42 @@ window.addEventListener('onauth', async (e) => {
if (!responsePostFS.ok) {
throw new Error(responsePostFS.statusText);
}
const uploadObj = {
object_id: uploadObjectId,
type: 'object',
data: {
object_type: objType,
url: `${storeExtPath}`,
},
};
let obj;
try {
obj = JSON.parse(output.value);
} catch (err) {
console.error(err);
throw err;
}
if (obj.object_id === '') {
obj.object_id = safeFilename;
}
obj.data.url = `${storeExtPath}`;
if (hideinar) {
uploadObj.data['hide-on-enter-ar'] = true;
obj.data['hide-on-enter-ar'] = true;
}
if (!model) {
if (objtype === 'image') {
// try to preserve image aspect ratio in mesh, user can scale to resize
const img = Swal.getPopup().querySelector('.swal2-image');
if (img.width > img.height) {
const ratio = img.width / img.height;
uploadObj.data.width = ratio;
uploadObj.data.height = 1.0;
obj.data.width = ratio;
obj.data.height = 1.0;
} else {
const ratio = img.height / img.width;
uploadObj.data.width = 1.0;
uploadObj.data.height = ratio;
obj.data.width = 1.0;
obj.data.height = ratio;
}
}
const scene = `${namespaceinput.value}/${sceneinput.value}`;
PersistObjects.performActionArgObjList('create', scene, [uploadObj], false);
setTimeout(async () => {
await PersistObjects.populateObjectList(
`${namespaceinput.value}/${sceneinput.value}`,
objFilter.value,
objTypeFilter,
uploadObjectId
);

$(`label[innerHTML='${uploadObjectId} (${objType})']`).focus();
}, 500);
// push updated data to forms
output.value = JSON.stringify(obj, null, 2);
jsoneditor.setValue(obj);
Alert.fire({
icon: 'info',
title: 'File Store Upload Success',
html: `File ${resultFileOpen.name} uploaded to File Store. Don't forget to publish your JSON with the new File Store URL.`,
timer: 10000,
});
})
.catch((error) => {
Swal.showValidationMessage(`Request failed: ${error}`);
Expand All @@ -517,7 +517,7 @@ window.addEventListener('onauth', async (e) => {
},
}).then((resultDidOpen) => {
if (resultDidOpen.dismiss === Swal.DismissReason.timer) {
console.error(`Upload ${strType} file dialog timed out!`);
console.error(`Upload ${objtype} file dialog timed out!`);
}
});
};
Expand All @@ -526,11 +526,9 @@ window.addEventListener('onauth', async (e) => {
});
}
// switch image/model
uploadModelButton.addEventListener('click', async () => {
await uploadSceneFileStore(true);
});
uploadImageButton.addEventListener('click', async () => {
await uploadSceneFileStore(false);
uploadFilestoreButton.addEventListener('click', async () => {
const obj = JSON.parse(output.value);
await uploadSceneFileStore(obj.data.object_type);
});

openAddSceneButton.addEventListener('click', async () => {
Expand Down

0 comments on commit 4470c68

Please sign in to comment.