Skip to content
Snippets Groups Projects
Commit 570b190d authored by utkarsh_33's avatar utkarsh_33 Committed by Tim Plunkett
Browse files

Issue #3484474 by utkarsh_33, zetagraph, phenaproxima, rkoller,...

Issue #3484474 by utkarsh_33, zetagraph, phenaproxima, rkoller, chrisfromredfin, narendrar: Change UI for the install queue to match bulk operations
parent e7a26726
No related branches found
No related tags found
1 merge request!634#3484474:Change UI for the install queue to match bulk operations
Pipeline #407335 passed with warnings
......@@ -14,3 +14,4 @@ CURLOPT
RETURNTRANSFER
varchar
techdebt
darkmode
......@@ -1039,6 +1039,51 @@
}
}
/* Prefixing #project-browser ensures more specific CSS styling. Without it, these styles are not applied. */
#project-browser .pb-install_bulk_actions {
margin-top: 1rem;
animation: none;
border-radius: 0.5rem;
}
#project-browser .install_button {
padding: 5px;
color: var(--color-white);
background-color: var(--color-blue-400);
}
#project-browser .install_button:hover {
background-color: var(--color-blue-500);
}
#project-browser .install_button_common {
height: 34px;
margin-left: 20px;
font-size: 0.79rem;
margin-block: 0;
}
.select_button {
padding: calc(0.5rem - 1px) calc(1rem - 1px);
cursor: pointer;
color: var(--color-blue-600);
border: 2px solid var(--color-blue-600);
border-radius: 2px;
background-color: #fff;
font-size: 0.79rem;
font-weight: bold;
}
.select_button:hover {
color: var(--color-blue-650);
border: 2px solid var(--color-blue-650);
}
.select_button:active {
color: var(--color-blue-700);
border: 2px solid var(--color-blue-700);
}
.project_status-indicator__label {
margin-bottom: 5px;
margin-left: 5px;
......@@ -1046,3 +1091,21 @@
font-size: 16px;
font-weight: 700;
}
#project-browser .clear_button {
margin-block: 0;
margin-inline: 0;
height: 34px;
margin-left: 10px;
padding: 5px;
font-size: 0.79rem;
}
/* @todo Remove this class, and its uses in the Svelte app, when we have a cleaner
* way to ensure that it looks good in Gin. */
#project-browser .views-bulk-actions-gin {
background: rgba(var(--gin-color-sticky-rgb), 0.9);
}
.views-bulk-actions__item-gin {
color: var(--gin-color-text-light);
}
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
<script>
import { get } from 'svelte/store';
import { queueList, updated } from './stores';
import { queueList, updated, clearQueue } from './stores';
import { processQueue } from './QueueProcessor';
import Loading from './Loading.svelte';
import LoadingEllipsis from './Project/LoadingEllipsis.svelte';
......@@ -8,9 +7,13 @@
let loading = false;
const { Drupal } = window;
let buttonClasses;
let bulkActionClasses = '';
const currentQueueList = get(queueList) || [];
const queueLength = Object.keys(currentQueueList).length;
$: currentQueueList = $queueList || [];
$: queueLength = currentQueueList.length;
let projectsToActivate = [];
let projectsToDownloadAndActivate = [];
const handleClick = async () => {
loading = true;
......@@ -18,23 +21,65 @@
loading = false;
$updated = new Date().getTime();
};
function clearSelection() {
projectsToDownloadAndActivate = [];
projectsToActivate = [];
clearQueue();
$updated = new Date().getTime();
}
$: {
// @see css/pb.css
if ('gin' in drupalSettings) {
buttonClasses = 'button--small button button--primary';
if (drupalSettings.gin.darkmode !== '1') {
bulkActionClasses = 'views-bulk-actions-gin';
}
} else {
buttonClasses = 'install_button';
}
}
</script>
<button
class="project__action_button project__action_button--fixed"
on:click={handleClick}
disabled={loading}
<div
class=" views-bulk-actions pb-install_bulk_actions {bulkActionClasses}"
data-drupal-sticky-vbo={queueLength !== 0}
>
{#if loading}
<Loading />
<LoadingEllipsis
message={Drupal.formatPlural(
<div
class="views-bulk-actions__item
views-bulk-actions__item--status views-bulk-actions__item-gin"
>
{#if queueLength === 0}
{Drupal.t('No projects selected')}
{:else}
{Drupal.formatPlural(
queueLength,
'Installing 1 project',
'Installing @count projects',
'1 project selected',
'@count projects selected',
)}
/>
{:else}
{Drupal.t('Install selected projects')}
{/if}
</div>
<button
class="project__action_button install_button_common {buttonClasses}"
on:click={handleClick}
>
{#if loading}
<Loading />
<LoadingEllipsis
message={Drupal.formatPlural(
queueLength,
'Installing 1 project',
'Installing @count projects',
)}
/>
{:else}
{Drupal.t('Install selected projects')}
{/if}
</button>
{#if queueLength !== 0}
<button class="button clear_button" on:click={clearSelection}>
{Drupal.t('Clear selection')}
</button>
{/if}
</button>
</div>
......@@ -3,6 +3,10 @@
export let click = () => {};
</script>
<button on:click={click} class="project__action_button" {...$$restProps}>
<button
on:click={click}
class="pb__action_button select_button"
{...$$restProps}
>
<slot />
</button>
......@@ -5,7 +5,6 @@
import Pagination from './Pagination.svelte';
import Project from './Project/Project.svelte';
import { numberFormatter } from './util';
import ProcessQueueButton from './ProcessQueueButton.svelte';
import {
filters,
rowsCount,
......@@ -60,14 +59,6 @@
});
let searchComponent;
function hasItemsInQueue() {
let hasItems = false;
queueList.subscribe((currentList) => {
hasItems = currentList.length > 0;
})();
return hasItems;
}
/**
* Load data from Drupal.org API.
*
......@@ -354,9 +345,6 @@
{#each rows as row, index (row)}
<Project {toggleView} project={row} />
{/each}
{#if PACKAGE_MANAGER.available && hasItemsInQueue() && (MAX_SELECTIONS === null || MAX_SELECTIONS > 1)}
<ProcessQueueButton />
{/if}
{/key}
<div slot="bottom">
<Pagination
......
......@@ -2,12 +2,14 @@
import Search from './Search/Search.svelte';
import Loading from './Loading.svelte';
import { pageSize, mediaQueryValues } from './stores';
import ProcessQueueButton from './ProcessQueueButton.svelte';
export { Search };
</script>
<script>
import { setContext } from 'svelte';
import { PACKAGE_MANAGER } from './constants';
const { Drupal } = window;
......@@ -68,6 +70,9 @@
>
<slot rows={visibleRows} />
</ul>
{#if PACKAGE_MANAGER.available}
<ProcessQueueButton />
{/if}
{/if}
<slot name="foot" />
</div>
......
......@@ -169,6 +169,11 @@ export const processQueue = async () => {
const currentQueueList = get(queueList) || [];
const projectsToActivate = [];
const projectsToDownloadAndActivate = [];
if (currentQueueList.length === 0) {
new Drupal.Message().add(Drupal.t('No projects selected'), { type: 'error' });
window.scrollTo({ top: 0, behavior: 'smooth' });
return;
}
for (const proj of currentQueueList) {
if (proj.status === 'absent') {
......
......@@ -79,7 +79,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->drupalGet('admin/modules/browse/project_browser_test_mock');
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button");
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button");
$this->assertNotEmpty($download_button);
$this->assertSame('Install Cream cheese on a bagel', $download_button->getText());
$download_button->click();
......@@ -105,7 +105,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->drupalGet('admin/modules/browse/project_browser_test_mock');
$this->svelteInitHelper('text', 'Pinky and the Brain');
$pinky_brain_selector = '#project-browser .pb-layout__main ul > li:nth-child(2)';
$action_button = $assert_session->waitForElementVisible('css', "$pinky_brain_selector button.project__action_button");
$action_button = $assert_session->waitForElementVisible('css', "$pinky_brain_selector button.pb__action_button");
$this->assertNotEmpty($action_button);
$this->assertSame('Install Pinky and the Brain', $action_button->getText());
$action_button->click();
......@@ -191,7 +191,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->svelteInitHelper('text', 'Pinky and the Brain');
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button");
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button");
$this->assertNotEmpty($download_button);
$this->assertSame('Install Cream cheese on a bagel', $download_button->getText());
$this->drupalGet('/admin/config/development/project_browser');
......@@ -202,7 +202,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->drupalGet('admin/modules/browse/project_browser_test_mock');
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
$action_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button");
$action_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button");
$this->assertNotEmpty($action_button);
$this->assertSame('View Commands for Cream cheese on a bagel', $action_button->getText());
}
......@@ -226,7 +226,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
// Try beginning another install while one is in progress, but not yet in
// the applying stage.
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.project__action_button");
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.pb__action_button");
$cream_cheese_button?->click();
$this->assertTrue($assert_session->waitForText('The process for adding projects is locked, but that lock has expired. Use unlock link to unlock the process and try to add the project again.'));
......@@ -235,7 +235,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->clickWithWait('#ui-id-1 > p > a');
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
// Try beginning another install after breaking lock.
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.project__action_button");
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.pb__action_button");
$cream_cheese_button?->click();
$installed_action = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector .project_status-indicator", 30000);
$assert_session->waitForText('Cream cheese on a bagel is Installed');
......@@ -266,14 +266,14 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
// Try beginning another install while one is in progress, but not yet in
// the applying stage.
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.project__action_button");
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.pb__action_button");
$cream_cheese_button?->click();
$this->assertTrue($assert_session->waitForText('The process for adding projects is locked, but that lock has expired. Use unlock link to unlock the process and try to add the project again.'));
// Click Unlock Install Stage link.
$this->clickWithWait('#ui-id-1 > p > a');
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
// Try beginning another install after breaking lock.
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.project__action_button");
$cream_cheese_button = $page->find('css', "$cream_cheese_module_selector button.pb__action_button");
$cream_cheese_button?->click();
$installed_action = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector .project_status-indicator", 30000);
$assert_session->waitForText('Cream cheese on a bagel is Installed');
......@@ -295,7 +295,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
$assert_session->statusMessageContains("Simulate an error message for the project browser.", 'error');
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$download_button_text = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button")
$download_button_text = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button")
?->getText();
$this->assertSame('View Commands for Cream cheese on a bagel', $download_button_text);
}
......@@ -314,7 +314,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
$assert_session->statusMessageContains("Simulate a warning message for the project browser.", 'warning');
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button");
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button");
$this->assertNotEmpty($download_button);
$this->assertSame('Install Cream cheese on a bagel', $download_button->getText());
$download_button->click();
......@@ -364,13 +364,13 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$assert_session = $this->assertSession();
$this->drupalGet('project-browser/project_browser_test_mock');
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
$assert_session->buttonNotExists('Install selected projects');
$this->svelteInitHelper('text', 'Kangaroo');
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$select_button1 = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button");
$select_button1 = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button");
$this->assertNotEmpty($select_button1);
$this->assertSame('Select Cream cheese on a bagel', $select_button1->getText());
$select_button1->click();
$this->assertSame('Select Cream cheese on a bagel', $select_button1?->getText());
$select_button1?->click();
$was_selected = $select_button1->waitFor(10, fn ($button) => $button->getText() === 'Deselect Cream cheese on a bagel');
$this->assertTrue($was_selected);
......@@ -380,16 +380,16 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->assertNotEmpty($assert_session->waitForButton('Install selected projects'));
$kangaroo_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(4)';
$select_button2 = $assert_session->waitForElementVisible('css', "$kangaroo_module_selector button.project__action_button");
$select_button2 = $assert_session->waitForElementVisible('css', "$kangaroo_module_selector button.pb__action_button");
$this->assertNotEmpty($select_button2);
$this->assertSame('Select Kangaroo', $select_button2->getText());
$select_button2->click();
$this->assertSame('Select Kangaroo', $select_button2?->getText());
$select_button2?->click();
$was_deselected = $select_button2->waitFor(10, function ($button) {
return $button->getText() === 'Deselect Kangaroo';
});
$this->assertTrue($was_deselected);
// Select button gets disabled on reaching maximum limit.
$assert_session->elementAttributeExists('css', '#project-browser .pb-layout__main ul > li:nth-child(3) button.project__action_button', 'disabled');
$assert_session->elementAttributeExists('css', '#project-browser .pb-layout__main ul > li:nth-child(3) button.pb__action_button', 'disabled');
$this->assertNotEmpty($assert_session->waitForButton('Install selected projects'));
$page->pressButton('Install selected projects');
......@@ -420,18 +420,15 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->container->get('module_installer')->install(['project_browser_devel'], TRUE);
$this->drupalGet('project-browser/project_browser_test_mock');
$assert_session->buttonNotExists('Install selected projects');
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$select_button1 = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button");
$select_button1 = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button");
$select_button1->click();
$this->assertNotEmpty($assert_session->waitForButton('Install selected projects'));
$this->drupalGet('project-browser/random_data');
$assert_session->buttonNotExists('Install selected projects');
$random_data = '#project-browser .pb-layout__main ul > li:nth-child(2)';
$select_button2 = $assert_session->waitForElementVisible('css', "$random_data button.project__action_button");
$select_button2 = $assert_session->waitForElementVisible('css', "$random_data button.pb__action_button");
$this->assertNotEmpty($select_button2);
$select_button2->click();
$select_button2?->click();
$this->assertNotEmpty($assert_session->waitForButton('Install selected projects'));
}
......@@ -448,7 +445,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->drupalGet('admin/modules/browse/project_browser_test_mock');
$this->svelteInitHelper('text', 'Cream cheese on a bagel');
$cream_cheese_module_selector = '#project-browser .pb-layout__main ul > li:nth-child(1)';
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.project__action_button");
$download_button = $assert_session->waitForElementVisible('css', "$cream_cheese_module_selector button.pb__action_button");
$this->assertNotEmpty($download_button);
$this->assertSame('Install Cream cheese on a bagel', $download_button->getText());
$download_button->click();
......@@ -473,15 +470,15 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
$this->svelteInitHelper('text', 'Helvetica');
$assert_session->waitForButton('Helvetica')?->click();
// Click select button in modal.
$assert_session->elementExists('css', '.pb-detail-modal__sidebar_element button.project__action_button')->click();
$assert_session->elementExists('css', '.pb-detail-modal__sidebar_element button.pb__action_button')->click();
$this->assertSame('Deselect Helvetica',
$assert_session->elementExists('css', '.pb-detail-modal__sidebar_element button.project__action_button')->getText());
$assert_session->elementExists('css', '.pb-detail-modal__sidebar_element button.pb__action_button')->getText());
// Close the modal.
$assert_session->waitForButton('Close')?->click();
$assert_session->elementNotExists('xpath', '//span[contains(@class, "ui-dialog-title") and text()="Helvetica"]');
$select_button = $assert_session->waitForElementVisible('css', "#project-browser .pb-layout__main ul > li:nth-child(7) button.project__action_button");
$select_button = $assert_session->waitForElementVisible('css', "#project-browser .pb-layout__main ul > li:nth-child(7) button.pb__action_button");
$this->assertNotEmpty($select_button);
// Asserts that the project is selected.
$was_selected = $select_button->waitFor(10, fn ($button) => $button->getText() === 'Deselect Helvetica');
......
......@@ -598,7 +598,7 @@ class ProjectBrowserUiTest extends WebDriverTestBase {
$assert_session->waitForButton('Helvetica')?->click();
// Check the detail modal displays.
$assert_session->waitForElementVisible('xpath', '//span[contains(@class, "ui-dialog-title") and text()="Helvetica"]');
$assert_session->elementExists('css', 'button.project__action_button');
$assert_session->elementExists('css', 'button.pb__action_button');
// Close the modal.
$assert_session->waitForButton('Close')?->click();
$assert_session->elementNotExists('xpath', '//span[contains(@class, "ui-dialog-title") and text()="Helvetica"]');
......@@ -614,7 +614,7 @@ class ProjectBrowserUiTest extends WebDriverTestBase {
$assert_session->waitForButton('Helvetica')?->click();
// Check the detail modal displays.
$assert_session->waitForElementVisible('xpath', '//span[contains(@class, "ui-dialog-title") and text()="Helvetica"]');
$assert_session->elementExists('css', 'button.project__action_button');
$assert_session->elementExists('css', 'button.pb__action_button');
// Close the modal and check it no longer exists.
$assert_session->waitForButton('Close')?->click();
$assert_session->elementNotExists('xpath', '//span[contains(@class, "ui-dialog-title") and text()="Helvetica"]');
......@@ -625,7 +625,7 @@ class ProjectBrowserUiTest extends WebDriverTestBase {
$assert_session->elementNotExists('xpath', '//span[contains(@class, "ui-dialog-title") and text()="Octopus"]');
// Check that first detail modal can be reopened.
$assert_session->waitForElementVisible('xpath', '//span[contains(@class, "ui-dialog-title") and text()="Helvetica"]');
$assert_session->elementExists('css', 'button.project__action_button');
$assert_session->elementExists('css', 'button.pb__action_button');
}
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment