UI Development

UI Development #

In the event you are contributing to Meltano UI and want to work with all of the frontend tooling (i.e., hot module reloading, etc.), you will need to run the following commands:

# Activate your poetry created virtual environment if needed.
# If you manage your virtualenv activation through other means you can omit this command.
poetry shell

# Create a new Meltano project
meltano init $PROJECT_NAME

# Change directory into your newly created project
cd $PROJECT_NAME

# Start the Meltano API and a production build of Meltano UI that you can ignore
meltano ui

# Open a new terminal tab and go to the directory you cloned meltano into
cd $WHEREVER_YOU_CLONED_MELTANO

# Install frontend infrastructure at the root directory
yarn setup

# Start local development environment
yarn serve

The development build of the Meltano UI will now be available at http://localhost:8080/.

A production build of the API will be available at http://localhost:5000/ to support the UI, but you will not need to interact with this directly. However, as mentioned in the API Development section above, users on MacOS may need to specify an alternate bind to port to prevent a port conflict with a MacOS system service also running on port 5000.

If you're developing for the _Embed_ app (embeddable iframe for reports) you can toggle MELTANO_EMBED:

# Develop for the embed app
export MELTANO_EMBED=1

# Develop for the main app (this is the default)
export MELTANO_EMBED=0

# Start local development environment
yarn serve

If you need to change the URL of your development environment, you can do this by updating your project’s .env file with the following configuration:

# The URL where the web app will be located when working locally in development
# since it provides the redirect after authentication.
# Not require for production
export MELTANO_UI_URL = ""

UI/UX #

Visual Hierarchy #

Depth #

The below level hierarchy defines the back to front depth sorting of UI elements. Use it as a mental model to inform your UI decisions.

  • Level 1 - Primary navigation, sub-navigation, and signage - Grey
  • Level 2 - Primary task container(s) - White w/Shadow
  • Level 3 - Dropdowns, dialogs, pop-overs, etc. - White w/Shadow
  • Level 4 - Modals - White w/Lightbox
  • Level 5 - Toasts - White w/Shadow + Message Color

Interactivity #

Within each aforementioned depth level is an interactive color hierarchy that further organizes content while communicating an order of importance for interactive elements. This interactive color hierarchy subtly influences the user’s attention and nudges their focus.

  1. Primary - $interactive-primary
    • Core interactive elements (typically buttons) for achieving the primary task(s) in the UI
    • Fill - Most important
    • Stroke - Important
  2. Secondary - $interactive-secondary
    • Supporting interactive elements (various controls) that assist the primary task(s) in the UI
    • Fill - Most important
      • Can be used for selected state (typically delegated to stroke) for grouped buttons (examples usage seen in Transform defaults)
    • Stroke - Important
      • Denotes the states of selected, active, and/or valid where grey represents the opposites unselected, inactive, and/or invalid
  3. Tertiary - Greyscale
    • Typically white buttons and other useful controls that aren’t core or are in support of the primary task(s) in the UI
  4. Navigation - $interactive-navigation
    • Denotes navigation and sub-navigation interactive elements as distinct from primary and secondary task colors

After the primary, secondary, tertiary, or navigation decision is made, the button size decision is informed by:

  1. Use the default button size
  2. Use the is-small modifier if it is within a component that can have multiple instances

Markup Hierarchy #

There are three fundamental markup groups in the codebase. All three are technically VueJS single-file components but each have an intended use:

  1. Views (top-level “pages” and “page containers” that map to parent routes)
  2. Sub-views (nested “pages” of “page containers” that map to child routes)
  3. Components (widgets that are potentially reusable across parent and child routes)

Here is a technical breakdown:

  1. Views - navigation, signage, and sub-navigation
    • Navigation and breadcrumbs are adjacent to the main view
    • Use <router-view-layout> as root with only one child for the main view:
      1. <div class="container view-body">
        • Can expand based on task real-estate requirements via is-fluid class addition
    • Reside in the src/views directory
  2. Sub-views - tasks
    • Use <section> as root (naturally assumes a parent of <div class="container view-body">) with one type of child:
      • One or more <div class="columns"> each with their needed <div class="column"> variations
    • Reside in feature directory (ex. src/components/analyze/AnalyzeModels)
  3. Components - task helpers
    • Use Vue component best practices
    • Reside in feature or generic directory (ex. src/components/analyze/ResultTable and src/components/generic/Dropdown)