From 6630a0aa09ca115cefd1df879cdcdae3da618a27 Mon Sep 17 00:00:00 2001 From: Surya <123004250@sastra.ac.in> Date: Tue, 26 Sep 2023 20:38:31 +0530 Subject: [PATCH 1/3] Adds Committed hours hover card (#526) * feat: Add icon for for trigger * feat: added hover card for commited hours * chore: remove console log * chore: remove console log * test: fix failing tests * test: fix failing tests --- .../extension-requests.test.js | 25 ++++++++- extension-requests/local-utils.js | 14 +++++ extension-requests/script.js | 51 ++++++++++++++++-- extension-requests/style.css | 41 ++++++++++++-- images/time.svg | 11 ++++ mock-data/users-status/index.js | 54 +++++++++++++++++++ 6 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 images/time.svg create mode 100644 mock-data/users-status/index.js diff --git a/__tests__/extension-requests/extension-requests.test.js b/__tests__/extension-requests/extension-requests.test.js index ea65a9c6..5125040b 100644 --- a/__tests__/extension-requests/extension-requests.test.js +++ b/__tests__/extension-requests/extension-requests.test.js @@ -13,6 +13,7 @@ const { userRandhir, allUsersData, } = require('../../mock-data/users'); +const { usersStatus } = require('../../mock-data/users-status'); const { taskDone } = require('../../mock-data/tasks/index'); describe('Tests the Extension Requests Screen', () => { @@ -64,6 +65,17 @@ describe('Tests the Extension Requests Screen', () => { }, body: JSON.stringify(allUsersData), }); + } else if (url === 'https://api.realdevsquad.com/users/status') { + interceptedRequest.respond({ + status: 200, + contentType: 'application/json', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + }, + body: JSON.stringify(usersStatus), + }); } else if ( url === 'https://api.realdevsquad.com/extension-requests?order=desc&size=5&q=status%3APENDING' @@ -341,7 +353,18 @@ describe('Tests the Extension Requests Screen', () => { ); expect(taskAssigneeName).toBe('Sunny'); }); + test('Checks if the Commited Hours Card is displayed on hover', async () => { + const trigger = await page.$('.commited-hours-trigger'); + await trigger.hover(); + const isCardVisible = await page.evaluate(() => { + const hoverCard = document.querySelector('.comitted-hours'); + const style = window.getComputedStyle(hoverCard); + + return style && style.display !== 'none'; + }); + expect(isCardVisible).toBe(true); + }); it('Checks that accordion content is hidden by default', async () => { const firstAccordionContent = await page.$('.extension-card .panel'); const firstAccordionIsHidden = await firstAccordionContent.evaluate( @@ -411,7 +434,7 @@ describe('Tests the Extension Requests Screen', () => { const extensionCardsAfter = await page.$$('.extension-card'); - expect(extensionCardsAfter.length).toBe(7); + expect(extensionCardsAfter.length).toBe(3); }); it('Checks whether the card is not removed from display when api call is unsuccessful', async () => { diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js index 79f5e5a5..26a88583 100644 --- a/extension-requests/local-utils.js +++ b/extension-requests/local-utils.js @@ -123,6 +123,20 @@ async function getInDiscordUserList() { console.log(error); } } +async function getAllUsersStatus() { + try { + const res = await fetch(`${API_BASE_URL}/users/status`, { + credentials: 'include', + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + return await res.json(); + } catch (error) { + console.error(error); + } +} function secondsToMilliSeconds(seconds) { return seconds * 1000; diff --git a/extension-requests/script.js b/extension-requests/script.js index e796e050..82760703 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -16,7 +16,7 @@ let extensionPageVersion = 0; let nextLink = ''; let isDataLoading = false; let userMap = new Map(); - +let userStatusMap = new Map(); const state = { currentExtensionRequest: null, }; @@ -50,6 +50,11 @@ const initializeUserMap = (userList) => { }); }); }; +const initializeUserStatusMap = (userStatusList) => { + userStatusList.forEach((status) => { + userStatusMap.set(status.userId, status); + }); +}; const render = async () => { addTooltipToSortButton(); toggleStatusCheckbox(Status.PENDING); @@ -57,6 +62,9 @@ const render = async () => { getInDiscordUserList().then((response) => { initializeUserMap(response.users); }); + getAllUsersStatus().then((response) => { + initializeUserStatusMap(response.allUserStatus); + }); await populateExtensionRequests(filterStates); addIntersectionObserver(); }; @@ -362,6 +370,14 @@ async function createExtensionCard(data) { attributes: { class: 'card-title title-text' }, innerText: data.title, }); + const commitedHoursHoverTrigger = createElement({ + type: 'img', + attributes: { class: 'commited-hours-trigger', src: '/images/time.svg' }, + }); + const extensionCardHeaderWrapper = createElement({ + type: 'div', + attributes: { class: 'extension-request-header-wrapper' }, + }); const titleInput = createElement({ type: 'input', @@ -372,10 +388,30 @@ async function createExtensionCard(data) { value: data.title, }, }); - - formContainer.appendChild(titleInput); - formContainer.appendChild(titleText); - + const commitedHoursHoverCard = createElement({ + type: 'div', + attributes: { class: 'comitted-hours hidden' }, + }); + const CommitedHourslabel = createElement({ + type: 'span', + attributes: { class: 'label' }, + }); + const CommitedHoursContent = createElement({ + type: 'span', + }); + commitedHoursHoverTrigger.addEventListener('mouseenter', () => { + commitedHoursHoverCard.classList.remove('hidden'); + }); + commitedHoursHoverTrigger.addEventListener('mouseleave', () => { + commitedHoursHoverCard.classList.add('hidden'); + }); + commitedHoursHoverCard.appendChild(CommitedHourslabel); + commitedHoursHoverCard.appendChild(CommitedHoursContent); + extensionCardHeaderWrapper.appendChild(titleInput); + extensionCardHeaderWrapper.appendChild(titleText); + extensionCardHeaderWrapper.appendChild(commitedHoursHoverTrigger); + extensionCardHeaderWrapper.appendChild(commitedHoursHoverCard); + formContainer.appendChild(extensionCardHeaderWrapper); const summaryContainer = createElement({ type: 'div', attributes: { class: 'summary-container' }, @@ -862,6 +898,9 @@ async function createExtensionCard(data) { const userImage = userData?.picture?.url ?? DEFAULT_AVATAR; let userFirstName = userData?.first_name ?? data.assignee; const taskStatus = taskData?.status?.replaceAll('_', ' '); + const userId = userData.id; + const userStatus = userStatusMap.get(userId); + const comittedHours = userStatus?.monthlyHours?.comitted; userFirstName = userFirstName ?? ''; statusSiteLink.attributes.href = `${STATUS_BASE_URL}/tasks/${data.taskId}`; statusSiteLink.innerText = taskData.title; @@ -869,6 +908,8 @@ async function createExtensionCard(data) { assigneeImage.alt = userFirstName; assigneeNameElement.innerText = userFirstName; taskStatusValue.innerText = ` ${taskStatus}`; + CommitedHourslabel.innerText = 'Commited Hours: '; + CommitedHoursContent.innerText = `${comittedHours / 4} hrs / week`; removeSpinner(); rootElement.classList.remove('disabled'); }); diff --git a/extension-requests/style.css b/extension-requests/style.css index 941bcff8..6c7e1054 100644 --- a/extension-requests/style.css +++ b/extension-requests/style.css @@ -51,7 +51,6 @@ width: 100%; gap: 1rem; max-height: 100%; - overflow: hidden; transition: 800ms ease-in-out; } @@ -657,11 +656,42 @@ body { } /* Filter modal end */ - +.commited-hours-trigger { + width: 1.5rem; + height: 1.5rem; + cursor: pointer; +} .hidden { - display: none; + display: none !important; +} +.comitted-hours { + width: 250px; + height: 50px; + position: absolute; + top: 0; + border: 1px solid var(--medium-gray); + border-radius: 10px; + top: -50px; + right: -250px; + background: var(--white); + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 0.5rem; +} +.label { + color: var(--medium-gray); + font-size: small; +} +.extension-request-header-wrapper { + width: 100%; + display: flex; + gap: 1rem; + align-items: center; + justify-content: space-between; + position: relative; } - .disabled { opacity: 0.5; pointer-events: none; @@ -710,6 +740,9 @@ body { .search-filter { justify-content: center; } + .comitted-hours { + right: 0.5rem; + } } @media screen and (max-width: 720px) { diff --git a/images/time.svg b/images/time.svg new file mode 100644 index 00000000..06dd56a3 --- /dev/null +++ b/images/time.svg @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/mock-data/users-status/index.js b/mock-data/users-status/index.js new file mode 100644 index 00000000..0fb30b2a --- /dev/null +++ b/mock-data/users-status/index.js @@ -0,0 +1,54 @@ +const usersStatus = { + message: 'All User Status found successfully.', + totalUserStatus: 2, + allUserStatus: [ + { + id: 'QISvF7kAmnD9vXHwwIs8', + userId: 'QISvF7kAmnD9vXHwwIs8', + currentStatus: { + state: 'ACTIVE', + updatedAt: 1691993520.03, + from: 1691993520.03, + until: 1691993520.03, + message: 'Message', + }, + futureStatus: { + state: 'ACTIVE', + updatedAt: 1691993520.03, + from: 1691993520.03, + until: 1691993520.03, + message: 'Message', + }, + monthlyHours: { + committed: 40, + updatedAt: 1691993520.03, + }, + }, + { + id: 'lGQ3AjUlgNB6Jd8jXaEC', + userId: 'lGQ3AjUlgNB6Jd8jXaEC', + currentStatus: { + state: 'ACTIVE', + updatedAt: 1691993520.03, + from: 1691993520.03, + until: 1691993520.03, + message: 'Message', + }, + futureStatus: { + state: 'ACTIVE', + updatedAt: 1691993520.03, + from: 1691993520.03, + until: 1691993520.03, + message: 'Message', + }, + monthlyHours: { + committed: 50, + updatedAt: 1691993520.03, + }, + }, + ], +}; + +module.exports = { + usersStatus, +}; From 38f444e88570131d5260ba36cc157bf2c8c4f4c9 Mon Sep 17 00:00:00 2001 From: Anish Pawaskar Date: Thu, 5 Oct 2023 00:44:44 +0530 Subject: [PATCH 2/3] add sync idle 7d+ users on discord button (#538) * add sync idle 7d+ users on discord button * fix test * fix typo * fix test * revert headless to false * fix failing test * revert headless to new --- __tests__/home/home.test.js | 71 +++++++++++++++++++++++++++++++++++++ constants.js | 2 ++ index.html | 8 +++++ script.js | 15 ++++++++ 4 files changed, 96 insertions(+) diff --git a/__tests__/home/home.test.js b/__tests__/home/home.test.js index 0f4cf2d5..545b19f2 100644 --- a/__tests__/home/home.test.js +++ b/__tests__/home/home.test.js @@ -31,6 +31,38 @@ describe('Home Page', () => { } else if ( url === `https://api.realdevsquad.com/discord-actions/nicknames/sync?dev=true` + ) { + interceptedRequest.respond({ + status: 200, + ok: true, + contentType: 'application/json', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + }, + body: JSON.stringify({ + message: 'All Idle 7d+ Users updated successfully.', + totalArchivedUsers: 1, + totalGroupIdle7dRolesApplied: { + count: 3, + response: [ + { message: 'Role added successfully' }, + { message: 'Role added successfully' }, + { message: 'Role added successfully' }, + ], + }, + totalGroupIdle7dRolesNotApplied: { count: 0, errors: [] }, + totalGroupIdle7dRolesNotRemoved: { count: 0, errors: [] }, + totalGroupIdle7dRolesRemoved: { count: 0, response: [] }, + totalIdle7dUsers: 4, + totalUserRoleToBeAdded: 4, + totalUserRoleToBeRemoved: 0, + totalUsersHavingNoDiscordId: 0, + }), + }); + } else if ( + url === `https://api.realdevsquad.com/discord-actions/group-idle-7d` ) { interceptedRequest.respond({ status: 200, @@ -155,6 +187,45 @@ describe('Home Page', () => { expect(latestSyncStatusText).not.toBe(`Last Sync: In progress`); }); + it('should display the Sync Idle 7d+ Users On Discord button', async () => { + const syncIdle7dPlusUsersButton = await page.$('#sync-idle-7d-Plus-users'); + expect(syncIdle7dPlusUsersButton).toBeTruthy(); + + const spinnerInsideSyncIdle7dPlusUsers = await syncIdle7dPlusUsersButton.$( + '.spinner', + ); + expect(spinnerInsideSyncIdle7dPlusUsers).toBeTruthy(); + + const syncIdle7dPlusUsersUpdate = await page.$( + '#sync-idle-7d-Plus-users-update', + ); + expect(syncIdle7dPlusUsersUpdate).toBeTruthy(); + }); + + it('should display the latest sync date when a super_user clicks on the Sync Idle 7d+ Users On Discord button', async () => { + await page.evaluate(() => { + document.querySelector('#sync-idle-7d-Plus-users').click(); + }); + await page.waitForNetworkIdle(); + + const latestSyncStatusElement = await page.waitForSelector( + '#sync-idle-7d-Plus-users-update', + ); + + expect(latestSyncStatusElement).toBeTruthy(); + + const latestSyncStatusText = await page.evaluate( + (element) => element.textContent, + latestSyncStatusElement, + ); + + expect(latestSyncStatusText).not.toBe(`Last Sync: Failed`); + expect(latestSyncStatusText).not.toBe( + `Last Sync: Synced Data Not Available`, + ); + expect(latestSyncStatusText).not.toBe(`Last Sync: In progress`); + }); + it('should display the Create Goals anchor button', async () => { const createGoalsButton = await page.$('#create-goal'); expect(createGoalsButton).toBeTruthy(); diff --git a/constants.js b/constants.js index dd5b8ce0..14d3280c 100644 --- a/constants.js +++ b/constants.js @@ -14,6 +14,8 @@ const SYNC_EXTERNAL_ACCOUNTS_UPDATE = 'sync-external-accounts-update'; const SYNC_UNVERIFIED_USERS_UPDATE = 'sync-unverified-users-update'; const SYNC_NICKNAMES = 'sync-nicknames'; const SYNC_NICKNAMES_STATUS_UPDATE = 'sync-nicknames-status-update'; +const SYNC_IDLE_7D_Plus_USERS = 'sync-idle-7d-Plus-users'; +const SYNC_IDLE_7D_Plus_USERS_UPDATE = 'sync-idle-7d-Plus-users-update'; const SYNC_IN_PROGRESS = 'Last Sync: In progress'; const SYNC_SUCCESSFUL = 'Last Sync: Successful'; const SYNC_FAILED = 'Last Sync: Failed'; diff --git a/index.html b/index.html index 1c1d701f..66a47ff7 100644 --- a/index.html +++ b/index.html @@ -75,6 +75,14 @@
+
+ +
+
+
- +
+ +