Giter VIP home page Giter VIP logo

loopback-workspace's Introduction

LoopBack Workspace 3.0

โš ๏ธ LoopBack 3 is in Maintenance LTS mode, only critical bugs and critical security fixes will be provided. (See Module Long Term Support Policy below.)

We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as soon as possible. Refer to our Migration Guide for more information on how to upgrade.

Overview

The loopback-workspace module provides node.js and REST APIs for interacting with a set of loopback components. Components are organized in the following basic directory structure:

  /my-workspace
    /my-component-a
    /my-component-b
    /my-component-c
    package.json

Each component has the following basic structure:

  /my-component
    config.json
    datasources.json
    model-config.json
    /models
      my-model.json
      my-model.js

Usage

Basic

The loopback-workspace itself is a loopback component. The following will load the workspace in the current working directory (process.cwd()).

// workspace is a loopback `app` object
var workspace = require('loopback-workspace');

Custom Workspace Directory

To start the workspace in a specific directory, specify the WORKSPACE_DIR env variable.

REST

In order to use the REST api, mount the app on an existing express app or call workspace.listen(PORT).

Test

To run end-to-end tests, you will need a local MySQL instance.

Run node test/helpers/setup-mysql.js to create a test database and a test user. This is a one-time task to run only once when setting up your development environment.

Use the npm test command to run the tests.

Module Long Term Support Policy

This module adopts the Module Long Term Support (LTS) policy, with the following End Of Life (EOL) dates:

Version Status Published EOL
4.x Maintenance LTS Sep 2017 Dec 2020
3.x End-of-Life Jul 2014 Apr 2019

Learn more about our LTS plan in the docs.

loopback-workspace's People

Contributors

0candy avatar agnes512 avatar anthonyettinger avatar bajtos avatar candytangnb avatar cgole avatar dallonf avatar deepakrkris avatar dhmlau avatar gunjpan avatar hacksparrow avatar jannyhou avatar jtary avatar kraman avatar loay avatar markdirish avatar nabdelgadir avatar rashmihunt avatar raymondfeng avatar richardpringle avatar ritch avatar rmg avatar sam-github avatar schoonology avatar seanbrookes avatar shimks avatar siddhipai avatar simonhoibm avatar superkhau avatar virkt25 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

Watchers

 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

loopback-workspace's Issues

Models with different cases are mapped to the same file

We can define models as Pet and pet. The runtime can handle that and treat them as different models. But the workspace maps both of them to pet.json. As a result, we lost one of two model definitions.

I understand the file mapping is designed to support operating system such as Mac or Windows which has case-insensitive file names by default.

Should we make model names case insensitive too?

Incorrect handling of `id` flag in discovered model properties

See strongloop/strong-arc#359

Here is the probable cause: Workspace uses id property as an identifier of the ModelProperty instance and provides isId to indicate whether the property is an id property:

"ModelProperty": {
"properties": {
"id": {"type": "string", "id": true, "json": false},
"modelId": {"type": "string", "required": true, "json": false},
"facetName": {"type": "string", "required": true, "json": false},
"name": {"type": "string"},
"type": {"type": "any"},
"isId": {"type": "boolean", "json": "id"},
"generated": {"type": "boolean"},
"required": {"type": "boolean"},
"index": {"type": "boolean"},
"description": {"type": "string"}
},

We need to fix DataSourceDefinition.prototype.createModel to process the data using the same algorithm that is used when loading data from JSON files - see Definition.addRelatedToCache.

unable to delete model definitions (via Studio and explorer)

I have a list of exsting model definitions and have hooked up a command to trigger a deleteById request.

The server is returning a 204 response which indicates things are ok but the model definition keeps coming back when querying all model definitions.

Here's a screenshot from my local explorer view showing what happens when attempting to delete:
screenshot

Templating enhancements

  • Workspace.getAvailableTemplates - add template description, return an array of {name, description}.
  • Distinguish between project templates and component templates. Project templates should include files like .gitignore and dependencies in package.json, they are intended for yo loopback. Component templates may be exposed via yo loopback:component.

not able to find DataSourceDefinitions after initial POST

using the explorer interface I'm posting the following DataSourceDefinition:

{
    "defaultForType": "mysql",
    "name": "apmweb",
    "connector": "loopback-connector-mysql",
    "host": "demo.strongloop.com",
    "port": 3306,
    "facetName": "common",
    "database": "demo",
    "username": "demo******",
    "password": "**********"
}

The server is responding with a 200 / success and a valid JSON object response but when I try to GET the datasources it is not returned.

I checked the filesystem datasource.json but there is no record of the new DSDef. in there either.

dspost

image

Refactor loopback-explorer integration in app.js template

See the discussion in #33. We are trying to move app.start from loopback-explorer to loopback. The current integration with loopback-explorer is causing troubles:

  • workspace's app.js is loading the module
  • loopback's app.start wants to report the explorer's URL

Proposed solution:

  1. The code loading plugins (i.e. loopback-explorer) is responsible for handling the case where the module is not available.
  2. The plugin (loopback-explorer) is responsible for reporting information useful to the user. The message should be printed from an even handler listening on a new "start" event that is emitted by the app.start().

ModelDefinition.create doesn't seem to be working

I cloned the repo

  • ran npm install
  • started the app
  • navigated to 'explorer'
  • posted a 'new' ModelDefinition' with a 'facetName'
  • got a 200 response indicating the model had been created successfully
  • when to 'GET' ModelDefnitions and it returned an empty collection
  • I don't see a .js file anywhere in the project structure by the name of ModelDefninition I created

Getting odd responses from server when submiting invalid config objects

If I submit an invalid object for a ModelDefinition or a ModelProperty I get the same message (see below). It looks like JSON.stringify run amok. But it would help to get more detailed errors when something goes wrong.

To reproduce:

  • start the server
  • go to explorer
  • paste the following into ModelDefnition POST entry:
{
"idInjection": false,
"name": "123dddewdedsdgsdfsdfsdfsdf"
}

note it is missing 'facetName' required property

TypeError: Converting circular structure to JSON
at Object.stringify (native)
at errorHandler (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/errorhandler/index.js:96:23)
at Layer.handle_error (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/layer.js:52:5)
at trim_prefix (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:261:13)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:230:9
at proto.process_params (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:305:12)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:221:12
at Function.match_layer (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:288:3)
at next (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:182:10)

at Layer.handle_error (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/layer.js:48:12)

at all (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/connectors/memory.js:320:11)
at EventEmitter.<anonymous> (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:196:17)
at g (events.js:180:16)
at EventEmitter.emit (events.js:92:17)
at done (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:101:14)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/async/lib/async.js:254:17

at connector.loadFromFile (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:92:10)
at connector.all (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:193:13)
at Function.find (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/dao.js:715:34)
at validateUniqueness (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/validations.js:345:20)
at validationFailed (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/validations.js:540:13)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/validations.js:439:11
at process._tickCallback (node.js:415:13)

at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/validations.js:438:17
at Array.forEach (native)
at ModelConstructor.<anonymous> (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/validations.js:434:35)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/hooks.js:53:14
at injectFacetName (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/models/workspace-entity.js:147:12)
at ModelConstructor.trigger (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/hooks.js:46:18)
at Validatable.isValid (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/validations.js:430:8)
at DataAccessObject.create (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/dao.js:152:7)

at all (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/connectors/memory.js:320:11)
at EventEmitter.<anonymous> (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:196:17)
at g (events.js:180:16)
at EventEmitter.emit (events.js:92:17)
at done (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:101:14)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/async/lib/async.js:254:17

at connector.loadFromFile (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:92:10)
at connector.all (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/connector.js:193:13)
at Function.find (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback-datasource-juggler/lib/dao.js:715:34)
at ACL.checkAccessForContext (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/lib/models/acl.js:397:8)
at Model.checkAccess (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/lib/models/model.js:240:12)
at Function.<anonymous> (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/lib/application.js:315:13)
at execStack (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:344:11)
at RemoteObjects.execHooks (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:350:10)

at module.exports (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/body-parser/node_modules/raw-body/index.js:93:10)
at read (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/body-parser/lib/read.js:65:3)
at jsonParser (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/body-parser/lib/types/json.js:83:5)
at handle (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/layer.js:76:5)
at trim_prefix (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:263:13)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:230:9
at proto.process_params (/Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:305:12)
at /Users/seanbrookes/_stacks/projects/strongloop/strongloop-api-studio/node_modules/loopback-workspace/node_modules/loopback/node_modules/express/lib/router/index.js:221:12

Turn on `strict` mode on models

Turn on strict mode on all models where it makes sense, i.e. all models except
ComponentDefinition (config) and DatasourceDefinition. This will force use to describe all properties in models.json. Once done, it should remove one source of possible errors in applications using loopback-workspace.

cookieParser uses a single string argument

Creating a new project via slc lb project some-name creates an application that will do nothing but through TypeError exceptions:

csalch@Chriss-MacBook-Air ~/code/bestfit/surdell/example/blue $ PORT=9000 npm start

> [email protected] start /Users/csalch/code/bestfit/surdell/example/blue
> node app.js

StrongOps not configured to monitor. Please refer to http://docs.strongloop.com/strong-agent for usage.
connect.multipart() will be removed in connect 3.0
visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives
connect.limit() will be removed in connect 3.0
Browse your REST API at http://0.0.0.0:9000/explorer
LoopBack server listening @ http://0.0.0.0:9000/
TypeError: secret required
    at Object.exports.unsign (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/cookie-signature/index.js:39:40)
    at /Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/utils.js:179:23
    at Array.forEach (native)
    at Object.exports.parseSignedCookies (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/utils.js:176:20)
    at Object.cookieParser [as handle] (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js:56:37)
    at next (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:193:15)
    at Object.logger (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/middleware/logger.js:158:5)
    at next (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:193:15)
    at Object.favicon [as handle] (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/middleware/favicon.js:77:7)
    at next (/Users/csalch/code/bestfit/surdell/example/blue/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:193:15)
GET / 400 15ms

It looks like cookieParser is being passed an improper argument.

Support async boot scripts OOTB

We need to rework server/server.js template to support async boot scripts.

boot(app, __dirname, function(err) {
  if (err) throw err;
  // start the server if `$ node server.js`
  if (require.main === module) {
    app.start();
  });

In order to support the scenario when the app is loaded via require but not started, e.g. in loopback-sdk-angular-cli, we need to modify loopback-boot to emit an event when the boot process is finished, e.g. app.emit('ready').

Tasks

Workspace.createFromTemplate in an existing project

At the moment, when the user calls yo loopback (Workspace.createFromTemplate), the workspace is reset to the initial state, discarding any existing entities.

We need a better implementation.

Option A

Allow yo loopback to provide a custom implementation of fs functions like writeJson and unlink. That way the user can be presented with a diff when a json file is being overwritten, and unlink can be changed to no-op.

While this is good enough for yo loopback, it does not solve the problem for the Studio.

Option B

Modify createFromTemplate to intelligently merge existing entities with template entities. The first run of createFromTemplate should upgrade the project to the latest template version, the second and subsequent runs would be no-ops.

@ritch Thoughts?

Validate relations

Any model belonging to a facet should validate that the facetName matches an existing facet.

DataSourceConfig and ModelConfig should also validate that the facet is of app type (see #100).

ModelProperty must belong to an existing model (see strongloop/strong-arc#93)

nesting package.json files in LB project causes corruption when saving datasource

not sure if this is specific to datasource save flow in Arc but the use case is:

  • I have a LB/Arc project.
  • it has a 'sub project' for a node app running on a tessel device.
  • I was trying to keep the tessel app code in a folder within my LB project so the code was all in one place
    eg:
    root/
    ../client/
    ../server/
    ../tessel/
    • package.json
      ...
      package.json
  • when I try to save a data source definition I get an error message in the UI indicating the package.json is corrupted.

It looks like LB is doing some kind of recursion through the project files and picking up both package.json files.

Shorthand property definition, anonymous complex types

We need to implement support for all exotic flavours of LDL property definitions.

{
  // a shorthand notation using a string instead of `{ type: 'string' } `
  shorthand: 'string',

  // an array type - shorthand notation
  arrayOfModels: ['User']

  // an array type - full notation
  arrayOfModels2: { type: ['User'] }

  // anonymous object type - shorthand version
  anonymous1: { apns: { production: 'boolean' }, gcm: { serverApiKey: 'string' } }

  // anonymous object type - full notation
  anonymous2: { type: { apns: { production: 'boolean' }, gcm: { serverApiKey: 'string' } } }

  // array of anonymous types
  anonArray: { type: [ { apns: { production: 'boolean' }, gcm: { serverApiKey: 'string' } } ] }
}

Discuss at F2F, Define and Document Components

This is a placeholder to discuss and define the component architecture. We should flesh out the following:

@bajtos @raymondfeng

Why use components

  • Organize models and datasources for a feature
  • Generic code that can be reused once configured
  • Prevent generated code being duplicated in every loopback app

How to define a component

  • In a package.json define a loopback-component object?
  • Just re-use package dependencies?
  • Use package name and other package.json ?
  • Use config.json in a Facet?

How to reuse a component in several apps

  • Template? Eg. use a template to generate models, datasource and other config.
  • Dependency? Eg. setup a dependency which isn't modified.

Extend or use models from other components

  • loopback.getModel() we could support facet ids... otherwise we might get collisions for names
  • import - Eg. modelConfig._meta.sources

Attach to datasources from other components

  • Need to be able to use a datasource from a component without referencing it directly Eg. di

Know when a component is ready

  • Components need to be able to have access to stable state of an app or other components.

Extend a component

  • Modify code directly Eg. using a template, modify the generated code
  • Extend models and modify config

Configure a component

  • Models, datasources, facets, etc

Component API (Workspace)

  • Add a component to an app
  • List available components?

strange behaviour b/w ModelDefinition and ModelProperty with rendered angular interface

I'm seeing some strange behaviour when i try to create a new ModelProperty.

If I try to call ModelProperty.create(config) with a valid property config object the app calls:

POST ///api/ModelDefnition - and creates a new model definition.

However if I switch the call to ModelDefinition.create(config) with a valid model property config object it calls:

POST ///api/ModelProperty/model.id - which is correct but shouldn't the call be going to ModelProperty instead of ModelDefinition?

including a screenshot of my current loopback-workspace package json:
screenshot

Support dynamic template files

At the moment, workspace template files are static, they are simply copied from workspace to the scaffolded project.

In some places, like the generated README, we need the ability to generate the content dynamically.

In order to do that, loopback-workspace should support a templating language like handlebars in the template files.

See also #177

Miroslav's TODO for yeoman

List of changes required by yo loopback:
#62

  • Remove id from the generated ACL entries in models.json
    #71
  • Simplify app.started, drop started event in favour of listening (see strongloop/loopback#357).
    #69
  • Provide a hook allowing workspace API consumers to supply custom ncp implementation, e.g. yeoman's directory function.
    #61
  • ensure js files are generated (rest/rest.js, server/server.js)
    #63
  • Depending on the component type, some configuration files are optional. E.g. the empty root component does not need any *.json files.
  • Remove workspace metadata from generated JSON files, e.g. componentName and configFile in rest/datasources.json, componentName in server/models.json.
  • package.json generated by the current template sets name to . instead of the project name.
  • implement Workspace.isValidDir (see Project.isValidProjectDir in 2.x)
  • Fix boot: include loopback-boot 2.x in package.json, drop email datasource, use capital model names in rest/models.json (User instead of user).
  • API: make componentName required in all entities
  • Refactor the server template to use the boot-based registration of middleware (see example-full-stack).
    #56
  • Modify value provides in models/model-access-control.js, use {name, value} instead of {value, humanized}.

which endpoint to use for discovery on a datasource

If I manually create a DataSourceDefinition in the target app /server/datasource.json file and then start studio I can see the datasource listed when I do a GET on the DataSourceDefintion. I can then use the id value to make sure the DataSourceDefinition rest end point is working by getting the definition via id.

But I want to use the new DSDef. to trigger the discovery flow but I can't see which end-point / method to use to trigger discovery.

I checked the GH readme and searched for 'schema' in the lbservices file but no luck.

Looking for insight

Middleware entities

Add the MiddlewareDefinition and MiddlewareConfig entities.

MiddlewareDefinition should map to a my-middleware.json file.
MiddlewareConfig should map to a server/middleware.json file.

Support `.key` and `.option.key` for ModelDefinition properties

loopback.createModel reads model settings from two places: top-level object (e.g. .base) or from the nested options object (e.g. .options.base).

loopback-workspace should support this dual format.

To keep things simple, we can normalize the model definition when it is loaded from the JSON file and support only single format when saving back to filesystem.

Clarification of Workspace purpose

@bajtos After a conversation with @altsang I realize that Workspace 3.0 goes well beyond what the simple project tagline states. Apparently models/properties can be defined through a Workspace. Since this is something I'm working on myself (but differently), I need to make sure there won't be any collisions along the way, should I keep my own implementation going forward. I can already see model names clashing with my setup.

Also, now that functionality like push and passport integration has been generalized into components, I wonder if there will be a mandatory dependency on Workspace for LoopBack projects. In other words, will these components work without Workspace? I presume this is still optional, with Workspace being a component itself.

Transactional loading of artifacts

I'd like to start thinking about a new design of workspace that will fix some fundamental issues with 3.0:

Issues

  • generating ids from keys in the file or file names is not practical since the API supports modifying different entities separately
  • renaming is difficult to implement and prone to weird bugs
  • sometimes unrelated files are loaded
  • overlap in functionality with loopback-boot

Initial 4.0 design

// in node
Workspace.load('path/to/workspace', function(err, workspace) {
  // all files are loaded an available for reading / writing their contents
  // in memory

  // renaming a model
  var modelDefinition = workspace.modelDefinitions.findByName('SomeName');
  var modelConfig = workspace.modelConfigs.findByName('SomeName');
  modelDefinition.name = modelConfig.name = 'MyNewName';

  // creating a model
  workspace.modelDefinitions.create('MyNewModel', ...);
  workspace.modelConfigs.create('MyNewModel', ...);

  // NOTE: all of the methods are sync (no callbacks)
  workspace.dataSourceDefinitions.create('MyDataSource', ...);

  // attach a data source
  workspace.modelConfigs.findByName('SomeName').dataSource = 'MyDataSource';

  workspace.save(function(err) {
    // validation errors (err) or
    // contents written to disk
  });
});

// in node / browser
Workspace.observe('file changed', function(file) {
  // notify the user
  // or merge the changes
});

// in a browser / arc (with browserify)
Workspace.load('path/to/workspace', function(err, workspace) {
  // same as above
});

Workspace.load() should either lock the workspace root or queue subsequent calls to ensure only one callback is modifying a workspace at a time.

@bajtos @seanbrookes thoughts?

Component entities

  • Define a Component model, add relation Component hasMany facets via Facet.componentName foreign key. Rework all id generators to use the component name as the first part of the id, e.g. loopback.common.User. To preserve backwards compatibility, the entities in the project itself should have empty component name.
  • Rework the code loading entities from file system to detect components in node_modules and load them too.

Out of scope: support for multi-component projects, where the top-level directory is not a component, but contains a set of component directories instead.

Support model options defined as `options.key` instead of `key`

The old models.json contained model options like base or relations nested inside options key:

{
  "Car": {
    "options": {
      "base": "Model"
    }
  }
}

LoopBack workspace should support this old format when loading model definitions and upgrade it to the new format.

See also buildModelOptionsFromConfig in loopback/lib/registry.js

Error and crash when attemting to verify datasource connection

I am able to create a DataSourceDefinition via explorer and then can do a GET and see the new DS in the results. However if I copy the id from the new DSDef and attempt to test the connection the studio app crashes and throws an exception (full trace below)-

WARNING: LoopBack connector "loopback-connector-mysql" is not installed as any of the following modules:

 ./connectors/loopback-connector-mysql
loopback-connector-mysql

To fix, run:

    npm install loopback-connector-mysql

/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/longjohn/dist/longjohn.js:185
        throw e;
              ^
TypeError: Object #<DataSource> has no method 'connect'

I have installed the mysql connector on both the studio app and the target testapp but same thing happens.
Here is the explorer screen shot:

screenshot

Here are the package.json files:
#1) Studio app

{
  "name": "strong-studio",
  "version": "0.0.1",
  "main": "app.js",
  "bin": {
    "strongloop-api-studio": "server.js"
  },
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "loopback": "1.x >=1.7.0",
    "loopback-angular": "^1.1.0",
    "loopback-connector-mongodb": "^1.2.2",
    "protractor": "^0.22.0",
    "request": "^2.34.0",
    "loopback-datasource-juggler": "^1.3.11",
    "loopback-connector-mysql": "^1.2.0",
    "gulp": "^3.6.2",
    "gulp-changed": "^0.3.0",
    "gulp-minify-html": "^0.1.3",
    "loopback-explorer": "~1.1.0",
    "loopback-push-notification": "~1.2.0"
  },
  "optionalDependencies": {
    "loopback-explorer": "~1.1.0",
    "loopback-push-notification": "~1.2.0"
  },
  "description": "A gui for working with the LoopBack framework",
  "devDependencies": {},
  "repository": {
    "type": "git",
    "url": "https://github.com/strongloop/strong-studio.git"
  },
  "keywords": [
    "studio",
    "loopback"
  ],
  "author": "Sean Brookes",
  "homepage": "https://github.com/strongloop/strong-studio"
}

#2) testapp (target)

{
  "name": "testapp",
  "version": "0.0.0",
  "main": "server/server.js",
  "scripts": {
    "pretest": "jshint ."
  },
  "dependencies": {
    "compression": "^1.0.3",
    "errorhandler": "^1.1.1",
    "loopback": "^2.0.0",
    "loopback-boot": "^2.0.0",
    "loopback-datasource-juggler": "^2.0.0",
    "serve-favicon": "^2.0.1",
    "loopback-connector-mysql": "^1.4.1"
  },
  "optionalDependencies": {
    "loopback-explorer": "^1.1.0"
  }
}

Full console trace:

GET /api/DataSourceDefinitions 304 80.804 ms - -

WARNING: LoopBack connector "loopback-connector-mysql" is not installed as any of the following modules:

 ./connectors/loopback-connector-mysql
loopback-connector-mysql

To fix, run:

    npm install loopback-connector-mysql


/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/longjohn/dist/longjohn.js:185
        throw e;
              ^
TypeError: Object #<DataSource> has no method 'connect'
    at DataSourceDefinition.testConnection (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/models/data-source-definition.js:50:14)
    at SharedMethod.invoke (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:207:17)
    at HttpContext.invoke (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/http-context.js:243:12)
    at /Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:475:9
    at execStack (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:346:7)
    at /Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/lib/application.js:326:13
    at /Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/lib/models/model.js:250:5
    at /Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/lib/models/acl.js:443:19
    at /Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/async/lib/async.js:254:17
    at async.each (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/async/lib/async.js:121:20)
---------------------------------------------
    at all (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback-datasource-juggler/lib/connectors/memory.js:320:11)
    at EventEmitter.<anonymous> (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/connector.js:196:17)
    at g (events.js:180:16)
    at EventEmitter.emit (events.js:92:17)
    at done (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/connector.js:101:14)
    at /Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/async/lib/async.js:254:17
---------------------------------------------
    at connector.loadFromFile (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/connector.js:92:10)
    at connector.all (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/connector.js:193:13)
    at Function.find (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback-datasource-juggler/lib/dao.js:715:34)
    at ACL.checkAccessForContext (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/lib/models/acl.js:397:8)
    at Model.checkAccess (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/lib/models/model.js:240:12)
    at ModelConstructor.<anonymous> (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/lib/application.js:315:13)
    at execStack (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:344:11)
    at RemoteObjects.execHooks (/Users/seanbrookes/_stacks/projects/strongloop/workspace/loopback-workspace/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:350:10)

Update `api-server` template to use the new declarative middleware registration

strongloop/loopback#739 and strongloop/loopback-boot#44 implement a declarative solution for registering components via middleware.json.

We should update the api-server template to use this new mechanism.

Tasks

Out of scope

Random Require

@Schoonology Running some tests using the workspace... Somehow I'm seeing this:

// import data
require('../../../../../asteroid-sample-app/test-data/import')(thing);

in the output of my model creation.

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.