From 32ec1edba68bda4cc971c6823a019741ba5d5c47 Mon Sep 17 00:00:00 2001
From: Adam G-H <32250-phenaproxima@users.noreply.drupalcode.org>
Date: Mon, 27 Jan 2025 17:13:55 +0000
Subject: [PATCH] Issue #3495112 by phenaproxima, chrisfromredfin, iamdroid:
 Export a coherent set of information about a particular Project Browser
 instance in drupalSettings

---
 project_browser.module                       |  12 +++++++++++-
 src/Element/ProjectBrowser.php               |  15 ++++++++++++++-
 sveltejs/public/build/bundle.js              | Bin 298746 -> 301393 bytes
 sveltejs/public/build/bundle.js.map          | Bin 276232 -> 276876 bytes
 sveltejs/src/App.svelte                      |   5 ++++-
 sveltejs/src/ProjectBrowser.svelte           |   6 +++++-
 sveltejs/src/Search/BooleanFilter.svelte     |   7 ++++---
 sveltejs/src/Search/Search.svelte            |  18 ++++++++----------
 sveltejs/src/main.js                         |   8 ++++++--
 templates/project-browser-main-app.html.twig |   2 +-
 10 files changed, 53 insertions(+), 20 deletions(-)

diff --git a/project_browser.module b/project_browser.module
index 211b4d17c..e168a2f1c 100644
--- a/project_browser.module
+++ b/project_browser.module
@@ -38,7 +38,7 @@ function project_browser_help(string $route_name, RouteMatchInterface $route_mat
 function project_browser_theme(): array {
   return [
     'project_browser_main_app' => [
-      'variables' => [],
+      'render element' => 'element',
     ],
   ];
 }
@@ -59,3 +59,13 @@ function project_browser_project_browser_source_info_alter(array &$definitions):
     ];
   }
 }
+
+/**
+ * Preprocess function for the project_browser_main_app theme hook.
+ *
+ * @param array $variables
+ *   The variables to pass to the template.
+ */
+function template_preprocess_project_browser_main_app(array &$variables): void {
+  $variables['id'] = $variables['element']['#id'];
+}
diff --git a/src/Element/ProjectBrowser.php b/src/Element/ProjectBrowser.php
index 757a955cd..7d9652524 100644
--- a/src/Element/ProjectBrowser.php
+++ b/src/Element/ProjectBrowser.php
@@ -3,6 +3,7 @@
 namespace Drupal\project_browser\Element;
 
 use Drupal\Component\Utility\DeprecationHelper;
+use Drupal\Component\Uuid\UuidInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Extension\ModuleHandlerInterface;
@@ -31,6 +32,7 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn
     private readonly ?InstallReadiness $installReadiness,
     private readonly ModuleHandlerInterface $moduleHandler,
     private readonly ConfigFactoryInterface $configFactory,
+    private readonly UuidInterface $uuid,
   ) {}
 
   /**
@@ -60,6 +62,7 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn
       $install_readiness,
       $container->get(ModuleHandlerInterface::class),
       $container->get(ConfigFactoryInterface::class),
+      $container->get(UuidInterface::class),
     );
   }
 
@@ -94,8 +97,10 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn
    */
   public function attachProjectBrowserSettings(array $element): array {
     assert($element['#source'] instanceof ProjectBrowserSourceInterface);
+    $element['#id'] ??= $this->uuid->generate();
     $element['#attached']['drupalSettings']['project_browser'] = $this->getDrupalSettings(
       $element['#source'],
+      $element['#id'],
       $element['#max_selections'] ?? $this->configFactory->get('project_browser.admin_settings')->get('max_selections') ?? NULL,
     );
     return $element;
@@ -106,6 +111,8 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn
    *
    * @param \Drupal\project_browser\Plugin\ProjectBrowserSourceInterface $source
    *   The source plugin to query for projects.
+   * @param string $instance_id
+   *   An identifier for the project browser application instance.
    * @param int|null $max_selections
    *   (optional) The maximum number of project to install at once, or NULL for
    *   no limit. Defaults to NULL.
@@ -113,7 +120,7 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn
    * @return array
    *   An array of Drupal settings.
    */
-  private function getDrupalSettings(ProjectBrowserSourceInterface $source, ?int $max_selections = NULL): array {
+  private function getDrupalSettings(ProjectBrowserSourceInterface $source, string $instance_id, ?int $max_selections = NULL): array {
     if (is_int($max_selections) && $max_selections <= 0) {
       throw new \InvalidArgumentException('$max_selections must be a positive integer or NULL.');
     }
@@ -139,6 +146,12 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn
       'package_manager' => $package_manager,
       'filters' => (object) $source->getFilterDefinitions(),
       'max_selections' => $max_selections,
+      'instances' => [
+        $instance_id => [
+          'source' => $source->getPluginId(),
+          'filters' => (object) $source->getFilterDefinitions(),
+        ],
+      ],
     ];
   }
 
diff --git a/sveltejs/public/build/bundle.js b/sveltejs/public/build/bundle.js
index c8deb70568ae814b78c9366f9c9da271ea6c5501..b292e3dea9414b38e5a2359c84124c5219936eef 100644
GIT binary patch
delta 5706
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
D`DPIQ

delta 4364
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

diff --git a/sveltejs/public/build/bundle.js.map b/sveltejs/public/build/bundle.js.map
index d12bb3ab15ac84b0d4e4db3039d51afce0a39353..e57323ad96d99f3dce56a724231d6f4aff882e35 100644
GIT binary patch
delta 2150
zcmah}TTB#Z6wb^U?kXtvn+ynYaTWmq#jTcq{#{|a+!0a1%fimW!n(Wc4zP*{y+oU)
z^^zt%HoZwNNt2pZiE$d6v})3a#<aG5X!_7<Nt)KCvBCDi_Qm#}8K4^5I1iIE=RfB=
z=l{NQ=Gotpp8q3h`U1CNs@tu2yne6h4fw6S{$9T*_6Pi7Rh$t0t^<lB2K@Vcu0F-L
znORM`!CW5ClF#EYoZ_UoMSK7Wlc%^1NLTS$+KDMHUcx_r;;fi>hl|G7-r;s=b!WLr
zKGmnFqQ~n~m5^<zjWB+3kIThhI{0+$yZ5;nSou(d_RK7|N6<1guAIwn?Hf}1)pEtJ
zhP+C+<e}hFZRdyFd$Fq*;)a!j{}qHOSGcK1W8vFZxRF)=-gL`^Sr6A<<*Kx^SGna!
zk|fa`8V$O9or<b@{R3hAd!9?f>-Bt&s6>K+kSgle_PQD0i)@D%L-Q$Du-wZ8aQXX{
zaF5r$NBgm!pU){0ALePx#9~^x*+f{owudi{!__goh;?DEkoUUrmWRJ4OnBXsI6J^s
zatca2x%|Q&w@Y<df}w!Uouw}n7!NBU%VJ>*t6N-(-wyE8J&I2`z_^w4W?6hNyjh&k
zZIRtzv$$|tKA@;XWdih#s!B=mqri(x4LCe8$XntTAPOYyqe1@N6d+QkrcCm0t<){7
ze3MVsa!>HqL5^y>?(#P*Q57<6AHj1)kRM~UR#Va%!I@b|#WO_^kJCjE6IDwIZNWJg
zWNOTLiNl^^D8r-0aEWCEC~0!z`63Y6N0<_Ohw*{;N?<Sa4ayjFLzdG;?0u4h5Qk(Z
z#4fcH(r#L<gtVGgCn22=o)W2n5U12dNS8zjA=YkUkJxas6gDMTtq#&|)8h#?2O$Gf
z%Ak%Pl(m*J__`!}TqXn5Ej1I;tfx}Rs52@v6aCpB#u~kn5XHG)VQut)jf~1p<Z2*G
zJJ|`3@%X(8t8soBV(|EBh{MAj5VzdgN>tfrW2m*ZW;~w?rE#sK#`XkrDA=9?Yw+Cb
z5QSqq;JIv8YRsmG{(l1_tTD5Ja_sJgCRl3WayP8txkGq;7nCqB(VHyCGdYlnWH&hE
zbuwuglXZ5C+Yy5ulcHLg(B1lpNtr>AdBUWnHvMEkmMHGefb7`XZDgCD;o#$+LwbU>
zYTIHi&V(TiE6N}%W<(~99y25jKj?vF80mqWsOHc@p5g4p`UvD}3B9nDk9LrVjp;6C
zKwhdLxk0;L*~=<3`SDZ{o3FesNRGF%XOt2j9mC5xtmL_4AmH#`$iekx5W}GSa+QoX
zogm{k<-!WQy`72i<$6fb+V(*$2NjL2i$WY~Y+`heW0DKjXgBu5ILFe5>5z=RRYKmf
zgG~DcqU?Aj9Wox(8(y3RD}&hBR7thDKG+WlZ2meVF9Y(**q#b$f`iyw@MDXRrzswo
zg6M^_TVAm6ew&s)1jhwDavow>WLFU9{ooXu3GKj{b&$H%j5cT9m`{Dkm$YoSZ(o*H
zKysRUKvkRebO28Au?K7pNg-?iE6zZwRvCh5jtzIfPV1V+aO73S=?{V+VA~P4%{Rj!
z;R|87z%^phF?KZn2E=JD6~eE?*LJ#ei5kq=D7cs;RL4~~NRZZ0bBOeAiC)TB%XYmJ
zbFFj@brD-4GCrOuoZ{N?t4!g=_(Srb%oG{08@sYjdpS!u&2tf~$`v+RTx7>ib32S5
zLO&t>W*OFlb7^e|+j2TY@ugg$FrKl`0QGR3`3%x|+J;P)RQ&WdpMpn!<`WZ___KEE
ze+uoBT;W0*Y?8O*-D=@5{$4E{6W9_5@o<gsB%aKK==g3Lvh6lOnWE`Trv?VQK?vb|
zqOdH=LEG4^=KkUfv)PZ11gI{L`LZ%&qg{VH@u^y&&Z0|b^lLV$6XZ0Ib?5f`)HJSe
fryi0eDh)Hd;RQezHfT3Q&@&p1QU<x~RWSJvaEzh4

delta 1618
zcmZuxYitx%6wbZp&e8|1-B1?$uw9l%3*8pC^s!|E>7AJt77Dv%c{I>M7ucms*L}CN
zB~VGw2r*cH$T64@`Js>qQky21NYp~&4`QMP6Mte+qM(ULh(;3w-r22)k@<D*neTk}
zeBU`UuRkn$?U$mLCrRO`5)Hf*R53V8R@U0>!J&98nYKrQX?rZ%5!e%qsNK>3rbD4@
z9zSu=a@==@xW!MS<YrB-)86js*wVJykGFpyDt`PP=@$MA<S@n0ACc$K?WYTH(+Oh1
z*7wOyF>;Bt!kpO(@x=t`VOaN&Sc*g8NIIA_f}wCUoDRpLDf?<Wju~VDQH4X027*g=
zQL8w3nS79A{T~=xuaePcq-U;@gw>R~`cSr}&OG4WYouPERr=&jEV?^lN<VB$fBK2d
zYX27*3T2_<*fmmd<dlOJ;k8!k5UV)7S1vkt(TZH0-bp74eaYB?;NG;Bj2%n`lX$F;
zy3i7)0~k0#YzwQa7R9rG+C5oB)iS4fyUfN@tL%sHn=q{v1qbN4V*E5h^TpH=dfJMW
zgESv|e+C7|VxWll7*+cS7Z?7Zw`wh_`l6<L@#IoitTbudJA}RGp$v;`V4-dezg-Fo
zg;E9M1ShMZ25(iv6(wQtj(&V&DL9mv&UqXkoP!GVl>t-g4ess4z<DS&DHQ59G8E|D
zBKbCrm_>{5-ZJQh9eo<!AAwS~o$KrI;&O0jqt=_U)|bZ=ba|m9UsXN4v%}fOIY*Zh
z=HYZg3dyN~77`MA4cx3QP~AG;ukUlN<vgrmpa&KxDcM#U?^{_F+i&n;oa%x~adr!|
zP<l|qaTiqKXAYQykGH}6+#xMuI5+Yd1LJqVnbTsdmnX^O+YS?Rn{+;67*BI2{^4GM
zsV?Xs!$Ptzr);I+GVoU`b6Di<!x}f^CY)XmR_xgcp1B^rxmk01q!6bE&mug(MEb3F
znbcdIl9OjdW+JIs_hq486FLvwWAGg5%*1(q&i!hGE^BeD5$2<Bu~gEVhDs%&@l7o_
z-Uuc5<%CQg?S_T4Gx<~|n1CYuy_l8a)F2d{>VYz`st4B4LRD1<bl%v$!|W#@7Y>T?
z(QYU&sMmSFen6Xb;I>~jbA1S`iYcW1Ejuei-wm+HW761*XODv>!o3h6(6G*ni91k3
zR*F9Z@GdC`Ka<FY^Y20(#y<py#lxFBnl;h84|;(~58CijJ+t9gD_EXjeJ~2l%efbi
z_d_im(Z%I{ILT}tzBaCB{o81o7}hdtaP<T&#fuyYQMExX^KiclJL9lnowRmy*6A$L
zEY+PRu^Fw+GG)dg6?#l$n{(@v5p9rHsB&Y|x_B6eHz`SoS5n|0b7F0J-^M{5KN^w~
znHiTmS}_2P_&5!d82JtgF#mhV!<jRXE506p)H`{@{($MJybvGEKsipAfJG#&tU>+@
zN`TFk(-_g?na%4&X?rRDR?3p#b!m9xZHa%ij19=u?bDvD?s8FA&Q4P@h}SDvvy|-X
z!UreiynL0JdC4haZ6#Z*_<7r)CazSnNgHVr@g}Aa@bV}QH?yNT9z9~nam%jS;RXDw
zk@<0K8{{bRD~)RSqnowh)LmMPb!#ARg>G)DY%=4L^kzdgGLPn)u8g^IwK9+6@Za)T
B03iSX

diff --git a/sveltejs/src/App.svelte b/sveltejs/src/App.svelte
index ab2aa018e..6cf7ef8bc 100644
--- a/sveltejs/src/App.svelte
+++ b/sveltejs/src/App.svelte
@@ -1,6 +1,9 @@
 <script>
   import ProjectBrowser from './ProjectBrowser.svelte';
 
+  // eslint-disable-next-line import/prefer-default-export
+  export let id;
+
   // Removes initial loader if it exists.
   const initialLoader = document.getElementById('initial-loader');
   if (initialLoader) {
@@ -8,4 +11,4 @@
   }
 </script>
 
-<ProjectBrowser />
+<ProjectBrowser {id} />
diff --git a/sveltejs/src/ProjectBrowser.svelte b/sveltejs/src/ProjectBrowser.svelte
index 768783630..bff7a4b11 100644
--- a/sveltejs/src/ProjectBrowser.svelte
+++ b/sveltejs/src/ProjectBrowser.svelte
@@ -31,9 +31,12 @@
   } from './constants';
   // cspell:ignore tabwise
 
-  const { Drupal } = window;
+  const { Drupal, drupalSettings } = window;
   const { announce } = Drupal;
 
+  export let id;
+  const settings = drupalSettings.project_browser.instances[id];
+
   let data;
   let rows = [];
   let sources = [];
@@ -286,6 +289,7 @@
         on:selectCategory={onSelectCategory}
         {searchText}
         {refreshLiveRegion}
+        filterDefinitions={settings.filters}
       />
 
       <div class="pb-layout__header">
diff --git a/sveltejs/src/Search/BooleanFilter.svelte b/sveltejs/src/Search/BooleanFilter.svelte
index 906cf43cc..8cd94aee4 100644
--- a/sveltejs/src/Search/BooleanFilter.svelte
+++ b/sveltejs/src/Search/BooleanFilter.svelte
@@ -1,11 +1,12 @@
 <script>
   import { filters } from '../stores';
 
-  export let name;
+  export let definition;
+
+  const { name, on_label: onLabel, off_label: offLabel } = definition;
+
   export let changeHandler;
   export let type;
-  export let onLabel;
-  export let offLabel;
 </script>
 
 <div class="filter-group__filter-options form-item">
diff --git a/sveltejs/src/Search/Search.svelte b/sveltejs/src/Search/Search.svelte
index 68ffd9714..fc2273a57 100644
--- a/sveltejs/src/Search/Search.svelte
+++ b/sveltejs/src/Search/Search.svelte
@@ -13,7 +13,7 @@
     searchString,
     sortCriteria,
   } from '../stores';
-  import { FULL_MODULE_PATH, DARK_COLOR_SCHEME, FILTERS } from '../constants';
+  import { FULL_MODULE_PATH, DARK_COLOR_SCHEME } from '../constants';
 
   const { Drupal } = window;
   const dispatch = createEventDispatcher();
@@ -39,6 +39,8 @@
   let sortText = sortMatch.text;
   let filterComponent;
 
+  export let filterDefinitions;
+
   export async function onSearch(event) {
     const state = stateContext.getState();
     const detail = {
@@ -74,7 +76,7 @@
     if (event) {
       const filterName = event.target.name;
 
-      if (FILTERS[filterName]._type === 'boolean') {
+      if (filterDefinitions[filterName]._type === 'boolean') {
         $filters[filterName] = event.target.value === 'true';
       } else {
         $filters[filterName] = event.target.value;
@@ -116,8 +118,6 @@
     document.getElementById('pb-text').focus();
   }
 
-  const filterDefinitions = Object.entries(FILTERS);
-
   /**
    * Resets the filters to the initial values provided by the source.
    *
@@ -127,7 +127,7 @@
    */
   const resetFilters = (clear) => {
     $filters = {};
-    filterDefinitions.forEach(([name, definition]) => {
+    Object.entries(filterDefinitions).forEach(([name, definition]) => {
       let value;
       if (clear) {
         if (definition._type === 'boolean') {
@@ -205,16 +205,14 @@
       </button>
     </div>
   </div>
-  {#if filterDefinitions.length !== 0}
+  {#if Object.keys(filterDefinitions).length !== 0}
     <div class="search__form-filters-container">
       <div class="search__form-filters">
-        {#each filterDefinitions as [filterType, filter]}
+        {#each Object.entries(filterDefinitions) as [filterType, filter]}
           {#if filter._type === 'boolean'}
             <BooleanFilter
-              name={filter.name}
+              definition={filter}
               type={filterType}
-              onLabel={filter.on_label}
-              offLabel={filter.off_label}
               changeHandler={onAdvancedFilter}
             />
           {:else if filter._type === 'multiple_choice'}
diff --git a/sveltejs/src/main.js b/sveltejs/src/main.js
index 74fc6d16e..2e1178d0c 100644
--- a/sveltejs/src/main.js
+++ b/sveltejs/src/main.js
@@ -1,9 +1,13 @@
 import App from './App.svelte';
 
+const element = document.querySelector('[data-project-browser-instance-id]');
+
 const app = new App({
   // The #project-browser markup is returned by the project_browser.browse Drupal route.
-  target: document.querySelector('#project-browser'),
-  props: {},
+  target: element,
+  props: {
+    id: element.getAttribute('data-project-browser-instance-id'),
+  },
 });
 
 export default app;
diff --git a/templates/project-browser-main-app.html.twig b/templates/project-browser-main-app.html.twig
index f3768f4f0..3a87f6cef 100644
--- a/templates/project-browser-main-app.html.twig
+++ b/templates/project-browser-main-app.html.twig
@@ -11,4 +11,4 @@
     &nbsp;
   </div>
 </div>
-<div id="project-browser"></div>
+<div data-project-browser-instance-id="{{ id }}" id="project-browser"></div>
-- 
GitLab