Browse Source

[E2E][CI] Add renaming file management E2E tests (#8160)

3.0.0/version-upgrade
xiangzihao 2 years ago committed by GitHub
parent
commit
30b8b4a93e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 197
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java
  2. 2
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java
  3. 170
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java
  4. 51
      dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/Constants.java
  5. 26
      dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java
  6. 5
      dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
  7. 4
      dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue
  8. 6
      dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
  9. 2
      dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/rename.vue
  10. 2
      dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
  11. 4
      dolphinscheduler-ui/src/js/module/components/popup/popup.vue

197
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java

@ -20,6 +20,7 @@
package org.apache.dolphinscheduler.e2e.cases;
import org.apache.dolphinscheduler.e2e.core.Constants;
import org.apache.dolphinscheduler.e2e.core.DolphinScheduler;
import org.apache.dolphinscheduler.e2e.pages.LoginPage;
import org.apache.dolphinscheduler.e2e.pages.resource.FileManagePage;
@ -28,6 +29,7 @@ import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage;
import org.apache.dolphinscheduler.e2e.pages.security.TenantPage;
import org.apache.dolphinscheduler.e2e.pages.security.UserPage;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
@ -38,6 +40,12 @@ import org.openqa.selenium.remote.RemoteWebDriver;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Paths;
import java.util.Arrays;
@DolphinScheduler(composeFiles = "docker/file-manage/docker-compose.yaml")
public class FileManageE2ETest {
private static RemoteWebDriver browser;
@ -54,6 +62,20 @@ public class FileManageE2ETest {
private static final String testDiretoryName = "test_directory";
private static final String testSubDirectoryName = "test_sub_directory";
private static final String testRenameDirectoryName = "test_rename_directory";
private static final String testFileName = "test_file";
private static final String testRenameFileName = "test_rename_file.sh";
private static final String testUnder1GBFileName = "test_file_0.01G";
private static final String testOver1GBFilePath = Constants.HOST_TMP_PATH + "/test_file_1.5G";
private static final String testUnder1GBFilePath = Constants.HOST_TMP_PATH + "/" + testUnder1GBFileName;
@BeforeAll
public static void setup() {
TenantPage tenantPage = new LoginPage(browser)
@ -72,6 +94,21 @@ public class FileManageE2ETest {
.goToTab(FileManagePage.class);
}
@AfterAll
public static void cleanup() {
String[] command = {"/bin/bash", "-c", String.format("sudo rm -f %s && sudo rm -f %s && sudo rm -rf %s", testUnder1GBFilePath, testOver1GBFilePath, Constants.HOST_CHROME_DOWNLOAD_PATH)};
try {
Process pro = Runtime.getRuntime().exec(command);
int status = pro.waitFor();
if (status != 0) {
throw new RuntimeException(String.format("Failed to call shell's command: %s", Arrays.toString(command)));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Test
@Order(10)
void testCreateDirectory() {
@ -85,6 +122,19 @@ public class FileManageE2ETest {
.anyMatch(it -> it.contains(testDiretoryName)));
}
@Test
@Order(11)
void testCancelCreateDirectory() {
final FileManagePage page = new FileManagePage(browser);
page.cancelCreateDirectory(testDiretoryName, "test_desc");
await().untilAsserted(() -> assertThat(page.fileList())
.as("File list should contain newly-created file")
.extracting(WebElement::getText)
.anyMatch(it -> it.contains(testDiretoryName)));
}
@Test
@Order(20)
void testCreateDuplicateDirectory() {
@ -99,12 +149,44 @@ public class FileManageE2ETest {
page.createDirectoryBox().buttonCancel().click();
}
@Test
@Order(21)
void testCreateSubDirectory() {
final FileManagePage page = new FileManagePage(browser);
page.createSubDirectory(testDiretoryName, testSubDirectoryName, "test_desc");
await().untilAsserted(() -> assertThat(page.fileList())
.as("File list should contain newly-created file")
.extracting(WebElement::getText)
.anyMatch(it -> it.contains(testSubDirectoryName)));
}
@Test
@Order(22)
void testRenameDirectory() {
final FileManagePage page = new FileManagePage(browser);
page.rename(testSubDirectoryName, testRenameDirectoryName);
await().untilAsserted(() -> {
browser.navigate().refresh();
assertThat(page.fileList())
.as("File list should contain newly-created file")
.extracting(WebElement::getText)
.anyMatch(it -> it.contains(testRenameDirectoryName));
});
}
@Test
@Order(30)
void testDeleteDirectory() {
final FileManagePage page = new FileManagePage(browser);
page.delete(testDiretoryName);
page.goToNav(ResourcePage.class)
.goToTab(FileManagePage.class)
.delete(testDiretoryName);
await().untilAsserted(() -> {
browser.navigate().refresh();
@ -116,4 +198,117 @@ public class FileManageE2ETest {
);
});
}
@Test
@Order(40)
void testCreateFile() {
final FileManagePage page = new FileManagePage(browser);
String scripts = "echo 123";
page.createFile(testFileName, scripts);
await().untilAsserted(() -> assertThat(page.fileList())
.as("File list should contain newly-created file")
.extracting(WebElement::getText)
.anyMatch(it -> it.contains(testFileName)));
}
@Test
@Order(41)
void testRenameFile() {
final FileManagePage page = new FileManagePage(browser);
page.rename(testFileName, testRenameFileName);
await().untilAsserted(() -> {
browser.navigate().refresh();
assertThat(page.fileList())
.as("File list should contain newly-created file")
.extracting(WebElement::getText)
.anyMatch(it -> it.contains(testRenameFileName));
});
}
@Test
@Order(42)
void testEditFile() {
final FileManagePage page = new FileManagePage(browser);
String scripts = "echo 456";
page.editFile(testRenameFileName, scripts);
await().untilAsserted(() -> assertThat(page.fileList())
.as("File list should contain newly-created file")
.extracting(WebElement::getText)
.anyMatch(it -> it.contains(testRenameFileName)));
}
@Test
@Order(45)
void testDeleteFile() {
final FileManagePage page = new FileManagePage(browser);
page.delete(testRenameFileName);
await().untilAsserted(() -> {
browser.navigate().refresh();
assertThat(
page.fileList()
).noneMatch(
it -> it.getText().contains(testRenameFileName)
);
});
}
@Test
@Order(60)
void testUploadOver1GBFile() throws IOException {
final FileManagePage page = new FileManagePage(browser);
RandomAccessFile file = new RandomAccessFile(testOver1GBFilePath, "rw");
file.setLength((long) (1.5 * 1024 * 1024 * 1024));
page.uploadFile(testOver1GBFilePath);
await().untilAsserted(() ->
assertThat(browser.findElement(By.tagName("body")).getText())
.contains("Upload File size cannot exceed 1g")
);
}
@Test
@Order(65)
void testUploadUnder1GBFile() throws IOException {
final FileManagePage page = new FileManagePage(browser);
browser.navigate().refresh();
RandomAccessFile file = new RandomAccessFile(testUnder1GBFilePath, "rw");
file.setLength((long) (0.01 * 1024 * 1024 * 1024));
page.uploadFile(testUnder1GBFilePath);
await().untilAsserted(() -> {
assertThat(page.fileList())
.as("File list should contain newly-created file")
.extracting(WebElement::getText)
.anyMatch(it -> it.contains(testUnder1GBFileName));
});
}
@Test
@Order(70)
void testDownloadFile() {
final FileManagePage page = new FileManagePage(browser);
page.downloadFile(testUnder1GBFileName);
File file = new File(Paths.get(Constants.HOST_CHROME_DOWNLOAD_PATH, testUnder1GBFileName).toFile().getAbsolutePath());
await().untilAsserted(() -> {
assert file.exists();
});
}
}

2
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java

@ -31,6 +31,7 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
@ -105,4 +106,5 @@ public class MysqlDataSourceE2ETest {
);
});
}
}

170
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java

@ -22,16 +22,18 @@ package org.apache.dolphinscheduler.e2e.pages.resource;
import lombok.Getter;
import org.apache.dolphinscheduler.e2e.pages.common.CodeEditor;
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
import org.apache.dolphinscheduler.e2e.pages.security.TenantPage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.LocalFileDetector;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.FindBys;
import org.openqa.selenium.support.PageFactory;
import java.io.File;
import java.util.List;
@ -40,8 +42,20 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab {
@FindBy(id = "btnCreateDirectory")
private WebElement buttonCreateDirectory;
@FindBy(id = "btnCreateFile")
private WebElement buttonCreateFile;
@FindBy(id = "btnUploadFile")
private WebElement buttonUploadFile;
private final CreateDirectoryBox createDirectoryBox;
private final RenameDirectoryBox renameDirectoryBox;
private final CreateFileBox createFileBox;
private final UploadFileBox uploadFileBox;
@FindBy(className = "items")
private List<WebElement> fileList;
@ -58,6 +72,12 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab {
super(driver);
createDirectoryBox = new CreateDirectoryBox();
renameDirectoryBox = new RenameDirectoryBox();
createFileBox = new CreateFileBox();
uploadFileBox = new UploadFileBox();
}
public FileManagePage createDirectory(String name, String description) {
@ -70,6 +90,51 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab {
return this;
}
public FileManagePage cancelCreateDirectory(String name, String description) {
buttonCreateDirectory().click();
createDirectoryBox().inputDirectoryName().sendKeys(name);
createDirectoryBox().inputDescription().sendKeys(description);
createDirectoryBox().buttonCancel().click();
return this;
}
public FileManagePage rename(String currentName, String AfterName) {
fileList()
.stream()
.filter(it -> it.getText().contains(currentName))
.flatMap(it -> it.findElements(By.id("btnRename")).stream())
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException("No rename button in file manage list"))
.click();
renameDirectoryBox().inputName().clear();
renameDirectoryBox().inputName().sendKeys(AfterName);
renameDirectoryBox().buttonSubmit().click();
return this;
}
public FileManagePage createSubDirectory(String directoryName, String subDirectoryName, String description) {
fileList()
.stream()
.filter(it -> it.getText().contains(directoryName))
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("No %s in file manage list", directoryName)))
.click();
buttonCreateDirectory().click();
createDirectoryBox().inputDirectoryName().sendKeys(subDirectoryName);
createDirectoryBox().inputDescription().sendKeys(description);
createDirectoryBox().buttonSubmit().click();
return this;
}
public FileManagePage delete(String name) {
fileList()
.stream()
@ -90,6 +155,56 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab {
return this;
}
public FileManagePage createFile(String fileName, String scripts) {
buttonCreateFile().click();
createFileBox().inputFileName().sendKeys(fileName);
createFileBox().codeEditor().content(scripts);
createFileBox().buttonSubmit().click();
return this;
}
public FileManagePage editFile(String fileName, String scripts) {
fileList()
.stream()
.filter(it -> it.getText().contains(fileName))
.flatMap(it -> it.findElements(By.id("btnEdit")).stream())
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException("No edit button in file manage list"))
.click();
createFileBox().codeEditor().content(scripts);
createFileBox().buttonSubmit().click();
return this;
}
public FileManagePage uploadFile(String filePath) {
buttonUploadFile().click();
driver.setFileDetector(new LocalFileDetector());
uploadFileBox().buttonUpload().sendKeys(filePath);
uploadFileBox().buttonSubmit().click();
return this;
}
public FileManagePage downloadFile(String fileName) {
fileList()
.stream()
.filter(it -> it.getText().contains(fileName))
.flatMap(it -> it.findElements(By.id("btnDownload")).stream())
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException("No download button in file manage list"))
.click();
return this;
}
@Getter
public class CreateDirectoryBox {
CreateDirectoryBox() {
@ -108,4 +223,57 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab {
@FindBy(id = "btnCancel")
private WebElement buttonCancel;
}
@Getter
public class RenameDirectoryBox {
RenameDirectoryBox() {
PageFactory.initElements(driver, this);
}
@FindBy(id = "inputName")
private WebElement inputName;
@FindBy(id = "inputDescription")
private WebElement inputDescription;
@FindBy(id = "btnSubmit")
private WebElement buttonSubmit;
@FindBy(id = "btnCancel")
private WebElement buttonCancel;
}
@Getter
public class CreateFileBox {
CreateFileBox() {
PageFactory.initElements(driver, this);
}
@FindBy(id = "inputFileName")
private WebElement inputFileName;
private final CodeEditor codeEditor = new CodeEditor(driver);
@FindBy(id = "btnSubmit")
private WebElement buttonSubmit;
@FindBy(id = "btnCancel")
private WebElement buttonCancel;
}
@Getter
public class UploadFileBox {
UploadFileBox() {
PageFactory.initElements(driver, this);
}
@FindBy(id = "btnUpload")
private WebElement buttonUpload;
@FindBy(id = "btnSubmit")
private WebElement buttonSubmit;
@FindBy(id = "btnCancel")
private WebElement buttonCancel;
}
}

51
dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/Constants.java

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.dolphinscheduler.e2e.core;
import java.nio.file.Paths;
/**
* Constants
*/
public final class Constants {
private Constants() {
throw new UnsupportedOperationException("Construct Constants");
}
/**
* tmp directory path
*/
public static final String HOST_TMP_PATH = System.getProperty("java.io.tmpdir");
/**
* chrome download path in host
*/
public static final String HOST_CHROME_DOWNLOAD_PATH = Paths.get(System.getProperty("java.io.tmpdir"), "download").toFile().getAbsolutePath();
/**
* chrome download path in selenium/standalone-chrome-debug container
*/
public static final String SELENIUM_CONTAINER_CHROME_DOWNLOAD_PATH = "/home/seluser/Downloads";
/**
* host os name
*/
public static final String OS_NAME = System.getProperties().getProperty("os.name");
}

26
dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java

@ -31,6 +31,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@ -116,8 +117,33 @@ final class DolphinSchedulerExtension
} else {
record = Files.createTempDirectory("record-");
}
// According to https://github.com/SeleniumHQ/docker-selenium#mounting-volumes-to-retrieve-downloaded-files
if ("linux".equalsIgnoreCase(Constants.OS_NAME)) {
File file = new File(Constants.HOST_CHROME_DOWNLOAD_PATH);
boolean result = file.mkdir();
if (!result) {
throw new IOException(String.format("mkdir %s error", Constants.HOST_CHROME_DOWNLOAD_PATH));
}
String[] command = {"/bin/bash", "-c", String.format("sudo chown 1200:1201 %s", Constants.HOST_CHROME_DOWNLOAD_PATH)};
try {
Process pro = Runtime.getRuntime().exec(command);
int status = pro.waitFor();
if (status != 0) {
throw new IOException(String.format("Failed to call shell's command: %s", Arrays.toString(command)));
}
} catch (Exception e) {
throw new IOException(e);
}
}
browser = new BrowserWebDriverContainer<>()
.withCapabilities(new ChromeOptions())
.withFileSystemBind(Constants.HOST_CHROME_DOWNLOAD_PATH, Constants.SELENIUM_CONTAINER_CHROME_DOWNLOAD_PATH)
.withRecordingMode(RECORD_ALL, record.toFile(), MP4);
if (network != null) {
browser.withNetwork(network);

5
dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue

@ -22,6 +22,7 @@
<template slot="name"><strong>*</strong>{{$t('File Name')}}</template>
<template slot="content">
<el-input
id="inputFileName"
type="input"
v-model="fileName"
maxlength="60"
@ -66,8 +67,8 @@
<template slot="name">&nbsp;</template>
<template slot="content">
<div class="submit">
<el-button type="primary" size="small" round :loading="spinnerLoading" @click="ok()">{{spinnerLoading ? $t('Loading...') : $t('Create')}} </el-button>
<el-button type="text" size="small" @click="() => $router.push({name: 'file'})"> {{$t('Cancel')}} </el-button>
<el-button id="btnSubmit" type="primary" size="small" round :loading="spinnerLoading" @click="ok()">{{spinnerLoading ? $t('Loading...') : $t('Create')}} </el-button>
<el-button id="btnCancel" type="text" size="small" @click="() => $router.push({name: 'file'})"> {{$t('Cancel')}} </el-button>
</div>
</template>
</m-list-box-f>

4
dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue

@ -27,8 +27,8 @@
<textarea id="code-edit-mirror" name="code-edit-mirror"></textarea>
</div>
<div class="submit-c">
<el-button type="text" @click="close()" :disabled="disabled" size="small"> {{$t('Return')}} </el-button>
<el-button type="primary" :loading="spinnerLoading" @click="ok()" round size="small">{{spinnerLoading ? $t('Loading...') : $t('Save')}} </el-button>
<el-button id="btnCancel" type="text" @click="close()" :disabled="disabled" size="small"> {{$t('Return')}} </el-button>
<el-button id="btnSubmit" type="primary" :loading="spinnerLoading" @click="ok()" round size="small">{{spinnerLoading ? $t('Loading...') : $t('Save')}} </el-button>
</div>
</template>
<m-no-data :msg="msg" v-if="msg"></m-no-data>

6
dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue

@ -54,13 +54,13 @@
<el-table-column :label="$t('Operation')" width="150">
<template slot-scope="scope">
<el-tooltip :content="$t('Edit')" placement="top">
<span><el-button type="primary" size="mini" icon="el-icon-edit-outline" @click="_edit(scope.row)" :disabled="_rtDisb(scope.row)" circle></el-button></span>
<span><el-button id="btnEdit" type="primary" size="mini" icon="el-icon-edit-outline" @click="_edit(scope.row)" :disabled="_rtDisb(scope.row)" circle></el-button></span>
</el-tooltip>
<el-tooltip :content="$t('Rename')" placement="top">
<span><el-button type="primary" size="mini" icon="el-icon-edit" @click="_rename(scope.row,scope.$index)" circle></el-button></span>
<span><el-button id="btnRename" type="primary" size="mini" icon="el-icon-edit" @click="_rename(scope.row,scope.$index)" circle></el-button></span>
</el-tooltip>
<el-tooltip :content="$t('Download')" placement="top">
<span><el-button type="primary" size="mini" icon="el-icon-download" @click="_downloadFile(scope.row)" :disabled="scope.row.directory? true: false" circle></el-button></span>
<span><el-button id="btnDownload" type="primary" size="mini" icon="el-icon-download" @click="_downloadFile(scope.row)" :disabled="scope.row.directory? true: false" circle></el-button></span>
</el-tooltip>
<el-tooltip :content="$t('Delete')" placement="top">
<el-popconfirm

2
dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/rename.vue

@ -22,6 +22,7 @@
<template slot="name"><strong>*</strong>{{$t('Name')}}</template>
<template slot="content">
<el-input
id="inputName"
type="input"
v-model="name"
size="small"
@ -33,6 +34,7 @@
<template slot="name">{{$t('Description')}}</template>
<template slot="content">
<el-input
id="inputDescription"
type="textarea"
v-model="description"
size="small"

2
dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue

@ -70,7 +70,7 @@
<template slot="content">
<div class="file-update-box">
<template v-if="progress === 0">
<input ref="file" name="file" type="file" class="file-update" @change="_onChange">
<input id="btnUpload" ref="file" name="file" type="file" class="file-update" @change="_onChange">
<el-button type="dashed" size="mini">{{$t('Upload')}}<em class="el-icon-upload"></em></el-button>
</template>
<div class="progress-box" v-if="progress !== 0">

4
dolphinscheduler-ui/src/js/module/components/popup/popup.vue

@ -23,8 +23,8 @@
<slot name="content"></slot>
</div>
<div class="bottom-p">
<el-button type="text" size="mini" round @click="close()" :disabled="disabled"> {{$t('Cancel')}} </el-button>
<el-button type="primary" size="mini" round :loading="spinnerLoading" @click="ok()" :disabled="disabled || apDisabled">{{spinnerLoading ? $t('Loading...') : okText}} </el-button>
<el-button id="btnCancel" type="text" size="mini" round @click="close()" :disabled="disabled"> {{$t('Cancel')}} </el-button>
<el-button id="btnSubmit" type="primary" size="mini" round :loading="spinnerLoading" @click="ok()" :disabled="disabled || apDisabled">{{spinnerLoading ? $t('Loading...') : okText}} </el-button>
</div>
</div>
</template>

Loading…
Cancel
Save