Initial Drupal 11 with DDEV setup

This commit is contained in:
gluebox
2025-10-08 11:39:17 -04:00
commit 89ef74b305
25344 changed files with 2599172 additions and 0 deletions

View File

@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Drupal\workspaces_ui\Hook;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
/**
* Hook implementations for the workspaces_ui module.
*/
class WorkspacesUiHooks {
use StringTranslationTrait;
/**
* Implements hook_help().
*/
#[Hook('help')]
public function help($route_name, RouteMatchInterface $route_match): ?string {
switch ($route_name) {
// Main module help for the Workspaces UI module.
case 'help.page.workspaces_ui':
$output = '';
$output .= '<h2>' . $this->t('About') . '</h2>';
$output .= '<p>' . $this->t('The Workspaces UI module provides an interface for managing workspaces for the <a href=":workspaces_module">Workspaces module</a>. For more information, see the <a href=":workspaces">online documentation for the Workspaces UI module</a>.', [':workspaces_module' => Url::fromRoute('help.page', ['name' => 'workspaces'])->toString(), ':workspaces' => 'https://www.drupal.org/docs/8/core/modules/workspace/overview']) . '</p>';
return $output;
}
return NULL;
}
/**
* Implements hook_toolbar().
*/
#[Hook('toolbar')]
public function toolbar(): array {
$items['workspace'] = [
'#cache' => [
'contexts' => [
'user.permissions',
],
],
];
$current_user = \Drupal::currentUser();
if (!$current_user->hasPermission('administer workspaces')
&& !$current_user->hasPermission('view own workspace')
&& !$current_user->hasPermission('view any workspace')) {
return $items;
}
/** @var \Drupal\workspaces\WorkspaceInterface $active_workspace */
$active_workspace = \Drupal::service('workspaces.manager')->getActiveWorkspace();
$items['workspace'] += [
'#type' => 'toolbar_item',
'tab' => [
'#lazy_builder' => ['workspaces.lazy_builders:renderToolbarTab', []],
'#create_placeholder' => TRUE,
'#lazy_builder_preview' => [
'#type' => 'link',
'#title' => $active_workspace ? $active_workspace->label() : $this->t('Live'),
'#url' => Url::fromRoute('entity.workspace.collection'),
'#attributes' => [
'class' => ['toolbar-tray-lazy-placeholder-link'],
],
],
],
'#wrapper_attributes' => [
'class' => ['workspaces-toolbar-tab'],
],
'#weight' => 500,
];
// Add a special class to the wrapper if we don't have an active workspace
// so we can highlight it with a different color.
if (!$active_workspace) {
$items['workspace']['#wrapper_attributes']['class'][] = 'workspaces-toolbar-tab--is-default';
}
// \Drupal\toolbar\Element\ToolbarItem::preRenderToolbarItem adds an
// #attributes property to each toolbar item's tab child automatically. Lazy
// builders don't support an #attributes property so we need to add another
// render callback to remove the #attributes property. We start by adding
// the defaults, and then we append our own pre render callback.
$items['workspace'] += \Drupal::service('plugin.manager.element_info')->getInfo('toolbar_item');
$items['workspace']['#pre_render'][] = 'workspaces.lazy_builders:removeTabAttributes';
return $items;
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Drupal\workspaces_ui\Routing;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
/**
* Subscriber for Workspaces routes.
*/
class RouteSubscriber extends RouteSubscriberBase {
/**
* {@inheritdoc}
*/
protected function alterRoutes(RouteCollection $collection): void {
// Re-enable access to the workspace routes.
$workspaces_routes = [
'entity.workspace.collection',
'entity.workspace.activate_form',
'entity.workspace.publish_form',
'entity.workspace.merge_form',
'workspaces.switch_to_live',
];
foreach ($workspaces_routes as $workspace_route) {
if ($route = $collection->get($workspace_route)) {
$requirements = $route->getRequirements();
unset($requirements['_access']);
$route->setRequirements($requirements);
}
}
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\workspaces_ui\Functional;
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
/**
* Generic module test for workspaces_ui.
*
* @group workspaces_ui
*/
class GenericTest extends GenericModuleTestBase {
}

View File

@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\workspaces_ui\FunctionalJavascript;
use Drupal\Tests\system\FunctionalJavascript\OffCanvasTestBase;
use Drupal\workspaces\Entity\Workspace;
/**
* Tests workspace settings stray integration.
*
* @group workspaces
* @group workspaces_ui
*/
class WorkspaceToolbarIntegrationTest extends OffCanvasTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['toolbar', 'workspaces', 'workspaces_ui'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$admin_user = $this->drupalCreateUser([
'administer workspaces',
'access toolbar',
'access administration pages',
]);
$this->drupalLogin($admin_user);
Workspace::create(['id' => 'stage', 'label' => 'Stage'])->save();
}
/**
* Tests workspace canvas can be toggled with JavaScript.
*/
public function testWorkspaceCanvasToggling(): void {
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
// Set size for horizontal toolbar.
$this->getSession()->resizeWindow(1200, 600);
$this->drupalGet('<front>');
// Wait for toolbar to appear.
$this->assertNotEmpty($assert_session->waitForElement('css', 'body.toolbar-horizontal'));
// Open workspace canvas.
$page->clickLink('Switch workspace');
$this->waitForOffCanvasToOpen('top');
$assert_session->elementExists('css', '.workspaces-dialog');
// Close Canvas.
$page->pressButton('Close');
$this->waitForOffCanvasToClose();
$assert_session->assertNoElementAfterWait('css', '.workspaces-dialog');
}
/**
* Tests workspace switch and landing page behavior.
*/
public function testWorkspaceSwitch(): void {
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
// Wait for toolbar to appear.
$this->getSession()->resizeWindow(1200, 600);
$this->drupalGet('admin');
// Wait for toolbar to appear.
$this->assertNotEmpty($assert_session->waitForElement('css', 'body.toolbar-horizontal'));
// Open workspace canvas.
$page->clickLink('Switch workspace');
$this->waitForOffCanvasToOpen('top');
// Click 'stage' workspace and confirm switch.
$page->clickLink('Stage');
$this->assertElementVisibleAfterWait('css', '.workspace-activate-form.workspace-confirm-form');
$page->find('css', '.ui-dialog-buttonset .button--primary')->click();
$assert_session->statusMessageContainsAfterWait('Stage is now the active workspace.', 'status');
// Make sure we stay on same page after switch.
$assert_session->addressEquals('admin');
}
}

View File

@ -0,0 +1,8 @@
name: 'Workspaces UI'
type: module
description: 'Provides a user interface for creating and managing workspaces.'
version: VERSION
package: Core
configure: entity.workspace.collection
dependencies:
- drupal:workspaces

View File

@ -0,0 +1,5 @@
services:
_defaults:
autoconfigure: true
workspaces_ui.route_subscriber:
class: Drupal\workspaces_ui\Routing\RouteSubscriber