Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
db6a1e5
WEBUI-1916 drive actions buttons should handle error properly when dr…
swarnadipa-dev Apr 24, 2026
950ae0c
show error toast for edit with drive when drive not installed
swarnadipa-dev Apr 27, 2026
19ba9ab
fixed Copilot review comments. added unit tests
swarnadipa-dev Apr 27, 2026
1a5e254
fixed blur logic. added unit tests
swarnadipa-dev Apr 28, 2026
094b942
addressed copilot review comments
swarnadipa-dev Apr 30, 2026
9ffe19a
removed app.js changes
swarnadipa-dev Apr 30, 2026
af3d045
removed app.js changes
swarnadipa-dev Apr 30, 2026
270c2ed
fix i18n key ordering: sort drive keys alphabetically
Copilot May 3, 2026
7436080
show install dialog when Drive is not installed across Chrome/Edge/Sa…
swarnadipa-dev May 5, 2026
a497064
refactored code and updated unit tests
swarnadipa-dev May 6, 2026
1fb52a9
removed unwanted merge markers.
swarnadipa-dev May 6, 2026
f9193f3
removed duplicate code. fixed lint
swarnadipa-dev May 6, 2026
6eace67
addressed sonar quality issues
swarnadipa-dev May 6, 2026
122d980
addressed sonar quality issues
swarnadipa-dev May 6, 2026
5923246
addressed sonar quality issues
swarnadipa-dev May 6, 2026
f4de18f
addressed sonar quality issues
swarnadipa-dev May 6, 2026
db334e5
addressed sonar quality issues
swarnadipa-dev May 6, 2026
b1ed417
fixed lint issue
swarnadipa-dev May 6, 2026
fcb506b
WEBUI-2002 : Upgrade ESLint and @eslint/js to v10 (#3111)
madhurkulshrestha-hyland May 11, 2026
6e1d5d9
WEBUI-1990: added sonar configurations [LTS-2023] (#3102)
swarnadipa-dev May 12, 2026
21adcfa
WEBUI-1990: fix sonar branch detection and add push trigger [LTS-2023…
swarnadipa-dev May 12, 2026
5bcab81
fix(sonar): use PR decoration params on pull_request events instead o…
swarnadipa-dev May 12, 2026
656b70a
fix(sonar): include addon test directories in sonar.tests and sonar.t…
swarnadipa-dev May 12, 2026
6a9749f
WEBUI-1990: declare addon test dirs as test code in sonar-project.pro…
swarnadipa-dev May 13, 2026
1a96b90
WEBUI-1990: fix sonar.tests source/test overlap (#3142)
swarnadipa-dev May 13, 2026
71dd606
WEBUI-2015 : lock JavaScript dependency versions with npm ci [LTS-202…
madhurkulshrestha-hyland May 14, 2026
4976cce
WEBUI-2017 WEBUI-2018 : define permissions at job level in workflow f…
madhurkulshrestha-hyland May 15, 2026
9a09760
WEBUI-1990: exclude non-unit-testable files from sonar coverage metri…
swarnadipa-dev May 18, 2026
e51e561
fix: prevent dialog toggle loop with no-cancel-on-outside-click and o…
swarnadipa-dev May 20, 2026
f6e509d
fix(lint): remove unused uaStub variable in nuxeo-drive-protocol-hand…
Copilot May 20, 2026
edbfd7e
fix: format long line in Safari test setup to respect Prettier printW…
swarnadipa-dev May 20, 2026
9cceaaf
WEBUI-1916: Drive action buttons handle failure gracefully
swarnadipa-dev May 22, 2026
3f2e700
removed nuxeo-protocol-handler file
swarnadipa-dev May 22, 2026
af78add
WEBUI-1916: Drive dialog UI improvements and persistent failure message
swarnadipa-dev May 25, 2026
f57d59c
added window.location.href
swarnadipa-dev May 25, 2026
202b256
fix: use hidden object for Safari and anchor click for other browsers…
swarnadipa-dev May 25, 2026
e6b0f7a
fix: use timeout-based protocol handler detection for _failureVisible
swarnadipa-dev May 25, 2026
2081290
test: add _launchDrive and _navigateTo unit tests for Drive buttons
swarnadipa-dev May 25, 2026
159603c
fix: Firefox _navigateTo via window.open, focus-return on non-macOS, …
swarnadipa-dev May 26, 2026
3874800
refactor: simplify Drive buttons - remove protocol detection, always …
swarnadipa-dev May 26, 2026
2eab8b9
test(WEBUI-1916): add unit tests for drive action buttons to reach 90…
swarnadipa-dev May 28, 2026
68dc9ac
chore: restore files unchanged from maintenance-3.1.x
swarnadipa-dev May 29, 2026
cbdf6a7
fix: correct unit test assertions for drive action buttons
swarnadipa-dev May 29, 2026
aeda74c
fix: extract _navigate() to prevent Karma page reload in tests
swarnadipa-dev May 29, 2026
241ece5
test: improve coverage to >90% on drive action button new code
swarnadipa-dev May 29, 2026
062f8ec
refactor: rename nuxeo-drive-test-helpers.js to nuxeo-drive-test-help…
swarnadipa-dev May 29, 2026
5d6122d
chore: revert sonar coverage exclusion for addon test helpers
swarnadipa-dev May 29, 2026
27eb9fc
refactor(drive): extract shared token-fetch and base64 utils to reduc…
swarnadipa-dev May 29, 2026
a0ef638
fix(drive): resolve Sonar maintainability issues
swarnadipa-dev May 29, 2026
0603b80
fix(drive): resolve Sonar issues in nuxeo-drive-utils.js
swarnadipa-dev May 29, 2026
e28fe45
fix(drive): remove regex from base64UrlSafeEncode to resolve Sonar S5852
swarnadipa-dev May 29, 2026
b3b5e1f
fix(drive): address Copilot review comments on i18n ordering and isPr…
swarnadipa-dev May 29, 2026
c73543b
WEBUI-1916: refactor Drive action buttons to navigate-first pattern
swarnadipa-dev May 29, 2026
1789d33
WEBUI-1916: clarify install hint link text in Drive dialog
swarnadipa-dev May 29, 2026
73ff408
test: update Drive button unit tests for navigate-first pattern
swarnadipa-dev May 29, 2026
45d8f7b
fix: use anchor click instead of location.href for nxdrive:// navigation
swarnadipa-dev May 29, 2026
02fb0c9
test: increase Drive button test coverage to >90%
swarnadipa-dev May 29, 2026
2602d62
fix(i18n): remove dead driveButton keys, add missing driveUpload.serv…
swarnadipa-dev May 29, 2026
1408f1e
fix: improve addGoSuite test isolation by conditionally stubbing _nav…
swarnadipa-dev Jun 1, 2026
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
17 changes: 12 additions & 5 deletions addons/nuxeo-drive/elements/nuxeo-drive-desktop-packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Polymer({
.table {
font-family: var(--nuxeo-app-font);
line-height: 3.5;
text-align: left;
}

.row {
Expand All @@ -54,20 +55,26 @@ Polymer({
.header {
background-color: var(--nuxeo-table-header-background);
color: var(--nuxeo-table-header-titles);
font-weight: 400;
font-weight: bold;
height: 56px;
display: flex;
flex-direction: row;
}

.cell {
padding: 0 24px 0 24px;
padding: 0 16px;
min-height: 46px;
overflow: hidden;
display: flex;
align-items: center;
}

paper-button {
line-height: normal;
margin: 0;
padding: 0;
min-width: 0;
text-transform: none;
}

.platform {
Expand All @@ -77,7 +84,7 @@ Polymer({
font-size: 0.9em;
letter-spacing: 0.04em;
line-height: 130%;
margin: 0 0.2em 0.2em 0;
margin: 0;
padding: 0.06em 0.3em;
vertical-align: baseline;
white-space: nowrap;
Expand All @@ -89,12 +96,12 @@ Polymer({
<div class="table">
<div class="header">
<div class="cell flex">[[i18n('driveDesktopPackages.platform')]]</div>
<div class="cell flex-3">[[i18n('driveDesktopPackages.install')]]</div>
<div class="cell flex-2">[[i18n('driveDesktopPackages.install')]]</div>
</div>
<template is="dom-repeat" items="[[packages]]" as="pkg">
<div class="row">
<div class="cell flex"><span class="platform">[[pkg.platform]]</span></div>
<div class="cell flex-3">
<div class="cell flex-2">
<a href$="[[pkg.url]]" tabindex="-1" target="_blank">
<paper-button noink> [[pkg.name]] </paper-button>
</a>
Expand Down
110 changes: 74 additions & 36 deletions addons/nuxeo-drive/elements/nuxeo-drive-download-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { mixinBehaviors } from '@polymer/polymer/lib/legacy/class.js';
import { I18nBehavior } from '@nuxeo/nuxeo-ui-elements/nuxeo-i18n-behavior.js';
import { isPageProviderDisplayBehavior } from '../../../elements/select-all-helpers.js';
import './nuxeo-drive-icons.js';
import { base64UrlSafeEncode, navigateAndShowFallback } from './nuxeo-drive-utils.js';

window.nuxeo = window.nuxeo || {};
const baseUrl = window.nuxeo.baseUrl || window.location.origin + window.location.pathname;
Expand All @@ -44,17 +45,21 @@ class NuxeoDriveDownloadButton extends mixinBehaviors([I18nBehavior], PolymerEle
reflectToAttribute: true,
value: false,
},

_installExpanded: {
type: Boolean,
value: false,
},
};
}

static get template() {
return html`
<style include="nuxeo-action-button-styles"></style>

<nuxeo-resource id="token" path="/token" params='{"application": "Nuxeo Drive"}'></nuxeo-resource>
<div
class="action"
on-tap="_download"
on-click="_download"
hidden$="[[!_isAvailable(documents.splices, documents.items.splices, documents.items.length, documents.selectedItems.splices, documents.selectedItems.length)]]"
>
<paper-icon-button noink icon="nuxeo-drive:download" id="driveBtn" aria-labelledby="label"></paper-icon-button>
Expand All @@ -63,12 +68,59 @@ class NuxeoDriveDownloadButton extends mixinBehaviors([I18nBehavior], PolymerEle
</div>

<nuxeo-dialog id="dialog" with-backdrop>
<div class="vertical layout">
<h1>[[i18n('driveEditButton.dialog.heading')]]</h1>
<nuxeo-drive-desktop-packages></nuxeo-drive-desktop-packages>
<style>
#dialog {
margin-top: 0;
top: 50%;
transform: translateY(-50%);
max-height: 80vh;
}

.dialog-content {
padding: 16px 24px;
}

.dialog-content h1 {
margin: 0 0 12px;
font-size: 1.6em;
}

.dialog-content p {
color: var(--primary-text-color, #333);
margin: 0 0 16px;
}

.close-btn {
border: 1px solid var(--nuxeo-primary-color, #0066ff);
color: var(--nuxeo-primary-color, #0066ff);
text-transform: uppercase;
font-size: 0.9em;
padding: 0.5em 1em;
}

.buttons {
justify-content: flex-end;
}

.install-link {
display: inline-block;
margin-top: 4px;
font-size: 0.9em;
}
</style>
<div class="dialog-content">
<h1>[[i18n('driveButton.dialog.heading')]]</h1>
<p>[[i18n('driveButton.dialog.description')]]</p>
<template is="dom-if" if="[[_installExpanded]]">
<p>[[i18n('driveButton.dialog.install.prompt')]]</p>
<nuxeo-drive-desktop-packages></nuxeo-drive-desktop-packages>
</template>
<template is="dom-if" if="[[!_installExpanded]]">
<a class="install-link" href="#" on-click="_toggleInstall">[[i18n('driveButton.install.dialog.hint')]]</a>
</template>
</div>
<div class="buttons">
<paper-button dialog-dismiss class="secondary">[[i18n('command.close')]]</paper-button>
<paper-button dialog-dismiss class="close-btn">[[i18n('command.close')]]</paper-button>
</div>
</nuxeo-dialog>

Expand All @@ -79,7 +131,7 @@ class NuxeoDriveDownloadButton extends mixinBehaviors([I18nBehavior], PolymerEle
_isAvailable() {
return isPageProviderDisplayBehavior(this.documents)
? (this.documents.selectedItems || this.documents.items || []).length > 0
: this.documents && this.documents.length > 0;
: this.documents?.length > 0;
}

_download() {
Expand All @@ -95,21 +147,17 @@ class NuxeoDriveDownloadButton extends mixinBehaviors([I18nBehavior], PolymerEle
return;
}

this.$.token
.get()
.then((response) => {
const tokens = response.entries.map((token) => token.id);

if (!tokens || !tokens.length) {
this.$.dialog.toggle();
return;
}

window.open(this.directDownloadUrl, '_top');
})
.catch((err) => {
this._showError(err && err.userMessage ? err.userMessage : this.i18n('driveDownload.directTransfer.failed'));
});
try {
this._installExpanded = false;
navigateAndShowFallback(this, this.directDownloadUrl);
} catch (e) {
this._showError(e.userMessage || e.message);
}
}

_toggleInstall(e) {
e.preventDefault();
this._installExpanded = true;
}

_showError(message) {
Expand All @@ -122,11 +170,11 @@ class NuxeoDriveDownloadButton extends mixinBehaviors([I18nBehavior], PolymerEle
return (this.documents.selectedItems || this.documents.items || []).map((doc) => doc.uid);
}

if (this.documents && this.documents.length > 0) {
if (this.documents?.length > 0) {
return this.documents.map((doc) => doc.uid);
}

if (this.document && this.document.uid) {
if (this.document?.uid) {
return [this.document.uid];
}

Expand Down Expand Up @@ -173,25 +221,15 @@ class NuxeoDriveDownloadButton extends mixinBehaviors([I18nBehavior], PolymerEle
const serverBytes = new TextEncoder().encode(server);
if (serverBytes.length > 255) {
const userMessage = this.i18n('driveDownload.serverUrlTooLong');
const err = new Error(this.i18n('driveDownload.serverUrlTooLong'));
const err = new Error(userMessage);
err.userMessage = userMessage;
throw err;
}
const payload = new Uint8Array([scheme, serverBytes.length, ...serverBytes, allUuidHex.length, ...uuidBinary]);

const b64 = this._base64UrlSafeEncode(payload);
const b64 = base64UrlSafeEncode(payload);
return `nxdrive://direct-download/${b64}`;
}

_base64UrlSafeEncode(bytes) {
let binary = '';
bytes.forEach((byte) => {
binary += String.fromCharCode(byte);
});

let b64 = btoa(binary);
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
}

customElements.define(NuxeoDriveDownloadButton.is, NuxeoDriveDownloadButton);
93 changes: 75 additions & 18 deletions addons/nuxeo-drive/elements/nuxeo-drive-edit-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { I18nBehavior } from '@nuxeo/nuxeo-ui-elements/nuxeo-i18n-behavior.js';
import { FiltersBehavior } from '@nuxeo/nuxeo-ui-elements/nuxeo-filters-behavior.js';
import { navigateAndShowFallback } from './nuxeo-drive-utils.js';

/**
`nuxeo-drive-edit-button`
Expand All @@ -31,25 +32,72 @@ Polymer({
_template: html`
<style include="nuxeo-action-button-styles"></style>

<nuxeo-resource id="token" path="/token" params='{"application": "Nuxeo Drive"}'></nuxeo-resource>

<template is="dom-if" if="[[_isAvailable(document,blob)]]">
<div class="action" on-tap="_go">
<div class="action" on-click="_go">
<paper-icon-button noink icon="icons:open-in-new" id="driveBtn" aria-labelledby="label"></paper-icon-button>
<span class="label" hidden$="[[!showLabel]]" id="label">[[i18n('driveEditButton.tooltip')]]</span>
<nuxeo-tooltip>[[i18n('driveEditButton.tooltip')]]</nuxeo-tooltip>
</div>
</template>

<nuxeo-dialog id="dialog" with-backdrop>
<div class="vertical layout">
<h1>[[i18n('driveEditButton.dialog.heading')]]</h1>
<nuxeo-drive-desktop-packages></nuxeo-drive-desktop-packages>
<style>
#dialog {
margin-top: 0;
top: 50%;
transform: translateY(-50%);
max-height: 80vh;
}

.dialog-content {
padding: 16px 24px;
}

.dialog-content h1 {
margin: 0 0 12px;
font-size: 1.6em;
}

.dialog-content p {
color: var(--primary-text-color, #333);
margin: 0 0 16px;
}

.close-btn {
border: 1px solid var(--nuxeo-primary-color, #0066ff);
color: var(--nuxeo-primary-color, #0066ff);
text-transform: uppercase;
font-size: 0.9em;
padding: 0.5em 1em;
}

.buttons {
justify-content: flex-end;
}

.install-link {
display: inline-block;
margin-top: 4px;
font-size: 0.9em;
}
</style>
<div class="dialog-content">
<h1>[[i18n('driveButton.dialog.heading')]]</h1>
<p>[[i18n('driveButton.dialog.description')]]</p>
<template is="dom-if" if="[[_installExpanded]]">
<p>[[i18n('driveButton.dialog.install.prompt')]]</p>
<nuxeo-drive-desktop-packages></nuxeo-drive-desktop-packages>
</template>
<template is="dom-if" if="[[!_installExpanded]]">
<a class="install-link" href="#" on-click="_toggleInstall">[[i18n('driveButton.install.dialog.hint')]]</a>
</template>
</div>
<div class="buttons">
<paper-button dialog-dismiss class="secondary">[[i18n('command.close')]]</paper-button>
<paper-button dialog-dismiss class="close-btn">[[i18n('command.close')]]</paper-button>
</div>
</nuxeo-dialog>

<paper-toast id="toast"></paper-toast>
`,

is: 'nuxeo-drive-edit-button',
Expand All @@ -67,23 +115,32 @@ Polymer({
reflectToAttribute: true,
value: false,
},

_installExpanded: {
type: Boolean,
value: false,
},
},

_isAvailable(doc, blob) {
return (
this.hasPermission(doc, 'Write') && !this.isProxy(doc) && blob && (!blob.appLinks || blob.appLinks.length === 0)
);
return this.hasPermission(doc, 'Write') && !this.isProxy(doc) && blob && !blob.appLinks?.length;
},

_go() {
this.$.token.get().then((response) => {
const tokens = response.entries.map((token) => token.id);
if (!tokens || !tokens.length) {
this.$.dialog.toggle();
return;
}
window.open(this.driveEditURL, '_top');
});
const url = this.driveEditURL;
if (!url) return;
this._installExpanded = false;
navigateAndShowFallback(this, url);
},

_toggleInstall(e) {
e.preventDefault();
this._installExpanded = true;
},

_showError(message) {
this.$.toast.text = message;
this.$.toast.open();
},

get driveEditURL() {
Expand Down
Loading
Loading