Code Monkey home page Code Monkey logo

evolutility-ui-react's Introduction

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

evolutility-ui-react's People

Contributors

dependabot[bot] avatar evoluteur avatar hassankaz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

evolutility-ui-react's Issues

CORS issue (Response for preflight is invalid)

Running into an issue working with the React-UI and Node-Server backed on the same localhost for seemingly "non-simple" requests meaning all of the base GET API calls to the backend work fine, but trying to use the edit views for PUT API calls are getting interrupted. The React-UI will throw a Network Error - and digging into the developer console its looking like a CORS-related issue.

http://localhost:2000/api/V1/winecellar/5: Response for preflight is invalid (redirect)

I'm curious if anyone else has encountered this issue while trying to stand up the base apps.

Search function

Hi,

Thanks for your great app. I'm able to add new model with less effort.

I have some questions

  • Do you support search functionality?
    I can't find any example using search. I also find that the search flag is commented.
  • Since I'm very new to react, can you give me a guidance to add search to a specific model?
    I have one model only so we can accept hard approach.

Thanks,
Van

Production server fails with file not found error

The error is:
Error: ENOENT: no such file or directory, stat 'D:\MyDocs\dev\Evolutility\evolutility-ui-react\src\public\index.html*.css'

Apparently caused by having moved the server.js. Changes required:

res.sendFile(path.join(__dirname, '../public', 'index.html'))

Also

app.use(express.static(path.join(__dirname, '../public')))

Issues attempting to Dockerize

Has anyone attempted to Dockerize this code base? When I go to run the app via docker I get the following error and just trying to troubleshoot where I've gone wrong as I've mirrored the same steps with a normal "local" install without any issues.

ERROR in ./src/components/views/many/Cards.js
Module not found: Error: Cannot resolve 'file' or 'directory' ../One/Card in /evolutility-ui-react/src/components/views/many
resolve file
/evolutility-ui-react/src/components/views/One/Card doesn't exist
/evolutility-ui-react/src/components/views/One/Card.webpack.js doesn't exist
/evolutility-ui-react/src/components/views/One/Card.web.js doesn't exist
/evolutility-ui-react/src/components/views/One/Card.js doesn't exist
/evolutility-ui-react/src/components/views/One/Card.json doesn't exist
resolve directory
/evolutility-ui-react/src/components/views/One/Card doesn't exist (directory default file)
/evolutility-ui-react/src/components/views/One/Card/package.json doesn't exist (directory description file)
[/evolutility-ui-react/src/components/views/One/Card]
[/evolutility-ui-react/src/components/views/One/Card.webpack.js]
[/evolutility-ui-react/src/components/views/One/Card.web.js]
[/evolutility-ui-react/src/components/views/One/Card.js]
[/evolutility-ui-react/src/components/views/One/Card.json]
@ ./src/components/views/many/Cards.js 25:12-34

Model.collections does not need a list of fields

In any model collections is the specification of a child set. It is used on a browse screen to retrieve a list of child records displayed in master-detail format.

The fields information is redundant. It matches exactly the fields information in the child model, and can be retrieved as needed by accessing the child model (filtered presumably on inMany). For similar reasons the table and column attributes are also redundant.

Demo for evolutility-ui-react (not an issue)

Hello Oliver,

Really impressed by Evolutility so far, congrats!

I see that you have a Demo for the jquery version of the FrontEnd, do you plan to showcase one also for the React?

Looking forward to see it!

Many thanks,
Costin V.

script/build fails with file not found

The error is
Module not found: Error: Can't resolve 'widgets/PageNotFound.js' in ...

I think the alias in config\webpack.config.dev.js is missing from config\webpack.config.prod.js. I tried fixing that, but then there are more.

Date format is US only

All dates displayed by Evolutility seem to be in US format (mm/dd/yyyy).
The culprit code appears to be this line in format.js:64.

return dateParts[1]+'/'+dateParts[2]+'/'+dateParts[0];

It really does need to format dates according to national preferences (mine are European dd/mm/yyyy).

LOV based on existing Entity returns no data

Trying to work backwards off of your template models to expand upon them. Looking at Winetasting.js and specifically the wine_id field:

{ id: 'wine_id', entity: 'winecellar', column: 'wine_id', type: 'lov', label: 'Wine', inMany: true, width: 62, required: true },

When I attempt to add a new winetasting record or edit an existing, the LOV drop down list does not populate with available Wines. Is this field type intended to work as such? Attempting to rejoin the normalized structure that is created through the use of the LOV field type is tricky.

Fetch models from server

Currently all models are compiled in. Assuming all the models are stored on the server it should be a simple change to:

  • retrieve a list of tables from the server to populate the top level menu (or just show a view on the table of tables)
  • retrieve a specified table with its model as required.

Threat from flat-map-stream

I have just been notified by my system that there is a known threat called Trojan:JS/CoinMiner that was introduced in the NodeJS flat-map-stream library.

More details here: hugeglass/flatmap-stream#2.

I would suggest that anyone with this module installed should delete it and reinstall.

package-lock.json http: regressions

The new version 0.2.0 has a package-lock.json, for the first time AFAIK. It contains a mixture of http: and https:, which is undesirable in its own right, but also causes a heap of regressions when updating from an earlier version in which the file was locally generated.

My guess is that the simplest solution is not to include this file in the release.

Info About group by data

Hi, I would like know if is there a simple way to use function like "group by" in evolutility-ui-react. for example I have a list of orders, I would like see the sum of orders by client.

Best regards.

Browser history does not work with click sort

To reproduce,

  • click on Todo. Displays the list.
  • click on Title. Shows up arrow in the title bar.
  • click on Title. Shows down arrow in the title bar and sorts list in descending order.
  • click on back button. Display does not change (still descending). However, address bar now shows:
    http://localhost:8080/todo/list?order=title.asc
  • click on Refresh. Display now shows ascending order.

As a side note, the title bar arrow does not always show correctly.

Date fields get blank when Editing

Hi Olivier,

When clicking the Edit button I saw that the fields that contain dates get erased.
I have attached a printscreen for this below (create_date). The fields had values prior to clicking on the Edit button.

image

Do you know if there is a particular reason for this? Is it possible to change the logic so that the fields stay as is?

Thank you!
Costin V.

hey

I just meet you ten minutes ago ,by node-red ant it's tab 'low-code' ,searched your project.
we are too many sames ,so i think you are a kindhearted man too ~ haha

How to set this up

Olivier, I tried setting this up in my local machine, is there a document where I can setup this and point to a database and build the UI.

Thanks for your help.

Krishna

Enable remote deployment

For deployment to node hosting such as Heroku etc I think a few things are needed, such as

  • ui-react SPA statically loadable from the public directory (port 80)
  • server-node port configurable
  • a better way to handle the uploads and pix paths.
    I'm sure there will be more.

Database in local storage

A local storage implementation is a really nice thing, both as a demo and for personal use. The steps I would take are:

  • refactor all references to axios into a separate function/object-based API
  • create a local storage based implementation of that API.

But maybe there is an easier way, reusing the backbone model from the jQuery project.

Missing country icons for comics

The cause is simple: no file(s) at the given path(s). The wine flags work, the comics flags don't.

Suggestion: put all the country icon files in their own directory, say 'country'. Then they can be shared.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.