sanger / limber

A config-driven LIMS built on Sequencescape, primarily for running library preparation pipelines in the laboratory
MIT License
4 stars 8 forks source link

Y24-432 - Centralize Vue Component Initialization #2033

Open seenanair opened 3 weeks ago

seenanair commented 3 weeks ago

Describe the Housekeeping Currently, each Vue component in Limber Rails application has its own index.js file for initialization. This leads to code duplication and file redundancy makes it harder to manage and maintain. It would be good to centralize the Vue component initialization into a single file to ensure a consistent approach to initialise Vue components across application.

Following is the suggested approach which need to be verified that it does not conflict with any existing setup.

StephenHulme commented 2 weeks ago

Suggest using the currently used vite_javascript_tag instead of javascript_pack_tag

StephenHulme commented 2 weeks ago

Let’s also use the app/frontend/javascript/shared/components/ directory or a similar location under app/frontend/javascript/ instead.

StephenHulme commented 2 weeks ago

These components all have index.js files and are most affected by this story: https://github.com/sanger/limber/blob/master/app/frontend/entrypoints/application.js#L56-L65

Here are some more initial details suggested by @seenanair:

The primary goal of this task is to reduce the number of scattered index.js files by consolidating them into a single location, which should also help reduce some code redundancy. I haven’t tried this approach myself, which is why I’ve labeled it as a research task. There are quite a few potential improvements, but this will provide a straightforward starting point for cleanup. I’m not much in favour of having multiple Vue instances for each component scattered in ERB files. During my research, I found ways to streamline sprinkiling of Vue components in erb files in a more cleaner way, but most methods rely on third-party libraries like Turbolinks. Adding another dependency might not be ideal, or viable, or other option is to use Vue as a SPA, but that also could introduce significant architectural changes. My idea is fairly simple: we could consolidate everything into a single file and create a helper function for mounting components. Here’s an example:

// Helper function to initialize Vue components
const initializeVueComponent = (selector, component, props = {}, data = {}) => {
  const element = document.querySelector(selector);
  if (element) {
    new Vue({
      el: selector,
      data: () => data,
      render: (h) => h(component, { props }),
    });
  }
};

document.addEventListener('DOMContentLoaded', () => {
  // Initialize QcInformation component
  initializeVueComponent('#qc-information', QcInformation, document.getElementById('qc-information')?.dataset || {});

  // Initialize PoolXPTubeSubmitPanel component
  const assetElem = document.getElementById('pool-xp-tube-submit-panel');
  if (assetElem) {
    const userId = cookieJar(document.cookie).user_id;
    const sequencescapeApiUrl = assetElem.dataset.sequencescapeApi;
    const tractionServiceUrl = assetElem.dataset.tractionServiceUrl;
    const tractionUIUrl = assetElem.dataset.tractionUiUrl;

    if (userId) {
      initializeVueComponent('#pool-xp-tube-submit-panel', PoolXPTubeSubmitPanel, {
        barcode: assetElem.dataset.barcode,
        userId,
        sequencescapeApiUrl,
        tractionServiceUrl,
        tractionUIUrl,
      });
    } else {
      new Vue({
        el: '#pool-xp-tube-submit-panel',
        render: (h) => h('div', "Unfortunately, Limber can't find your user ID, which is required to add custom metadata. Please log out and swipe in again to resolve this issue. If this continues, let us know."),
      });
    }
  }
});