feat(apps): lots of more work on apps, changed app_plugin to app_settings in order to to confuse the app plugin model (definition) and app org settings

pull/3712/head
Torkel Ödegaard 10 years ago
parent ab79348af5
commit c1e94e61d0
  1. 9
      pkg/api/api.go
  2. 63
      pkg/api/app_plugin.go
  3. 59
      pkg/api/app_settings.go
  4. 9
      pkg/api/datasources.go
  5. 13
      pkg/api/dtos/app_plugin.go
  6. 31
      pkg/api/dtos/apps.go
  7. 5
      pkg/api/frontendsettings.go
  8. 6
      pkg/api/index.go
  9. 13
      pkg/models/app_settings.go
  10. 76
      pkg/plugins/plugins.go
  11. 96
      pkg/plugins/queries.go
  12. 18
      pkg/services/sqlstore/app_settings.go
  13. 14
      pkg/services/sqlstore/migrations/app_settings.go
  14. 2
      pkg/services/sqlstore/migrations/migrations.go
  15. 2
      public/app/core/routes/all.js
  16. 1
      public/app/features/apps/all.ts
  17. 5
      public/app/features/apps/app_srv.ts
  18. 28
      public/app/features/apps/edit_ctrl.ts
  19. 6
      public/app/features/apps/list_ctrl.ts
  20. 10
      public/app/features/apps/partials/edit.html
  21. 5
      public/app/features/apps/partials/list.html
  22. 6
      public/less/filter-list.less
  23. 3
      tasks/options/watch.js

@ -41,8 +41,8 @@ func Register(r *macaron.Macaron) {
r.Get("/admin/orgs", reqGrafanaAdmin, Index) r.Get("/admin/orgs", reqGrafanaAdmin, Index)
r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index) r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
r.Get("/org/apps", reqSignedIn, Index) r.Get("/apps", reqSignedIn, Index)
r.Get("/org/apps/edit/*", reqSignedIn, Index) r.Get("/apps/edit/*", reqSignedIn, Index)
r.Get("/dashboard/*", reqSignedIn, Index) r.Get("/dashboard/*", reqSignedIn, Index)
r.Get("/dashboard-solo/*", reqSignedIn, Index) r.Get("/dashboard-solo/*", reqSignedIn, Index)
@ -119,8 +119,9 @@ func Register(r *macaron.Macaron) {
r.Patch("/invites/:code/revoke", wrap(RevokeInvite)) r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
// apps // apps
r.Get("/apps", wrap(GetAppPlugins)) r.Get("/apps", wrap(GetOrgAppsList))
r.Post("/apps", bind(m.UpdateAppPluginCmd{}), wrap(UpdateAppPlugin)) r.Get("/apps/:appId/settings", wrap(GetAppSettingsById))
r.Post("/apps/:appId/settings", bind(m.UpdateAppSettingsCmd{}), wrap(UpdateAppSettings))
}, reqOrgAdmin) }, reqOrgAdmin)
// create new org // create new org

@ -1,63 +0,0 @@
package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
)
func GetAppPlugins(c *middleware.Context) Response {
query := m.GetAppPluginsQuery{OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to list Plugin Bundles", err)
}
translateToDto := func(app *plugins.AppPlugin) *dtos.AppPlugin {
return &dtos.AppPlugin{
Name: app.Name,
Type: app.Type,
Enabled: app.Enabled,
Pinned: app.Pinned,
Module: app.Module,
Info: &app.Info,
}
}
seenApps := make(map[string]bool)
result := make([]*dtos.AppPlugin, 0)
for _, orgApp := range query.Result {
if def, ok := plugins.Apps[orgApp.Type]; ok {
pluginDto := translateToDto(def)
pluginDto.Enabled = orgApp.Enabled
pluginDto.JsonData = orgApp.JsonData
result = append(result, pluginDto)
seenApps[orgApp.Type] = true
}
}
for _, app := range plugins.Apps {
if _, ok := seenApps[app.Type]; !ok {
result = append(result, translateToDto(app))
}
}
return Json(200, result)
}
func UpdateAppPlugin(c *middleware.Context, cmd m.UpdateAppPluginCmd) Response {
cmd.OrgId = c.OrgId
if _, ok := plugins.Apps[cmd.Type]; !ok {
return ApiError(404, "App type not installed.", nil)
}
err := bus.Dispatch(&cmd)
if err != nil {
return ApiError(500, "Failed to update App Plugin", err)
}
return ApiSuccess("App updated")
}

@ -0,0 +1,59 @@
package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
)
func GetOrgAppsList(c *middleware.Context) Response {
orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
if err != nil {
return ApiError(500, "Failed to list of apps", err)
}
result := make([]*dtos.AppSettings, 0)
for _, app := range plugins.Apps {
orgApp := orgApps[app.Id]
result = append(result, dtos.NewAppSettingsDto(app, orgApp))
}
return Json(200, result)
}
func GetAppSettingsById(c *middleware.Context) Response {
appId := c.Params(":appId")
if pluginDef, exists := plugins.Apps[appId]; !exists {
return ApiError(404, "PluginId not found, no installed plugin with that id", nil)
} else {
orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
if err != nil {
return ApiError(500, "Failed to get org app settings ", nil)
}
orgApp := orgApps[appId]
return Json(200, dtos.NewAppSettingsDto(pluginDef, orgApp))
}
}
func UpdateAppSettings(c *middleware.Context, cmd m.UpdateAppSettingsCmd) Response {
appId := c.Params(":appId")
cmd.OrgId = c.OrgId
cmd.AppId = appId
if _, ok := plugins.Apps[cmd.AppId]; !ok {
return ApiError(404, "App type not installed.", nil)
}
err := bus.Dispatch(&cmd)
if err != nil {
return ApiError(500, "Failed to update App Plugin", err)
}
return ApiSuccess("App updated")
}

@ -118,12 +118,10 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
func GetDataSourcePlugins(c *middleware.Context) { func GetDataSourcePlugins(c *middleware.Context) {
dsList := make(map[string]*plugins.DataSourcePlugin) dsList := make(map[string]*plugins.DataSourcePlugin)
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} if enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId); err != nil {
err := bus.Dispatch(&orgApps)
if err != nil {
c.JsonApiErr(500, "Failed to get org apps", err) c.JsonApiErr(500, "Failed to get org apps", err)
} return
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result) } else {
for key, value := range enabledPlugins.DataSources { for key, value := range enabledPlugins.DataSources {
if !value.BuiltIn { if !value.BuiltIn {
@ -133,3 +131,4 @@ func GetDataSourcePlugins(c *middleware.Context) {
c.JSON(200, dsList) c.JSON(200, dsList)
} }
}

@ -1,13 +0,0 @@
package dtos
import "github.com/grafana/grafana/pkg/plugins"
type AppPlugin struct {
Name string `json:"name"`
Type string `json:"type"`
Enabled bool `json:"enabled"`
Pinned bool `json:"pinned"`
Module string `json:"module"`
Info *plugins.PluginInfo `json:"info"`
JsonData map[string]interface{} `json:"jsonData"`
}

@ -0,0 +1,31 @@
package dtos
import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
)
type AppSettings struct {
Name string `json:"name"`
AppId string `json:"appId"`
Enabled bool `json:"enabled"`
Pinned bool `json:"pinned"`
Info *plugins.PluginInfo `json:"info"`
JsonData map[string]interface{} `json:"jsonData"`
}
func NewAppSettingsDto(def *plugins.AppPlugin, data *models.AppSettings) *AppSettings {
dto := &AppSettings{
AppId: def.Id,
Name: def.Name,
Info: &def.Info,
}
if data != nil {
dto.Enabled = data.Enabled
dto.Pinned = data.Pinned
dto.Info = &def.Info
}
return dto
}

@ -29,14 +29,11 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
datasources := make(map[string]interface{}) datasources := make(map[string]interface{})
var defaultDatasource string var defaultDatasource string
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
err := bus.Dispatch(&orgApps)
if err != nil { if err != nil {
return nil, err return nil, err
} }
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
for _, ds := range orgDataSources { for _, ds := range orgDataSources {
url := ds.Url url := ds.Url

@ -2,7 +2,6 @@ package api
import ( import (
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
@ -69,14 +68,11 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
}) })
} }
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
err = bus.Dispatch(&orgApps)
if err != nil { if err != nil {
return nil, err return nil, err
} }
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
for _, plugin := range enabledPlugins.Apps { for _, plugin := range enabledPlugins.Apps {
if plugin.Module != "" { if plugin.Module != "" {
data.PluginModules = append(data.PluginModules, plugin.Module) data.PluginModules = append(data.PluginModules, plugin.Module)

@ -2,9 +2,9 @@ package models
import "time" import "time"
type AppPlugin struct { type AppSettings struct {
Id int64 Id int64
Type string AppId string
OrgId int64 OrgId int64
Enabled bool Enabled bool
Pinned bool Pinned bool
@ -18,19 +18,18 @@ type AppPlugin struct {
// COMMANDS // COMMANDS
// Also acts as api DTO // Also acts as api DTO
type UpdateAppPluginCmd struct { type UpdateAppSettingsCmd struct {
Type string `json:"type" binding:"Required"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Pinned bool `json:"pinned"` Pinned bool `json:"pinned"`
JsonData map[string]interface{} `json:"jsonData"` JsonData map[string]interface{} `json:"jsonData"`
Id int64 `json:"-"` AppId string `json:"-"`
OrgId int64 `json:"-"` OrgId int64 `json:"-"`
} }
// --------------------- // ---------------------
// QUERIES // QUERIES
type GetAppPluginsQuery struct { type GetAppSettingsQuery struct {
OrgId int64 OrgId int64
Result []*AppPlugin Result []*AppSettings
} }

@ -13,7 +13,6 @@ import (
"text/template" "text/template"
"github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@ -180,78 +179,3 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
return loader.Load(jsonParser, currentDir) return loader.Load(jsonParser, currentDir)
} }
func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins {
enabledPlugins := NewEnabledPlugins()
orgAppsMap := make(map[string]*models.AppPlugin)
for _, orgApp := range orgApps {
orgAppsMap[orgApp.Type] = orgApp
}
seenPanels := make(map[string]bool)
seenApi := make(map[string]bool)
for appType, installedApp := range Apps {
var app AppPlugin
app = *installedApp
// check if the app is stored in the DB for this org and if so, use the
// state stored there.
if b, ok := orgAppsMap[appType]; ok {
app.Enabled = b.Enabled
app.Pinned = b.Pinned
}
// if app.Enabled {
// for _, d := range app.DatasourcePlugins {
// if ds, ok := DataSources[d]; ok {
// enabledPlugins.DataSourcePlugins[d] = ds
// }
// }
// for _, p := range app.PanelPlugins {
// if panel, ok := Panels[p]; ok {
// if _, ok := seenPanels[p]; !ok {
// seenPanels[p] = true
// enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
// }
// }
// }
// for _, a := range app.ApiPlugins {
// if api, ok := ApiPlugins[a]; ok {
// if _, ok := seenApi[a]; !ok {
// seenApi[a] = true
// enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
// }
// }
// }
// enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, &app)
// }
}
// add all plugins that are not part of an App.
for d, installedDs := range DataSources {
if installedDs.App == "" {
enabledPlugins.DataSources[d] = installedDs
}
}
for p, panel := range Panels {
if panel.App == "" {
if _, ok := seenPanels[p]; !ok {
seenPanels[p] = true
enabledPlugins.Panels = append(enabledPlugins.Panels, panel)
}
}
}
for a, api := range ApiPlugins {
if api.App == "" {
if _, ok := seenApi[a]; !ok {
seenApi[a] = true
enabledPlugins.ApiList = append(enabledPlugins.ApiList, api)
}
}
}
return enabledPlugins
}

@ -0,0 +1,96 @@
package plugins
import (
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
)
func GetOrgAppSettings(orgId int64) (map[string]*m.AppSettings, error) {
query := m.GetAppSettingsQuery{OrgId: orgId}
if err := bus.Dispatch(&query); err != nil {
return nil, err
}
orgAppsMap := make(map[string]*m.AppSettings)
for _, orgApp := range query.Result {
orgAppsMap[orgApp.AppId] = orgApp
}
return orgAppsMap, nil
}
func GetEnabledPlugins(orgId int64) (*EnabledPlugins, error) {
enabledPlugins := NewEnabledPlugins()
orgApps, err := GetOrgAppSettings(orgId)
if err != nil {
return nil, err
}
seenPanels := make(map[string]bool)
seenApi := make(map[string]bool)
for appType, installedApp := range Apps {
var app AppPlugin
app = *installedApp
// check if the app is stored in the DB for this org and if so, use the
// state stored there.
if b, ok := orgApps[appType]; ok {
app.Enabled = b.Enabled
app.Pinned = b.Pinned
}
// if app.Enabled {
// for _, d := range app.DatasourcePlugins {
// if ds, ok := DataSources[d]; ok {
// enabledPlugins.DataSourcePlugins[d] = ds
// }
// }
// for _, p := range app.PanelPlugins {
// if panel, ok := Panels[p]; ok {
// if _, ok := seenPanels[p]; !ok {
// seenPanels[p] = true
// enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
// }
// }
// }
// for _, a := range app.ApiPlugins {
// if api, ok := ApiPlugins[a]; ok {
// if _, ok := seenApi[a]; !ok {
// seenApi[a] = true
// enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
// }
// }
// }
// enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, &app)
// }
}
// add all plugins that are not part of an App.
for d, installedDs := range DataSources {
if installedDs.App == "" {
enabledPlugins.DataSources[d] = installedDs
}
}
for p, panel := range Panels {
if panel.App == "" {
if _, ok := seenPanels[p]; !ok {
seenPanels[p] = true
enabledPlugins.Panels = append(enabledPlugins.Panels, panel)
}
}
}
for a, api := range ApiPlugins {
if api.App == "" {
if _, ok := seenApi[a]; !ok {
seenApi[a] = true
enabledPlugins.ApiList = append(enabledPlugins.ApiList, api)
}
}
}
return &enabledPlugins, nil
}

@ -8,27 +8,27 @@ import (
) )
func init() { func init() {
bus.AddHandler("sql", GetAppPlugins) bus.AddHandler("sql", GetAppSettings)
bus.AddHandler("sql", UpdateAppPlugin) bus.AddHandler("sql", UpdateAppSettings)
} }
func GetAppPlugins(query *m.GetAppPluginsQuery) error { func GetAppSettings(query *m.GetAppSettingsQuery) error {
sess := x.Where("org_id=?", query.OrgId) sess := x.Where("org_id=?", query.OrgId)
query.Result = make([]*m.AppPlugin, 0) query.Result = make([]*m.AppSettings, 0)
return sess.Find(&query.Result) return sess.Find(&query.Result)
} }
func UpdateAppPlugin(cmd *m.UpdateAppPluginCmd) error { func UpdateAppSettings(cmd *m.UpdateAppSettingsCmd) error {
return inTransaction2(func(sess *session) error { return inTransaction2(func(sess *session) error {
var app m.AppPlugin var app m.AppSettings
exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&app) exists, err := sess.Where("org_id=? and app_id=?", cmd.OrgId, cmd.AppId).Get(&app)
sess.UseBool("enabled") sess.UseBool("enabled")
sess.UseBool("pinned") sess.UseBool("pinned")
if !exists { if !exists {
app = m.AppPlugin{ app = m.AppSettings{
Type: cmd.Type, AppId: cmd.AppId,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
Enabled: cmd.Enabled, Enabled: cmd.Enabled,
Pinned: cmd.Pinned, Pinned: cmd.Pinned,

@ -2,14 +2,14 @@ package migrations
import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
func addAppPluginMigration(mg *Migrator) { func addAppSettingsMigration(mg *Migrator) {
var appPluginV2 = Table{ appSettingsV1 := Table{
Name: "app_plugin", Name: "app_settings",
Columns: []*Column{ Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "org_id", Type: DB_BigInt, Nullable: true}, {Name: "org_id", Type: DB_BigInt, Nullable: true},
{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "app_id", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "enabled", Type: DB_Bool, Nullable: false}, {Name: "enabled", Type: DB_Bool, Nullable: false},
{Name: "pinned", Type: DB_Bool, Nullable: false}, {Name: "pinned", Type: DB_Bool, Nullable: false},
{Name: "json_data", Type: DB_Text, Nullable: true}, {Name: "json_data", Type: DB_Text, Nullable: true},
@ -17,12 +17,12 @@ func addAppPluginMigration(mg *Migrator) {
{Name: "updated", Type: DB_DateTime, Nullable: false}, {Name: "updated", Type: DB_DateTime, Nullable: false},
}, },
Indices: []*Index{ Indices: []*Index{
{Cols: []string{"org_id", "type"}, Type: UniqueIndex}, {Cols: []string{"org_id", "app_id"}, Type: UniqueIndex},
}, },
} }
mg.AddMigration("create app_plugin table v2", NewAddTableMigration(appPluginV2)) mg.AddMigration("create app_settings table v1", NewAddTableMigration(appSettingsV1))
//------- indexes ------------------ //------- indexes ------------------
addTableIndicesMigrations(mg, "v2", appPluginV2) addTableIndicesMigrations(mg, "v3", appSettingsV1)
} }

@ -18,7 +18,7 @@ func AddMigrations(mg *Migrator) {
addApiKeyMigrations(mg) addApiKeyMigrations(mg)
addDashboardSnapshotMigrations(mg) addDashboardSnapshotMigrations(mg)
addQuotaMigration(mg) addQuotaMigration(mg)
addAppPluginMigration(mg) addAppSettingsMigration(mg)
addSessionMigration(mg) addSessionMigration(mg)
} }

@ -138,7 +138,7 @@ define([
controllerAs: 'ctrl', controllerAs: 'ctrl',
resolve: loadAppsBundle, resolve: loadAppsBundle,
}) })
.when('/apps/edit/:type', { .when('/apps/edit/:appId', {
templateUrl: 'app/features/apps/partials/edit.html', templateUrl: 'app/features/apps/partials/edit.html',
controller: 'AppEditCtrl', controller: 'AppEditCtrl',
controllerAs: 'ctrl', controllerAs: 'ctrl',

@ -1,3 +1,2 @@
import './edit_ctrl'; import './edit_ctrl';
import './list_ctrl'; import './list_ctrl';
import './app_srv';

@ -15,9 +15,6 @@ export class AppSrv {
} }
get(type) { get(type) {
if (this.apps[type]) {
return this.$q.when(this.apps[type]);
}
return this.getAll().then(() => { return this.getAll().then(() => {
return this.apps[type]; return this.apps[type];
}); });
@ -38,7 +35,7 @@ export class AppSrv {
update(app) { update(app) {
return this.backendSrv.post('api/org/apps', app).then(resp => { return this.backendSrv.post('api/org/apps', app).then(resp => {
this.apps[app.type] = app;
}); });
} }
} }

@ -8,20 +8,36 @@ export class AppEditCtrl {
appModel: any; appModel: any;
/** @ngInject */ /** @ngInject */
constructor(private appSrv: any, private $routeParams: any) {} constructor(private backendSrv: any, private $routeParams: any) {}
init() { init() {
this.appModel = {}; this.appModel = {};
this.appSrv.get(this.$routeParams.type).then(result => { this.backendSrv.get(`/api/org/apps/${this.$routeParams.appId}/settings`).then(result => {
this.appModel = _.clone(result); this.appModel = result;
}); });
} }
update() { update(options) {
this.appSrv.update(this.appModel).then(function() { var updateCmd = _.extend({
window.location.href = config.appSubUrl + "org/apps"; appId: this.appModel.appId,
orgId: this.appModel.orgId,
enabled: this.appModel.enabled,
pinned: this.appModel.pinned,
jsonData: this.appModel.jsonData,
}, options);
this.backendSrv.post(`/api/org/apps/${this.$routeParams.appId}/settings`, updateCmd).then(function() {
window.location.href = window.location.href;
}); });
} }
toggleEnabled() {
this.update({enabled: this.appModel.enabled});
}
togglePinned() {
this.update({pinned: this.appModel.pinned});
}
} }
angular.module('grafana.controllers').controller('AppEditCtrl', AppEditCtrl); angular.module('grafana.controllers').controller('AppEditCtrl', AppEditCtrl);

@ -7,11 +7,11 @@ export class AppListCtrl {
apps: any[]; apps: any[];
/** @ngInject */ /** @ngInject */
constructor(private appSrv: any) {} constructor(private backendSrv: any) {}
init() { init() {
this.appSrv.getAll().then(result => { this.backendSrv.get('api/org/apps').then(apps => {
this.apps = result; this.apps = apps;
}); });
} }
} }

@ -1,7 +1,7 @@
<topnav title="Apps" icon="fa fa-fw fa-cubes" subnav="true"> <topnav title="Apps" icon="fa fa-fw fa-cubes" subnav="true">
<ul class="nav"> <ul class="nav">
<li ><a href="org/apps">Overview</a></li> <li ><a href="apps">Overview</a></li>
<li class="active" ><a href="org/apps/edit/{{ctrl.current.type}}">Edit</a></li> <li class="active" ><a href="apps/edit/{{ctrl.current.type}}">Edit</a></li>
</ul> </ul>
</topnav> </topnav>
@ -25,10 +25,12 @@
<em> <em>
{{ctrl.appModel.info.description}} {{ctrl.appModel.info.description}}
</em> </em>
<br><br>
<div class="form-inline"> <div class="form-inline">
<editor-checkbox text="Enabled" model="ctrl.appModel.enabled" change="enabledChanged()"></editor-checkbox> <editor-checkbox text="Enabled" model="ctrl.appModel.enabled" change="ctrl.toggleEnabled()"></editor-checkbox>
<editor-checkbox text="Pinned" model="ctrl.appModel.pinned" change="enabledChanged()"></editor-checkbox> &nbsp; &nbsp; &nbsp;
<editor-checkbox text="Pinned" model="ctrl.appModel.pinned" change="ctrl.togglePinned()"></editor-checkbox>
</div> </div>
<app-config-loader></app-config-loader> <app-config-loader></app-config-loader>

@ -15,10 +15,13 @@
<ul class="filter-list"> <ul class="filter-list">
<li ng-repeat="app in ctrl.apps"> <li ng-repeat="app in ctrl.apps">
<ul class="filter-list-card"> <ul class="filter-list-card">
<li class="filter-list-card-image">
<img src="{{app.info.logos.small}}">
</li>
<li> <li>
<div class="filter-list-card-controls"> <div class="filter-list-card-controls">
<div class="filter-list-card-config"> <div class="filter-list-card-config">
<a href="apps/edit/{{app.type}}"> <a href="apps/edit/{{app.appId}}">
<i class="fa fa-cog"></i> <i class="fa fa-cog"></i>
</a> </a>
</div> </div>

@ -52,6 +52,12 @@
font-weight: normal; font-weight: normal;
} }
.filter-list-card-image {
width: 50px;
padding: 5px 50px 5px 5px;
}
.filter-list-card-status { .filter-list-card-status {
color: #777; color: #777;
font-size: 12px; font-size: 12px;

@ -33,6 +33,9 @@ module.exports = function(config, grunt) {
grunt.config(option, result); grunt.config(option, result);
grunt.task.run('typescript:build'); grunt.task.run('typescript:build');
grunt.task.run('tslint'); grunt.task.run('tslint');
// copy ts file also used by source maps
newPath = filepath.replace(/^public/, 'public_gen');
grunt.file.copy(filepath, newPath);
} }
}); });

Loading…
Cancel
Save