Code Monkey home page Code Monkey logo

vue-admin's Introduction

Vue-Admin logo

Vue-Admin is designed to let developers build frontend administration applications that run in the browser in a very easy way using Vue, Javascript and REST services.

Build Status Build Status Version License License

Introduction

We've been working a lot with other libraries that generate administration dashboards, routes, resources in other javascript frameworks, but did not find any Vue library capable of performing this kind of solution, except of many really impressive Vue libraries that provide UI components for admin dashboards. We are pretty convinced Vue's learning curve is gentle, so we thought we could try and build our own tool.

demo of the app running

About the library

Given a simple configuration to Vue-Admin components, this library connects your backend and interprets your services as frontend resources from which CRUD views are automatically created and associated with a route.
Vue-Admin also lets you create custom views to provide other kind of information to the site (measures, landings, etc).

Vue-Admin provides:

  • create, read, update and delete views for each declared resource.
  • customizable homepage.
  • navigation between views.
  • an authentication view
  • vuetify2 support

Dependencies and third party libraries

We assume your project ships the following dependencies:

  • vue-router: used to dynamically create routes and bind components to them. We also take advantage of some of the route hooks.
  • vuex: lets us globally share information between the core application and component customizations of a library user.
  • vuetify: we basically don't want to implement UI components from scratch, plus their widgets are awesome. The drawer, buttons, cards and CRUD views are implemented with Vuetify, but you could use any other UI framework if you want to build your own CRUD views. Take the magazines view as example.

Core Libaries vue-admin-js depends on:

  • vuex-crud: this lightweight tool creates the resources crud store state, mutations and getters for us.

Installation

# using npm
npm i --save vue-admin-js

Configuration

Auth Provider

You will have to configure an adapter to communicate with your REST api.

We currently provide a simple example using an axios client in the demo app. Though we intend to keep developing other kind of adapters for different node backend frameworks, they will live in separate packages.

Anyways, we hope the axios example encourages you to write your own adapter until we release the adapters guide. The @va-auth module uses the vuex store and expects a user to make use of the action types it provides.

Usage

App.vue

<template>
  <Admin :authProvider="authProvider">
    <Resource
      name="articles"
      resourceIdName="id"
      userPermissionsField="permissions"
      apiUrl="http://localhost:8888/api/"
    >
      <View slot="list"   :component="ListArticles"   :permissions="['admin']" />
      <View slot="show"   :component="ShowArticles"   :permissions="['admin']" />
      <View slot="create" :component="CreateArticles" :permissions="['admin']" />
      <View slot="edit"   :component="EditArticles" :isPublic="true" />
    </Resource>
  </Admin>
</template>

<script>
  import { Admin, Resource } from 'vue-admin-js'
  // Your components
  import ListArticles from './components/articles/ListArticles'
  import ShowArticles from './components/articles/ShowArticles'
  import CreateArticles from './components/articles/CreateArticles'
  import EditArticles from './components/articles/EditArticles'
  import createAxiosAdapter from './va-auth-adapter/axios.adapter'
  import axios from 'axios'

  const authUrl = 'http://localhost:8888/api/auth'
  const client = axios

  const authProvider = createAxiosAdapter(client, { authUrl })

  export default {
    name: 'App',
    components: {
      Admin,
      Resource
    },
    data() {
      return {
        authProvider,
        // Your Components
        ListArticles,
        ShowArticles,
        CreateArticles,
        EditArticles,
      }
    }
  }
</script>

ListArticles.vue

<template>
  <List>
    <p source="id" :sortable="true" headerText="ID" alignHeader="left" alignContent="left" />
    <h3 source="title" :sortable="true" headerText="Title" alignHeader="center" alignContent="left" />
    <p source="content" :sortable="true" headerText="Content" alignHeader="center" alignContent="right" />
  </List>
</template>

<script>
import { List } from 'vue-admin-js'

export default {
  name: 'ListArticles',
  components: {
    List
  }
}
</script>

Using your own custom authentication component

By default Vue-Admin provides a default authentication view, but you may desire to use your own custom view to authenticate. In that case, you just need to pass it as a property in the Admin component like the following.

Example of custom authentication component usage

  ...
  <Admin :authProvider="authProvider" :authLayout="AuthCustomView">
  ...

In order to use the available authentication mechanism you have to declare a prop with a va object field which will contain the bounded login function.

Example of provided login mechanism usage in custom auth component

  ...
  props: {
    va: {
      type: Object,
      required: true
    }
  },
  ...
  methods: {
    login() {
      this.va.login(this.username, this.password)
    }
  }
  ...

Examples

For a complete example take a look at the demo files

Some of the custom components examples can be found in the magazines views

Starting a new project

Using the official Vue cli

# install the official vue cli
npm install -g @vue/cli-init
# initialise the project
vue init webpack my-project
cd my-project
# install required dependencies
npm install --save vue-admin-js vue-router vuex vuex-crud vuetify
# run the project
npm run dev

...and start customizing your App.vue

Getting it running

To get vue-admin-js up and running we'll need two terminals: one for the frontend and another one simulating a backend.

Clone a vue-admin-js repository and open two terminals in the repository root.

git clone https://github.com/Cambalab/vue-admin.git
cd vue-admin

In the first terminal get the node development server running

# install the test server dependencies
cd utils/server-test && npm install
# run the server (we prefer to use the same port as Cypress server)
PORT=8888 node server

In the second terminal get the frontend application running

# make sure you're in the root of the project
npm install
npm run serve

Demo app credentials

User with admin permissions

username: [email protected]
password: 123456

User with guest permissions

username: [email protected]
password: 123456

Scripts: tests, lint, build

We use the vue-cli-service to run tests, lint checking and the library build.

All of the above are used by the travis continuous integration.

unit tests

# in the root of the project run the unit tests script
npm run test:unit

end to end tests

# go to the root of the project to run the e2e tests script
# there's no need to run the test server, we use the Cypress server
npm run test:e2e

lint service

# zero tolerance for errors and warnings
npm run lint

build service

# the build is targeted as a library
npm run build

Contribution

Please make sure to read the Contributing Guide before making a pull request.

License

GNU General Public License version 3

👩‍💻 with 💚 💜 ❤️ by cambá.coop 🌎 Buenos Aires, Argentina

vue-admin's People

Contributors

agustinariq avatar c3-tko avatar cuococarlos avatar danielormeno avatar dependabot[bot] avatar estefi-prieto avatar florblue avatar glmaljkovich avatar jejoivanic avatar josx avatar sevenindirecto avatar sgobotta avatar smarbos avatar tehuel 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

vue-admin's Issues

Functional proposal for custom components rendering

This may be a .vue file. Instead of using template syntax, the file exports only the <script></script> part.

So, with this you are in charge of rendering something, with the use of the (createElement) function provided by vue to all component render function.

Read the doc to become familiar with the API.

Example:

  • BirthDay, Mail, Name and PhoneNumber are simple vue components exported with <template></template>, <script></script> and <style></style> tags.
  • The render function of smartRendererComponent must return a valid createElement object.
  • You can use the known properties too: computed, props, etc.

smartRendererComponent.vue

<script>
import { postForm } from '@/api'
import BirthDay from '@/components/Inputs/BirthDay'
import Mail from '@/components/Inputs/Mail'
import Name from '@/components/Inputs/Name'
import PhoneNumber from '@/components/Inputs/PhoneNumber'

import Vue from 'vue'
import VeeValidate, { Validator } from 'vee-validate'
import es from 'vee-validate/dist/locale/es'

// Add locale helper.
Validator.addLocale(es)
Vue.use(VeeValidate, {
  locale: 'es',
  inject: false
})

export default {
  $validates: true,
  render: function (createElement) {
    let self = this
    let csrfTokenInput = createElement(
      'input',
      {
        attrs: {
          type: 'hidden',
          value: self.csrfToken
        }
      }
    )

    let childInputs = this.options.map(function (element) {
      let toCreateElement = ''

      switch (element.formField.name.toUpperCase()) {
        case 'NOMBRE':
          toCreateElement = Name
          break
        case 'CUMPLEANOS':
          toCreateElement = BirthDay
          break
        case 'MAIL':
          toCreateElement = Mail
          break
        case 'WHATSAPP':
          toCreateElement = PhoneNumber
          break
      }

      return createElement(toCreateElement, {
        props: {
          mysqlType: element.formField.mysql_type,
          inputName: element.formField.name.toUpperCase(),
          placeholder: element.formField.html_placeholder,
          validationRules: element.placeFormFieldValidations,
          formFieldId: element.formField.id
        }
      })
    })

    let vForm = createElement('form', {
      on: {
        submit: function (event) {
          event.preventDefault()

          self.$validator.validateAll().then(result => {
            let data = {
              _csrf: self.csrfToken,
              connectorId: self.$store.state.customer.id,
              responses: []
            }
            data.responses = self.$children.map(function (currentValue) {
              return {
                mysqlType: currentValue.mysqlType,
                formFieldId: currentValue.formFieldId,
                data: currentValue.formData
              }
            })
            postForm(self.$store.state.place.slug, data)
          })
        }
      }
    }, [
      csrfTokenInput,
      childInputs,
      createElement('button', {
        attrs: {
          class: 'button disabled',
          disabled: !self.isSubmitDisabled,
          type: 'submit',
          variant: 'success'
        },
        domProps: {
          innerHTML: 'INGRESAR'
        }
      })
    ]
  )

    return createElement('div', {
      'class': {
        'text-center': true
      }
    }, [vForm])
  },
  computed: {
    isSubmitDisabled () {
      let fields = Object.values(this.fields)

      return fields.every(function (element) {
        return element.valid
      })
    }
  },
  props: {
    csrfToken: {
      type: String,
      required: true
    },
    options: {
      type: Array,
      required: true
    }
  }
}
</script>

Simple API injection proposal for custom user componentisation

#34 inspired me to experiment with functional rendering and jsx syntax in Vue. I took into consideration a few aspects while working on it:

  • it is possible to inject props and functionality in custom components passed to Resource using JSX syntax, though it's not very popular among Vue developers. We would also be forcing them (users) to take a strange path when building their own components for a view in JSX syntax, since most Vue UI frameworks use the tag to layout their interfaces.
  • Similar to the previous consideration, we could build custom components, such as buttons, textfields, forms, pagination tables, that would behave as wrappers and trigger different actions (a submit button would store information in database, for example.). We will have to somehow interact between the form elements and keep track of the inputted information before a database call is requested.
  • Since it's possible to pass a component by props, I thought a simple set of a few functions can be injected into a user component, so that any form input and button in any view behave the way we expect. We let users build their own interfaces and we provide the event listener and submitting functions for their elements. We still take care of keeping track of their form data and do the database calls when requested.
  • The third idea led me to implement a simple API that could be injected to any user component that is passed to Resource as a prop.

Update Package.json information

Depends on #18

Updates:

  • Remove private repository attribute
  • Add project description (similar to github homepage)
  • add author: Cambá [email protected]
  • Licence: GPL (same as master)
  • update version to 0.0.0
  • add keywords (similar to topics #18)
  • add repository
 "repository": {
    "type": "git",
    "url": "git+https://github.com/josx/ra-data-feathers.git"
  }
  • add bugs
 "bugs": {
    "url": "https://github.com/Cambalab/vue-admin/issues"
  },
  "homepage": "https://github.com/Cambalab/vue-admin#readme",
  • add publish commands

Mixin proposal for resource components injected with va prop

We're currently handling custom components the following way:

  1. A custom component is passed to Resource by a user
  2. Resource injects a va props into this component with crud functionality
  3. The user accesses it's props to use the crud functions, like this.va.fetchList

Gabi Buenou (aka @glmaljkovich) suggested mixins to inject this functionality. This would not only provide a facility to the user (usage be like: $va.fetchList), but would also help decoupling the binding utils from the resource utils: more information in this WIP

Configure ESLint to enforce coding style consistency

Searching for different options, I think the best choice would be to use prettier because it's less bureaucratic than airbnb. We just want clean and pretty indented/formatted code to enforce a style among contributors.

The vue-cli installs all the required dependencies to get it running. The bad thing is that it automatically fixes all code with it's default configuration (which is not what we're aiming for: we don't want double quotes, for example).

Prettier needs a custom .prettierrc.json file. Looking at the current code, the following rules should not harm the current code so much, plus we intent not to use semicolons and avoid double quotes in plain javascript.

taken from prettier configuration. There are other rules that could be useful.

{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": false,
  "singleQuote": true
}

In order to instantiate prettier we'll have to configure an .eslintrc.json file. I found this one from an old project that could do the trick.

Then I've had a little thought about the fix option that runs by default in the vue-cli-service at npm run lint. I think it would be safer if we disable the auto fix option for that service. We'll be including a pre-commit hook feature to prevent pushing dirty code. That way we can use the npm run lint script just as a code state checker.

Add a unit test for the Delete action

Is your feature request related to a problem? Please describe.
There're no unit tests for the DeleteButton component. It would be nice to implement a simple unit test for that.

Describe the solution you'd like
The test should include:

  • the component initialises with default props
  • the component initialises with given props (those that are not provided by default)
  • onDelete method: the store dispatch method should be called once when clicked
  • onDelete method: the router push method should be called once when clicked

Take the [date input spec] as example.

As a User I can declare Actions in the template (List, Create, Edit, View) as children of a Resource component

The current situation is:

  • Resource accepts a list of objects that declare different attributes of a resource (entity in a db)
  • Resource accepts a custom Vue component and gets a few vue-admin functions injected to perform requests to an API

Our goal:

  • A user should be able to declare a Resource by using a Vue component
  • Resource will be wrapped by a functional component that must provide valid data (props) to the Resource component.
  • VueAdmin must also expose a new functional component for every action (List, Create, Show, Edit)
  • In a first instance this component will work as a wrapper of the original Action component (List, Create, Show, Edit). VueAdmin must manipulate and reorder props as necessary to bring valid data to the Action component.
  • A user should declare UI components such as TextField, TextInput, etc as children of one of the Action components. This component can be exposed or can be native html elements such as p, div, input, etc (To review)

As a user I want to declare permissions to restrict access to my Resource views

Users should be able to declare an array of permissions as a prop of a Resource view. The should also be able to declare a view as private or public, meaning an unauthenticated user should or should not have the rights to visit that view.

An approach would be something like:

<Resource name="articles" ... >
  <View slot="create" :component="CreateArticles" :permissions="['admin', 'developer']" />
  <View slot="show" :component="ShowArticles" :public="true" />
  <View slot="list" :component="ListArticles" />
</Resource>

...where:

  • CreateArticles is not public and restricted to admin and developer permissions only
  • ShowArticles is a public, so that it can be accessed by unauthorized users
  • ListArticles is not public, but not restricted to specific permissions, meaning any unauthorized user has access.

Create Changelog

The best and simplest choice would be to use the github-changelog-generator.

  • We need to add a script in the package.json that runs the changelog, recreates the changelog.md file and commits the change
  • That script should also be added to the npm publish command, so that it gets updated on every release.

Implement spinner/loaders on api calls for user feedback

The best approach would be to take advantage of vuex-crud callbacks, for example:

Full vuex-crud callbacks docs here

  // Callback for POST start
  onCreateStart: () => {
    // Updates the store with an 'isLoading' boolean, attribute
  },
  // Callback for POST success
  onCreateSuccess: () => {
    // Updates the store with an isLoading: false, attribute
    // Here we can also add a success dialog in the future, with an UNDO feature
  },
  // Callback for POST erro
  onCreateError: () => {
    // Updates the store with an isLoading: false, attribute
    // Here we can also add an error dialog in the future
  }

Vuex-crud automatically commits the START, SUCCESS or ERROR state to the store. Then the component (Create in this case) should look up the updated store state with the getter methods and render or hide a spinner depending on the isLoading boolean state.

This issue is an epic to smaller issues for the list, create and edit components.

Centralise defaults modules to a single module

We're currently using defaults modules to get the initial values and validations for the Resource component and the List, Show, Create, Edit views.

We probably want to have a generalized defaults module that can return a defaults object given a string: eg: Resource

Some properties in List are not dynamic

Describe the bug
When a user changes from a resource to another (from articles to magazines, for example), this.name is not updated so that if a user first went to articles List and then navigates to magazines List, then this.name for the magazines Resource is 'articles'.

To Reproduce
Steps to reproduce the behavior:

  • More than 1 resource is needed, it can be tested using the #40 branch
  1. Go to the drawer
  2. Click on articles
  3. Open dev tools and dive to a div with name 'articles-list-container'
  4. Go to the drawer
  5. Click on magazines

Expected behavior
The div name attribute has the same value, it should have changed to 'magazines-list-container'. Use resourceName as a computed property in List.

Use it from Npm package

Right We are using the components thru including components directly

But We need to use it from npm, at first at least installing locally (without uploading to npm registry).

Here is the entry point and We need to expose all components:

To use it from user point of view we need to:

  • npm installl vue-admin
  • import { Admin, Resource } from VueAdmin;

Vuex-Crud Analysis and adaptation

We decided to use vuex-crud for store management. Apaprently the urls are kind of fixed at the moment, for each crud modul.

  • Verify if we can dynamically use the urls on rest calls
  • Use vuex crud along with a data provider cilent
  • Decide if we want to colaborate with vuex-crud to implement a client feature

More documentation

At least We need to write:

  • How to install, configure and run (client)
  • How to install and run test server
  • How to use Admin and resources components
  • How to send props and which props are available

Add Image of the app running to Readme

Is your feature request related to a problem? Please describe.
It would be nice to have a gif showing some of the vue-admin features. The gif could include:

  • Sign in process
  • A tour through a resource views: how a resource is created, how it's edited, etc.

It could be centered placed right after the Introduction brief in the README.md file.

Describe the solution you'd like
Any other ideas are welcome.

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.