Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
23 changes: 23 additions & 0 deletions test/core/workflow/workflow-upload/action-binder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1920,5 +1920,28 @@ describe('Unity Upload Block', () => {
testDiv.dispatchEvent(clickEvent);
expect(testDiv).to.not.be.null;
});

it('should prevent double file picker while lock is active', async () => {
const actionBinder = new ActionBinder(unityEl, workflowCfg, unityEl, [unityEl]);
const container = document.createElement('div');
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.id = 'file-upload';
fileInput.className = 'file-upload';
container.appendChild(fileInput);

await actionBinder.initActionListeners(container, { '#file-upload': 'upload' });

let openCount = 0;
fileInput.addEventListener('click', (e) => {
if (e.defaultPrevented) return;
openCount += 1;
});

fileInput.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
fileInput.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));

expect(openCount).to.equal(1);
});
});
});
61 changes: 59 additions & 2 deletions test/unitylibs/scripts/transition-screen.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,66 @@ describe('TransitionScreen', () => {
});

describe('progressBarHandler', () => {
it('should call updateProgressBar and recurse', () => {
beforeEach(() => {
splashScreenEl.innerHTML = `
<div class="spectrum-ProgressBar" value="0" aria-valuenow="0"></div>
<div class="spectrum-ProgressBar-percentage">0%</div>
<div class="spectrum-ProgressBar-fill" style="width: 0%"></div>
<div id="progress-status"></div>
`;
});

it('should call updateProgressBar and recurse', () => {
const spy = sinon.spy(screen, 'updateProgressBar');
// Use fake timers to control setTimeout
const clock = sinon.useFakeTimers();
screen.progressBarHandler(splashScreenEl, 10, 10, true);
clock.tick(20);
expect(spy.called).to.be.true;
spy.restore();
clock.restore();
});

it('should ignore stale callbacks after clearProgressBarHandler', () => {
const clock = sinon.useFakeTimers();
screen.progressBarHandler(splashScreenEl, 10, 10, true);
clock.tick(15);
screen.clearProgressBarHandler();
const valueBeforeStaleTick = splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value');
clock.tick(100);
expect(splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value')).to.equal(valueBeforeStaleTick);
clock.restore();
});

it('should restart cleanly when initialized after cancel', () => {
const clock = sinon.useFakeTimers();
screen.progressBarHandler(splashScreenEl, 10, 10, true);
clock.tick(15);
screen.clearProgressBarHandler();
screen.progressBarHandler(splashScreenEl, 10, 10, true);
expect(splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value')).to.equal('0');
clock.tick(15);
expect(parseInt(splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value'), 10)).to.be.greaterThan(0);
clock.restore();
});
});

describe('clearProgressBarHandler', () => {
it('should stop pending progress updates when updateProgressBar reaches 100', () => {
splashScreenEl.innerHTML = `
<div class="spectrum-ProgressBar" value="0" aria-valuenow="0"></div>
<div class="spectrum-ProgressBar-percentage">0%</div>
<div class="spectrum-ProgressBar-fill" style="width: 0%"></div>
<div id="progress-status"></div>
`;
const clock = sinon.useFakeTimers();
screen.progressBarHandler(splashScreenEl, 10, 10, true);
clock.tick(15);
screen.updateProgressBar(splashScreenEl, 100);
expect(splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value')).to.equal('100');
clock.tick(100);
expect(splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value')).to.equal('100');
clock.restore();
});
});

describe('handleSplashProgressBar', () => {
Expand Down Expand Up @@ -97,10 +141,23 @@ describe('TransitionScreen', () => {
document.body.innerHTML = '<main></main><header></header><footer></footer>';
});
it('should hide splash and reset LOADER_LIMIT when displayOn is false', () => {
const clock = sinon.useFakeTimers();
splashScreenEl.innerHTML = `
<div class="spectrum-ProgressBar" value="0" aria-valuenow="0"></div>
<div class="spectrum-ProgressBar-percentage">0%</div>
<div class="spectrum-ProgressBar-fill" style="width: 0%"></div>
<div id="progress-status"></div>
`;
screen.progressBarHandler(splashScreenEl, 10, 10, true);
clock.tick(15);
screen.splashVisibilityController(false);
const valueAtCancel = splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value');
clock.tick(100);
expect(screen.LOADER_LIMIT).to.equal(95);
expect(splashScreenEl.classList.contains('show')).to.be.false;
expect(splashScreenEl.parentElement.classList.contains('hide-splash-overflow')).to.be.false;
expect(splashScreenEl.querySelector('.spectrum-ProgressBar').getAttribute('value')).to.equal(valueAtCancel);
clock.restore();
});
it('should show splash and set aria-hidden when displayOn is true', () => {
const stub = sinon.stub(screen, 'progressBarHandler');
Expand Down
42 changes: 36 additions & 6 deletions unitylibs/core/widgets/prompt-bar-upload/prompt-bar-upload.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ display: flex;
flex-direction: column;
align-items: flex-start;
gap: 17px;
border-right: 1px solid rgb(255 255 255 / 12%);
padding-right: 16px;
border-inline-end: 1px solid rgb(255 255 255 / 12%);
padding-inline-end: 16px;
box-sizing: border-box;
}

Expand Down Expand Up @@ -134,6 +134,31 @@ width: min(339px, 100%);
max-width: 100%;
}

.unity-prompt-bar-upload.unity-enabled .pbu-main .alert-holder .alert-toast .alert-content {
min-width: 0;
}

.unity-prompt-bar-upload.unity-enabled .pbu-main .alert-holder .alert-toast .alert-content .alert-icon {
flex: 1 1 0%;
justify-content: flex-start;
min-width: 0;
width: auto;
}

.unity-prompt-bar-upload.unity-enabled .pbu-main .alert-holder .alert-toast .alert-content .alert-text {
flex: 1 1 auto;
max-width: 100%;
min-width: 0;
width: 100%;
padding-inline: 0;
overflow-wrap: break-word;
text-align: center;
}

.unity-prompt-bar-upload.unity-enabled .pbu-main .alert-holder .alert-toast .alert-content .alert-text p {
padding-top: 0;
}

.unity-prompt-bar-upload.unity-enabled .pbu-right-section .unity-slf-prompt-label {
margin-bottom: 0px;
margin-inline: 0;
Expand Down Expand Up @@ -911,6 +936,11 @@ border: 2px solid;
background: rgb(64 105 253 / 14%);
}

.pbu-drop-zone-wrap .drop-zone:focus-visible {
outline: none;
border: 2px solid #4069FD;
}

.pbu-drop-zone-wrap .drop-zone.hidden {
display: none;
}
Expand Down Expand Up @@ -1138,11 +1168,11 @@ line-height: normal;
.unity-prompt-bar-upload.unity-enabled .pbu-left-section {
width: 100%;
max-width: 100%;
border-right: none;
padding-right: 0;
padding-bottom: 16px;
border-inline-end: none;
padding-inline-end: 0;
padding-block-end: 16px;
margin-bottom: 0;
border-bottom: 1px solid rgb(255 255 255 / 12%);
border-block-end: 1px solid rgb(255 255 255 / 12%);
}

.unity-prompt-bar-upload.unity-enabled .pbu-drop-zone-wrap {
Expand Down
14 changes: 13 additions & 1 deletion unitylibs/core/workflow/workflow-upload/action-binder.js
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,18 @@ export default class ActionBinder {
if (this.limits.allowedFileTypes?.length) {
el.setAttribute('accept', this.limits.allowedFileTypes.join(','));
}
el.addEventListener('click', () => {
let isFilePickerOpen = false;
el.addEventListener('click', (e) => {
if (isFilePickerOpen) {
e.preventDefault();
return;
}
isFilePickerOpen = true;
const releaseFilePickerLock = () => { isFilePickerOpen = false; };
window.addEventListener('focus', releaseFilePickerLock, { once: true });
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') releaseFilePickerLock();
}, { once: true });
this.canvasArea.forEach((element) => {
const errHolder = element.querySelector('.alert-holder');
if (errHolder?.classList.contains('show')) {
Expand All @@ -558,6 +569,7 @@ export default class ActionBinder {
});
});
el.addEventListener('change', async (e) => {
isFilePickerOpen = false;
const files = this.extractFiles(e);
this.filesData = { count: files.length, size: files[0].size, type: files[0].type };
this.logAnalyticsinSplunk('Click Drag and drop|UnityWidget', { assetId: this.assetId, fileMetaData: this.filesData });
Expand Down
23 changes: 20 additions & 3 deletions unitylibs/scripts/transition-screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ export default class TransitionScreen {
this.isDesktop = isDesktop;
this.headingElements = [];
this.progressText = '';
this.progressBarTimeoutId = null;
this.progressBarGeneration = 0;
}

clearProgressBarHandler() {
if (this.progressBarTimeoutId != null) {
clearTimeout(this.progressBarTimeoutId);
this.progressBarTimeoutId = null;
}
this.progressBarGeneration += 1;
}

setProgressTextFromDOM() {
Expand All @@ -44,6 +54,7 @@ export default class TransitionScreen {
? this.progressText.replace('%', `${p}%`)
: `${p}%`;
if (status && status.textContent !== newStatus) status.textContent = newStatus;
if (percentage >= 100) this.clearProgressBarHandler();
}

static createProgressBar() {
Expand All @@ -63,13 +74,18 @@ export default class TransitionScreen {
const newDelay = Math.min(delay + 100, 2000);
const newI = Math.max(i - 5, 5);
const progressBar = s.querySelector('.spectrum-ProgressBar');
if (initialize) this.updateProgressBar(s, 0);
else {
if (initialize) {
this.clearProgressBarHandler();
this.updateProgressBar(s, 0);
} else {
const currentValue = parseInt(progressBar?.getAttribute('value'), 10);
if (currentValue === 100 || currentValue >= this.LOADER_LIMIT) return;
}

setTimeout(() => {
const generation = this.progressBarGeneration;
this.progressBarTimeoutId = setTimeout(() => {
this.progressBarTimeoutId = null;
if (generation !== this.progressBarGeneration) return;
const v = initialize ? 0 : parseInt(progressBar.getAttribute('value'), 10);
if (v === 100) return;
this.updateProgressBar(s, v + newI);
Expand Down Expand Up @@ -213,6 +229,7 @@ export default class TransitionScreen {

splashVisibilityController(displayOn) {
if (!displayOn) {
this.clearProgressBarHandler();
this.LOADER_LIMIT = 95;
this.splashScreenEl.parentElement?.classList.remove('hide-splash-overflow');
this.splashScreenEl.classList.remove('show');
Expand Down
Loading