JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 13
  • Score
    100M100P100Q56228F
  • License AGPL-3.0

No-Code UI for Hasura GraphQL

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (evolutility-ui-react) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    Evolutility-UI-React · GitHub license npm version

    Evolutility-UI-React is a set of model-driven views to Browse, Edit, List, Cards, Charts, Stats, Overview, and Activity.

    With it you can easily build CRUD applications by writing models rather than code. It uses Hasura GraphQL backend. No hand-coding is necessary!

    Check out the live demos.

    Edit

    Table of Contents

    1. Installation
    2. Configuration
    3. Views for One, Many records, and for Comfort
    4. Models
    5. Backend
    6. License

    Installation

    Download or clone from GitHub.

    # To get the latest stable version, use git from the command line.
    git clone https://github.com/evoluteur/evolutility-ui-react

    or use the npm package:

    # To get the latest stable version, use npm from the command line.
    npm install evolutility-ui-react

    In the Evolutility-UI-React directory, use the command line to type the following:

    # Install dependencies
    npm install
    
    # Run the node.js server
    npm start
    

    In a web browser, go to the url [http://localhost:3000/ the REST endpoints, you also need to install and run Evolutility-Server-Node which provides the matching REST endpoints based on the same metadata.

    Configuration

    Configurations options are specified in the file /src/config.js. They apply to all apps (app specific options are specified in models).

    Option Description Example
    apiPath Path to GraphQL API. "https://myapp.hasura.app/v1/graphql"
    adminSecret Token for Hasura.
    useCache Enable/disable data caching. true
    cacheDuration Cache duration in seconds. 120 (for 2 minutes)
    filesUrl Path to upload files to. "/pix/"
    pageSize Page size in pagination. 50
    withActivity Tracks and shows records activity (last visited and most visited). Currently implemented w/ the browser's localStorage, it will be moved to the server later. true
    queryModels Get models from JSON files or from the database through the API. (not implemented yet)
    withTimestamp Tracks and shows timestamp for creation date and last update for every record. The DB tables need timestamp columns "updated_at" and "created_at" for the feature to work. (partial implementation) true

    Views

    For any object, a single model defines UI elements across views in a simple declarative way.

    Evolutility-UI-React provides different types of view:

    Evolutility uses GraphQL with Hasura.

    Notes: Views for actions (search, filter, export) will come later.

    Views for One object

    Browse - Edit

    Browse

    Shows all fields for viewing (read only). Fields are grouped in panels.

    Browse

    Code: /src/components/views/one/Browse/Browse.jsx

    Route: "/{entity}/browse/{id}"

    Edit

    This view shows all fields for edition to create or update records. It automatically performs validation based on the model. Fields are grouped in panels and tabs.

    Edit

    Code: /src/components/views/one/Edit/Edit.jsx

    Route: "/{entity}/edit/{id}"

    Views for Many objects

    List - Cards - Charts - Stats

    List

    Gives a tabular view of a collection.

    List

    Code: /src/components/views/many/List/List.jsx

    Route: "/{entity}/list"

    Cards

    Shows records side by side as cards.

    Cards

    Code: /src/components/views/many/Cards/Cards.jsx

    Route: "/{entity}/cards"

    Charts

    Draws charts about the collection. Currently bars and pie charts are implemented, a list with count and percentages is also available. Only provided for fields of types like boolean, lov, integer, decimal, date... (not text or textmultilines).

    Charts

    Code: /src/components/views/analytics/Charts/Charts.jsx

    Route: "/{entity}/charts"

    Note: The "Charts" view is currently only implemented for REST, not available with GraphQL yet.

    Stats

    Display last update, number of updates in the last week, and for numeric fields the min, max, count, average.

    Stats

    Code: /src/components/views/analytics/Stats/Stats.jsx

    Route: "/{entity}/stats"

    "Comfort" views

    Display a summary of the object and the latest activity on it.

    Overview

    Display a summary of the object and the latest activity on it.

    Overview

    Code: /src/components/views/comfort/Overview/Overview.jsx

    Route: "/{entity}/"

    Activity

    Show list of "last visited" and "most visited" records for the object (stored in the browser's localStorage).

    Activity

    Code: /src/components/views/comfort/Activity/Activity.jsx

    Route: "/{entity}/activity"

    Models

    Each model describe an object and its list of fields. A single model is used for all views (Browse, Edit, List, Cards...).

    For any object, all UI views (List, Cards, Edit, Charts...) share the same model. All Fields are present in the Edit and Browse views. Fields can be flagged with "inMany" to be included in the List and Cards views, or "noCharts" and "noStats" to be excluded from the Charts or Stats views.

    Object

    Property Meaning
    id Unique key to identify the entity (used in route and as API parameter).
    qid Entity ID used in GraphQL (may be different from id in route).
    icon Icon file name for the entity (example: "cube.gif").
    name Object name (singular).
    namePlural Object name (plural).
    title Application name.
    fields Array of Fields.
    groups Array of Groups. If not provided a single group will be used.
    collections Array of Collections.
    titleField Id of the field which value is used as record title. titleField can also be a function.
    titleFunction Function to calculate the record title based it's data. Example: titleFunction = (data, model) => data.firstname + " " + data.lastname;
    defaultViewOne To have List and Cards link to Edit instead of Browse, set defaultViewOne="edit".

    Field

    Objects have fields.

    Property Meaning
    id Unique key for the field (can be the same as column but doesn't have to be).
    type Field type to show in the UI. Possible field types:
    • boolean (yes/no)
    • date
    • decimal
    • document
    • email
    • image
    • integer
    • json
    • lov (list of values)
    • money
    • text
    • textmultiline
    • time
    • url
    label Field description (displayed with an asterisk for required fields).
    labelShort Optional shorter version of the labels (used in List and Cards views).
    required Determines if the field is required for saving.
    readOnly If set to true, the field value cannot be changed.
    defaultValue Default field value for new records.
    format Field format (using moment for date values and numeral for numeric values).
    max, min Maximum/Minimum value allowed (only applies to numeric fields).
    maxLength, minLength Maximum/Minimum length allowed (only applies to text fields).
    regExp Regular expression used to validate the field value.
    list List of items in the dropdown as an array of id-text objects (only for fields of "lov" type). If ommited, the list will be retrieved in the first query by id on that object.
    lovIcon Set to True to include icon with LOV items(only for fields of "lov" type).
    object Model id for the object to link to (only for fields of "lov" type).
    chartObject Optional overide for object name in charts (only for "lov" fields).
    aggregate Optional overide for aggregation name in charts (only for "lov" fields).
    inMany Determines if the field is present (by default) in lists of records.
    inSearch Determine if the field is used in text searches.
    height For fields of type "textmultiline", number of lines used in the field (in Browse and Edit views).
    width Field width in Browse and Edit views (in percent of parent width).
    help Optional help on the field.
    chartType Default charts type used for the field ("Bars", "Pie", or "Table"). "Bars" is used if not specified.
    noCharts Exclude field from charts (only applies to fields of type integer, decimal, money, boolean, list of values which are "chartable").
    noStats Exclude field from Stats.

    Field Group

    Field Groups are used to separate Fields into panels in the Edit and Browse views.

    Property Meaning
    id Unique key for the group. It is optional.
    type Type of fields group. Only "panel" is currently supported (tab and other types of groups will be added later).
    label Group title displayed in the group header.
    fields Array of field ids.
    width Width (in % of the container total width).
    help Optional help tooltip text.
    header Optional text displayed at the top of the group (just below the group title).
    footer Optional text displayed below the group.

    Notes:

    • Field Groups are optional. By default a single group holds all fields.
    • Field Groups are positioned based on their "width" property the same way than fields are positioned inside groups.

    Collection

    Multiple details tables can be specified with "collections".

    Property Meaning
    id Unique key for the collection.
    title Collection title.
    object Model.id for the Object to link to.
    fields Array of fields (objects or ids). Fields in collections can be field objects or just ids of fields in the collection's object.
    readOnly Specify if the collection is readOnly.
    hideIfEmpty Hide Collection when it is empty in Edit view (always hidden when empty in Browse view).
    help Optional help tooltip text.
    header Text to be displayed before the collection.
    footer Text to be displayed below the collection.

    Sample model using collections: Wine Cellar.

    Sample model

    The following example is the model for a simple graphic novels inventory app.

    {
        id: "comics",
        title: "Graphic Novels",
        name: "graphic novel serie",
        namePlural: "graphic novel series",
        icon: "comics.png",
        titleField: "title",
        fields:[
          {
              id: "title", type: "text",
              label: "Title",
              required: true, maxLength: 255,
              width: 100, inMany: true,
          },
          {
              id: "authors", type: "text",
              label: "Authors",
              inMany: true, width: 62,
    
          },
          {
              id: "genre", type: "lov",
              label: "Genre",
              width: 38, inMany: true,
              list: [
                {id: 1, text: "Adventure"},
                {id: 2, text: "Fairy tale"},
                {id: 3, text: "Erotic"},
                {id: 4, text: "Fantastic"},
                {id: 5, text: "Heroic Fantasy"},
                {id: 6, text: "Historic"},
                {id: 7, text: "Humor"},
                {id: 8, text: "One of a kind"},
                {id: 9, text: "Youth"},
                {id: 10, text: "Thriller"},
                {id: 11, text: "Science-fiction"},
                {id: 12, text: "Super Heros"},
                {id: 13, text: "Western"}
              ]
          },
          {
              id: "serie_nb", type: "integer",
              label: "Albums", noCharts: true,
              width: 15, inMany: false
          },
          {
              id: "have_nb", type: "integer",
              label: "Owned",
              width: 15, inMany: false, noCharts: true
          },
          {
              id: "have", type: "text",
              label: "Have",
              width: 15, inMany: false
          },
          {
              id: "language", type: "lov",
              label: "Language",
              width: 17, inMany: true,
              lovIcon: true,
              list: [
                {id: 2, text: 'French', icon:'comics/flags/fr.png'},
                {id: 1, text: 'American', icon:'comics/flags/us.png'}
              ]
          },
          {
              id: "complete", type: "boolean",
              label: "Complete",
              width: 19, inMany: false
          },
          {
              id: "finished", type: "boolean",
              label: "Finished",
              width: 19, inMany: false
          },
          {
              id: "pix", type: "image",
              label: "Cover",
              width: 30, inMany: true
          },
          {
              id: "notes", type: "textmultiline",
              label: "Notes",
              width: 70, height: 7, maxLength: 5000,
              inMany: false
          }
      ],
    
      groups: [
          {
            id:"serie", type: "panel", label: "Serie", width: 70,
            fields: ["title", "authors", "genre",
                  "serie_nb", "have_nb", "have",
                  "language", "complete", "finished", "notes"
            ]
          },
          {
            id:"pix", type: "panel", label: "Cover", width: 30,
            fields: ["pix"]
          }
      ]
    }
    

    More sample models: To-do list, Address book, Restaurants list, Wine cellar.

    Backend

    You will need to setup the GraphQL backend on Hasura with the Evolutility demo database.

    1. You can signup for a free account or host it yourself (Quickstart Hasura CLI).
    2. Add a Postgres database to your Hasura setup.
    3. Add the demo tables by running the SQL script evol-db-schema.sql.
    4. Populate your database with sample data by running evol-db-data.sql
    5. Add relationships in Hasura console.
      Relationships on comics table:
      • genre (Object): comics / genre_id -> comics_genre / id
      • language (Object): comics / language_id -> comics_language / id
      Relationships on comics_genre table:
      • comics (Array): comics_genre / id => comics / genre_id
      Relationships on comics_language table:
      • comics (Array): comics_language / id => comics / language_id
      Relationships on contact table:
      • category (Object): contact / category_id -> contact_category / id
      Relationships on contact_category table:
      • contacts (Array): contact_category / id => contact / category_id
      Relationships on music_album table:
      • artist (Object): music_album / artist_id -> music_artist / id
      • tracks (Array): music_album / id -> music_track / album_id
      Relationships on music_artist table:
      • albums (Array): music_artist / id -> music_album / artist_id
      Relationships on music_genre table:
      • tracks (Array): music_genre / id -> music_track / genre_id
      Relationships on music_track table:
      • album (Object): music_track / album_id -> music_album / id
      • genre (Object): music_track / genre_id -> music_genre / id
      Relationships on restaurant table:
      • cuisine (Object): restaurant / cuisine_id -> restaurant_cuisine / id
      • price (Object): restaurant / price_id -> restaurant_price / id
      Relationships on restaurant_cuisine table:
      • restaurants (Array): restaurant_cuisine / id => restaurants / cuisine_id
      Relationships on restaurant_price table:
      • restaurants (Array): restaurant_price / id => restaurants / price_id
      Relationships on task table:
      • category (Object): task / category_id -> task_category / id
      • priority (Object): task / priority_id -> task_priority / id
      Relationships on task_category table:
      • tasks (Array): task_category / id => task / category_id
      Relationships on task_priority table:
      • tasks (Array): task_priority / id => task / priority_id
      Relationships on wine table:
      • wine_tastings (Array): wine / id -> wine_tasting / wine_id
      • bsize (Object): wine / bsize_id -> wine_bsize / id
      • country (Object): wine / country_id -> wine_country / id
      • grape (Object): wine / grape_id -> wine_grape / id
      • score (Object): wine / score_id -> wine_score / id
      • type (Object): wine / type_id -> wine_type / id
      Relationships on wine_bsize table:
      • wines (Array): wine_bsize / id => wine / bsize_id
      Relationships on wine_country table:
      • wines (Array): wine_country / id => wine / country_id
      Relationships on wine_grape table:
      • wines (Array): wine_grape / id => wine / grape_id
      Relationships on wine_score table:
      • wines (Array): wine_score / id => wine / score_id
      Relationships on wine_tasting table:
      • wine (Object): wine_tasting / wine_id -> wine / id
      Relationships on wine_type table:
      • wines (Array): wine_type / id => wine / type_id
    6. In Evolutility, change the "apiPath" and "adminSecret" in the ./src/config.js file.

    License

    Copyright (c) 2023 Olivier Giulieri.

    Evolutility-UI-React is released under the AGPL-3.0 license.

    To suggest a feature or report a bug: https://github.com/evoluteur/evolutility-ui-react/issues