You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by oc...@apache.org on 2023/12/18 02:16:04 UTC
(trafficcontrol) branch master updated: Update Service Categories table to use AG-Grid (#7880)
This is an automated email from the ASF dual-hosted git repository.
ocket8888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new 0c5607e2d6 Update Service Categories table to use AG-Grid (#7880)
0c5607e2d6 is described below
commit 0c5607e2d6fa010bc02921b09e971539d92b2c4b
Author: The Anh Nguyen <nt...@gmail.com>
AuthorDate: Mon Dec 18 09:15:57 2023 +0700
Update Service Categories table to use AG-Grid (#7880)
* update UI service categories to AG-Grid
* update integration tests Service Categories
---
.../TableServiceCategoriesController.js | 81 ++++++++++----
.../table.serviceCategories.tpl.html | 35 ++----
.../PageObjects/ServiceCategories.po.ts | 122 ++++++++++-----------
.../integration/specs/ServiceCategories.spec.ts | 61 +++++++----
4 files changed, 168 insertions(+), 131 deletions(-)
diff --git a/traffic_portal/app/src/common/modules/table/serviceCategories/TableServiceCategoriesController.js b/traffic_portal/app/src/common/modules/table/serviceCategories/TableServiceCategoriesController.js
index 363ba6fe63..48c1958d2f 100644
--- a/traffic_portal/app/src/common/modules/table/serviceCategories/TableServiceCategoriesController.js
+++ b/traffic_portal/app/src/common/modules/table/serviceCategories/TableServiceCategoriesController.js
@@ -18,36 +18,79 @@
*/
/**
- * @param {*} serviceCategories
+ *@typedef ServiceCategory
+ * @property {string} name
+ * @property {string} lastUpdated
+ */
+
+/**
+ * @param {ServiceCategory} serviceCategories
* @param {*} $scope
* @param {*} $state
* @param {import("../../../service/utils/LocationUtils")} locationUtils
*/
-var TableServiceCategoriesController = function(serviceCategories, $scope, $state, locationUtils) {
+var TableServiceCategoriesController = function (
+ serviceCategories,
+ $scope,
+ $state,
+ locationUtils
+) {
+ /**** Constants, scope data, etc. ****/
- $scope.serviceCategories = serviceCategories;
+ /** The columns of the ag-grid table */
+ $scope.columns = [
+ {
+ headerName: "Name",
+ field: "name",
+ hide: false,
+ },
+ {
+ headerName: "Last Updated",
+ field: "lastUpdated",
+ hide: true,
+ filter: "agDateColumnFilter",
+ },
+ ];
- $scope.editServiceCategory = function(name) {
- locationUtils.navigateToPath('/service-categories/edit?name=' + encodeURIComponent(name));
- };
+ /** @type {import("../agGrid/CommonGridController").CGC.DropDownOption[]} */
+ $scope.dropDownOptions = [
+ {
+ name: "createServiceCategoryMenuItem",
+ href: "#!/service-categories/new",
+ text: "Create New Service Category",
+ type: 2,
+ },
+ ];
- $scope.createServiceCategory = function() {
- locationUtils.navigateToPath('/service-categories/new');
+ /** Reloads all resolved data for the view. */
+ $scope.refresh = () => {
+ $state.reload();
};
- $scope.refresh = function() {
- $state.reload(); // reloads all the resolves for the view
+ /** Options, configuration, data and callbacks for the ag-grid table. */
+ /** @type {import("../agGrid/CommonGridController").CGC.GridSettings} */
+ $scope.gridOptions = {
+ onRowClick: (row) => {
+ locationUtils.navigateToPath(
+ `/service-categories/edit?name=${encodeURIComponent(
+ row.data.name
+ )}`
+ );
+ },
};
- angular.element(document).ready(function () {
- $('#serviceCategoriesTable').dataTable({
- "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
- "iDisplayLength": 25,
- "aaSorting": []
- });
- });
-
+ $scope.serviceCategories = serviceCategories.map((serviceCategory) => ({
+ ...serviceCategory,
+ lastUpdated: new Date(
+ serviceCategory.lastUpdated.replace(" ", "T").replace("+00", "Z")
+ ),
+ }));
};
-TableServiceCategoriesController.$inject = ['serviceCategories', '$scope', '$state', 'locationUtils'];
+TableServiceCategoriesController.$inject = [
+ "serviceCategories",
+ "$scope",
+ "$state",
+ "locationUtils",
+];
module.exports = TableServiceCategoriesController;
diff --git a/traffic_portal/app/src/common/modules/table/serviceCategories/table.serviceCategories.tpl.html b/traffic_portal/app/src/common/modules/table/serviceCategories/table.serviceCategories.tpl.html
index 9b95deadf4..ef22b60b97 100644
--- a/traffic_portal/app/src/common/modules/table/serviceCategories/table.serviceCategories.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/serviceCategories/table.serviceCategories.tpl.html
@@ -18,30 +18,13 @@ under the License.
-->
<div class="x_panel">
- <div class="x_title">
- <ol class="breadcrumb pull-left">
- <li class="active">Service Categories</li>
- </ol>
- <div class="pull-right">
- <button name="createServiceCategoryButton" class="btn btn-primary" title="Create Service Category" ng-click="createServiceCategory()"><i class="fa fa-plus"></i></button>
- <button type=button class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
- </div>
- <div class="clearfix"></div>
- </div>
- <div class="x_content">
- <br>
- <table id="serviceCategoriesTable" class="table responsive-utilities jambo_table">
- <thead>
- <tr class="headings">
- <th>Name</th>
- </tr>
- </thead>
- <tbody>
- <tr ng-click="editServiceCategory(sc.name)" ng-repeat="sc in ::serviceCategories">
- <td name="name" data-search="^{{::sc.name}}$">{{::sc.name}}</td>
- </tr>
- </tbody>
- </table>
- </div>
+ <common-grid-controller
+ table-title="Service Categories"
+ table-name="serviceCategories"
+ options="gridOptions"
+ data="serviceCategories"
+ columns="columns"
+ drop-down-options="dropDownOptions"
+ >
+ </common-grid-controller>
</div>
-
diff --git a/traffic_portal/test/integration/PageObjects/ServiceCategories.po.ts b/traffic_portal/test/integration/PageObjects/ServiceCategories.po.ts
index bac32353e7..f5247c1926 100644
--- a/traffic_portal/test/integration/PageObjects/ServiceCategories.po.ts
+++ b/traffic_portal/test/integration/PageObjects/ServiceCategories.po.ts
@@ -16,104 +16,96 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { browser, by, element } from 'protractor';
+import { by, element } from "protractor";
-import { randomize } from '../config';
-import { BasePage } from './BasePage.po';
-import { SideNavigationPage } from './SideNavigationPage.po';
+import { randomize } from "../config";
+import { SideNavigationPage } from "./SideNavigationPage.po";
interface CreateServiceCategory {
Name: string;
- validationMessage?: string;
}
interface UpdateServiceCategory {
description: string;
NewName: string;
- validationMessage?: string;
}
interface DeleteServiceCategory {
Name: string;
- validationMessage?: string;
}
-export class ServiceCategoriesPage extends BasePage {
-
- private btnCreateServiceCategories = element(by.name("createServiceCategoryButton"));
- private txtSearch = element(by.id('serviceCategoriesTable_filter')).element(by.css('label input'));
- private txtName = element(by.id('name'));
-
- private btnDelete = element(by.buttonText('Delete'));
- private txtConfirmName = element(by.name('confirmWithNameInput'));
- private randomize = randomize;
-
+export class ServiceCategoriesPage extends SideNavigationPage {
+ private txtName = element(by.name("name"));
async OpenServicesMenu() {
- let snp = new SideNavigationPage();
- await snp.ClickServicesMenu();
+ await this.ClickServicesMenu();
}
+ /**
+ * Navigates the browser to the Service Categories table page.
+ */
async OpenServiceCategoriesPage() {
- let snp = new SideNavigationPage();
- await snp.NavigateToServiceCategoriesPage();
+ await this.NavigateToServiceCategoriesPage();
}
- public async CreateServiceCategories(serviceCategories: CreateServiceCategory): Promise<boolean> {
- let result = false;
- let basePage = new BasePage();
- await this.btnCreateServiceCategories.click();
- await this.txtName.sendKeys(serviceCategories.Name + this.randomize);
- await basePage.ClickCreate();
- result = await basePage.GetOutputMessage().then(function (value) {
- if (value.indexOf(serviceCategories.validationMessage ?? "") > -1) {
- return true;
- } else {
- return false;
- }
- })
- return result;
+ public async CreateServiceCategories(
+ serviceCategories: CreateServiceCategory,
+ outputMessage: string
+ ): Promise<boolean> {
+ await this.OpenServiceCategoriesPage();
+ await element(by.buttonText("More")).click();
+ await element(by.linkText("Create New Service Category")).click();
+ this.txtName.sendKeys(serviceCategories.Name + randomize);
+ await this.ClickCreate();
+ return this.GetOutputMessage().then(
+ (v) => v.indexOf(outputMessage ?? "") > -1
+ );
}
- public async SearchServiceCategories(nameServiceCategories: string): Promise<boolean> {
- let name = nameServiceCategories + this.randomize;
- await this.txtSearch.clear();
- await this.txtSearch.sendKeys(name);
- if (await browser.isElementPresent(element(by.xpath("//td[@data-search='^" + name + "$']"))) == true) {
- await element(by.xpath("//td[@data-search='^" + name + "$']")).click();
- return true;
- }
- return false;
+ public async SearchServiceCategories(
+ nameServiceCategories: string
+ ): Promise<void> {
+ nameServiceCategories += randomize;
+ await this.OpenServiceCategoriesPage();
+ const searchInput = element(by.id("quickSearch"));
+ await searchInput.clear();
+ await searchInput.sendKeys(nameServiceCategories);
+ await element(
+ by.cssContainingText("span", nameServiceCategories)
+ ).click();
}
- public async UpdateServiceCategories(serviceCategories: UpdateServiceCategory): Promise<boolean | undefined> {
- let basePage = new BasePage();
+ public async UpdateServiceCategories(
+ serviceCategories: UpdateServiceCategory,
+ outputMessage: string
+ ): Promise<boolean | undefined> {
switch (serviceCategories.description) {
case "update service categories name":
await this.txtName.clear();
- await this.txtName.sendKeys(serviceCategories.NewName + this.randomize);
- await basePage.ClickUpdate();
+ await this.txtName.sendKeys(
+ serviceCategories.NewName + randomize
+ );
+ await this.ClickUpdate();
break;
default:
return undefined;
}
- return await basePage.GetOutputMessage().then(value => serviceCategories.validationMessage === value || (serviceCategories.validationMessage !== undefined && value.includes(serviceCategories.validationMessage)));
+ return await this.GetOutputMessage().then(
+ (v) =>
+ outputMessage === v ||
+ (outputMessage !== undefined && v.includes(outputMessage))
+ );
}
- public async DeleteServiceCategories(serviceCategories: DeleteServiceCategory): Promise<boolean> {
- let name = serviceCategories.Name + this.randomize;
- let result = false;
- let basePage = new BasePage();
- await this.btnDelete.click();
- await this.txtConfirmName.sendKeys(name);
- await basePage.ClickDeletePermanently();
- result = await basePage.GetOutputMessage().then(function (value) {
- if (value.indexOf(serviceCategories.validationMessage ?? "") > -1) {
- return true;
- } else {
- return false;
- }
- })
- return result;
-
+ public async DeleteServiceCategories(
+ serviceCategories: DeleteServiceCategory,
+ outputMessage: string
+ ): Promise<boolean> {
+ const name = serviceCategories.Name + randomize;
+ await element(by.buttonText("Delete")).click();
+ await element(by.name("confirmWithNameInput")).sendKeys(name);
+ await this.ClickDeletePermanently();
+ return this.GetOutputMessage().then(
+ (v) => v.indexOf(outputMessage ?? "") > -1
+ );
}
}
diff --git a/traffic_portal/test/integration/specs/ServiceCategories.spec.ts b/traffic_portal/test/integration/specs/ServiceCategories.spec.ts
index fdbcd6b3fb..3da4587147 100644
--- a/traffic_portal/test/integration/specs/ServiceCategories.spec.ts
+++ b/traffic_portal/test/integration/specs/ServiceCategories.spec.ts
@@ -16,65 +16,84 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { browser } from 'protractor';
+import { browser } from "protractor";
-import { LoginPage } from '../PageObjects/LoginPage.po';
-import { TopNavigationPage } from '../PageObjects/TopNavigationPage.po';
+import { LoginPage } from "../PageObjects/LoginPage.po";
+import { TopNavigationPage } from "../PageObjects/TopNavigationPage.po";
import { api } from "../config";
-import { ServiceCategoriesPage } from '../PageObjects/ServiceCategories.po';
+import { ServiceCategoriesPage } from "../PageObjects/ServiceCategories.po";
import { serviceCategories } from "../Data";
const loginPage = new LoginPage();
const topNavigation = new TopNavigationPage();
const serviceCategoriesPage = new ServiceCategoriesPage();
-describe('Setup API for Service Categories Test', () => {
- it('Setup', async () => {
+describe("Setup API for Service Categories Test", () => {
+ it("Setup", async () => {
await api.UseAPI(serviceCategories.setup);
});
});
-serviceCategories.tests.forEach(async serviceCategoriesData => {
- serviceCategoriesData.logins.forEach(login => {
+serviceCategories.tests.forEach(async (serviceCategoriesData) => {
+ serviceCategoriesData.logins.forEach((login) => {
describe(`Traffic Portal - ServiceCategories - ${login.description}`, () => {
- it('can login', async () => {
+ it("can login", async () => {
browser.get(browser.params.baseUrl);
await loginPage.Login(login);
expect(await loginPage.CheckUserName(login)).toBeTruthy();
});
- it('can open service categories page', async () => {
+ it("can open service categories page", async () => {
await serviceCategoriesPage.OpenServicesMenu();
await serviceCategoriesPage.OpenServiceCategoriesPage();
});
- serviceCategoriesData.add.forEach(add => {
+ serviceCategoriesData.add.forEach((add) => {
it(add.description, async () => {
- expect(await serviceCategoriesPage.CreateServiceCategories(add)).toBeTruthy();
+ expect(
+ await serviceCategoriesPage.CreateServiceCategories(
+ add,
+ add.validationMessage
+ )
+ ).toBeTruthy();
await serviceCategoriesPage.OpenServiceCategoriesPage();
});
});
- serviceCategoriesData.update.forEach(update => {
+ serviceCategoriesData.update.forEach((update) => {
it(update.description, async () => {
- await serviceCategoriesPage.SearchServiceCategories(update.Name);
- expect(await serviceCategoriesPage.UpdateServiceCategories(update)).toBeTruthy();
+ await serviceCategoriesPage.SearchServiceCategories(
+ update.Name
+ );
+ expect(
+ await serviceCategoriesPage.UpdateServiceCategories(
+ update,
+ update.validationMessage
+ )
+ ).toBeTruthy();
await serviceCategoriesPage.OpenServiceCategoriesPage();
});
});
- serviceCategoriesData.remove.forEach(remove => {
+ serviceCategoriesData.remove.forEach((remove) => {
it(remove.description, async () => {
- await serviceCategoriesPage.SearchServiceCategories(remove.Name);
- expect(await serviceCategoriesPage.DeleteServiceCategories(remove)).toBeTruthy();
+ await serviceCategoriesPage.SearchServiceCategories(
+ remove.Name
+ );
+ expect(
+ await serviceCategoriesPage.DeleteServiceCategories(
+ remove,
+ remove.validationMessage
+ )
+ ).toBeTruthy();
await serviceCategoriesPage.OpenServiceCategoriesPage();
});
});
- it('can logout', async () => {
+ it("can logout", async () => {
expect(await topNavigation.Logout()).toBeTruthy();
});
});
});
});
-describe('Clean Up API for Service Categories Test', () => {
- it('Cleanup', async () => {
+describe("Clean Up API for Service Categories Test", () => {
+ it("Cleanup", async () => {
await api.UseAPI(serviceCategories.cleanup);
});
});