This is an automated email from the ASF dual-hosted git repository.

tbonelee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 33ebb738d4 [ZEPPELIN-6520] Bind repository proxy password input to 
proxyPassword control
33ebb738d4 is described below

commit 33ebb738d4d8ae43b8ffc14ca9fcbc642fb46160
Author: 김예나 <[email protected]>
AuthorDate: Mon Jul 13 00:37:21 2026 +0900

    [ZEPPELIN-6520] Bind repository proxy password input to proxyPassword 
control
    
    ### What is this PR for?
    
    In the interpreter "add repository" dialog, the proxy **Password** input 
was bound to the wrong reactive-form control (`proxyLogin`) — the same control 
the **Login** field already uses. As a result a proxy password could never be 
saved, and typing a proxy password overwrote the proxy login.
    
    This PR binds the Password input to the `proxyPassword` control so that 
both proxy credentials are submitted independently.
    
    `create-repository-modal.component.html`:
    ```diff
    -      <input nz-input type="password" formControlName="proxyLogin" 
placeholder="proxy password" />
    +      <input nz-input type="password" formControlName="proxyPassword" 
placeholder="proxy password" />
    ```
    
    ### What type of PR is it?
    
    Bug Fix
    
    ### Todos
    
    * [x] - Fix the form-control binding
    * [x] - Add an e2e regression test
    
    ### What is the ticket?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-6520
    
    ### How should this be tested?
    
    * `cd zeppelin-web-angular && npm run lint`
    * A Playwright e2e test is added: 
`e2e/tests/workspace/interpreter/create-repository-proxy-credentials.spec.ts`. 
It fills the proxy login and proxy password in the add-repository modal and 
asserts the `POST /api/interpreter/repository` payload carries each value in 
its own field (`proxyLogin` / `proxyPassword`). The test fails on the current 
binding and passes with this fix.
    * Manually: add a repository with a proxy login and password in the 
interpreter UI and confirm both are sent.
    
    ### Screenshots (if appropriate)
    
    N/A — the form renders identically; the defect is only visible in the 
submitted payload.
    
    ### Questions:
    
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    
    Closes #5291 from kimyenac/ZEPPELIN-6520.
    
    Signed-off-by: ChanHo Lee <[email protected]>
---
 .../e2e/models/interpreter-repository-modal.ts     | 65 +++++++++++++++++++++
 .../create-repository-proxy-credentials.spec.ts    | 66 ++++++++++++++++++++++
 .../create-repository-modal.component.html         |  2 +-
 3 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/zeppelin-web-angular/e2e/models/interpreter-repository-modal.ts 
b/zeppelin-web-angular/e2e/models/interpreter-repository-modal.ts
new file mode 100644
index 0000000000..c4fc0d1782
--- /dev/null
+++ b/zeppelin-web-angular/e2e/models/interpreter-repository-modal.ts
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Locator, Page } from '@playwright/test';
+import { BasePage } from './base-page';
+
+export interface RepositoryProxyCredentials {
+  id: string;
+  url: string;
+  proxyLogin: string;
+  proxyPassword: string;
+}
+
+export class InterpreterRepositoryModal extends BasePage {
+  readonly repositoryTrigger: Locator;
+  readonly createRepositoryTag: Locator;
+  readonly idInput: Locator;
+  readonly urlInput: Locator;
+  readonly proxyLoginInput: Locator;
+  readonly proxyPasswordInput: Locator;
+  readonly addButton: Locator;
+
+  constructor(page: Page) {
+    super(page);
+    this.repositoryTrigger = page.locator('button.repository-trigger');
+    this.createRepositoryTag = page.locator('nz-tag.editable-tag');
+    this.idInput = page.locator('input[placeholder="Repository id"]');
+    this.urlInput = page.locator('input[placeholder="Repository url"]');
+    // Locate the proxy inputs by placeholder, not formControlName: the 
binding is
+    // what the regression test exercises, so the locator must not depend on 
it.
+    this.proxyLoginInput = page.locator('input[placeholder="proxy login"]');
+    this.proxyPasswordInput = page.locator('input[placeholder="proxy 
password"]');
+    this.addButton = page.getByRole('button', { name: 'Add', exact: true });
+  }
+
+  async navigate(): Promise<void> {
+    await this.navigateToRoute('/interpreter');
+  }
+
+  async openCreateModal(): Promise<void> {
+    await this.repositoryTrigger.click();
+    await this.createRepositoryTag.click();
+    await this.idInput.waitFor({ state: 'visible' });
+  }
+
+  async fillProxyRepository(form: RepositoryProxyCredentials): Promise<void> {
+    await this.fillAndVerifyInput(this.idInput, form.id);
+    await this.fillAndVerifyInput(this.urlInput, form.url);
+    await this.fillAndVerifyInput(this.proxyLoginInput, form.proxyLogin);
+    await this.fillAndVerifyInput(this.proxyPasswordInput, form.proxyPassword);
+  }
+
+  async submit(): Promise<void> {
+    await this.addButton.click();
+  }
+}
diff --git 
a/zeppelin-web-angular/e2e/tests/workspace/interpreter/create-repository-proxy-credentials.spec.ts
 
b/zeppelin-web-angular/e2e/tests/workspace/interpreter/create-repository-proxy-credentials.spec.ts
new file mode 100644
index 0000000000..ec156dac60
--- /dev/null
+++ 
b/zeppelin-web-angular/e2e/tests/workspace/interpreter/create-repository-proxy-credentials.spec.ts
@@ -0,0 +1,66 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { expect, test } from '@playwright/test';
+import { InterpreterRepositoryModal } from 
'../../../models/interpreter-repository-modal';
+import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from 
'../../../utils';
+
+interface AddRepositoryRequestBody {
+  id: string;
+  proxyLogin?: string;
+  proxyPassword?: string;
+}
+
+test.describe('Interpreter Repository - Proxy Credentials', () => {
+  addPageAnnotationBeforeEach(PAGES.WORKSPACE.INTERPRETER_CREATE_REPO);
+
+  test('submits the proxy login and proxy password to their own fields', async 
({ page }) => {
+    const proxyLogin = 'proxy-user';
+    const proxyPassword = 'proxy-secret';
+    const repoId = `e2e-proxy-repo-${Date.now()}`;
+
+    await page.goto('/#/interpreter');
+    await waitForZeppelinReady(page);
+
+    // Intercept the POST so the payload can be checked without persisting a 
repo.
+    let requestBody: AddRepositoryRequestBody | null = null;
+    await page.route('**/api/interpreter/repository', async route => {
+      if (route.request().method() === 'POST') {
+        requestBody = route.request().postDataJSON() as 
AddRepositoryRequestBody;
+        await route.fulfill({
+          status: 200,
+          contentType: 'application/json',
+          body: JSON.stringify({ status: 'OK', message: '', body: '' })
+        });
+        return;
+      }
+      await route.continue();
+    });
+
+    const modal = new InterpreterRepositoryModal(page);
+    await modal.openCreateModal();
+    await modal.fillProxyRepository({
+      id: repoId,
+      url: 'repo1.maven.org/maven2/',
+      proxyLogin,
+      proxyPassword
+    });
+    await modal.submit();
+
+    await expect.poll(() => requestBody, { timeout: 15000 }).not.toBeNull();
+
+    // Regression guard for ZEPPELIN-6520: Password was bound to proxyLogin, 
so the
+    // password overwrote the login and proxyPassword was always empty.
+    expect(requestBody!.proxyLogin).toBe(proxyLogin);
+    expect(requestBody!.proxyPassword).toBe(proxyPassword);
+  });
+});
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html
 
b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html
index 072be772b2..607e4987f8 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html
@@ -84,7 +84,7 @@
   <nz-form-item>
     <nz-form-label [nzSpan]="6">Password</nz-form-label>
     <nz-form-control nz-col [nzSpan]="16">
-      <input nz-input type="password" formControlName="proxyLogin" 
placeholder="proxy password" />
+      <input nz-input type="password" formControlName="proxyPassword" 
placeholder="proxy password" />
     </nz-form-control>
   </nz-form-item>
 </form>

Reply via email to