Merge pull request #164 from trheyi/main

[add] app & login widget
This commit is contained in:
Max 2022-09-21 00:21:38 +08:00 committed by GitHub
commit 5eca33d32a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 764 additions and 1 deletions

View file

@ -38,6 +38,8 @@ env:
MONGO_TEST_USER: "root"
MONGO_TEST_PASS: "123456"
DEMO_APP: ${{ github.WORKSPACE }}/../app
jobs:
UnitTest:
runs-on: ubuntu-latest
@ -130,12 +132,19 @@ jobs:
ref: 5e91d3d9dcabd2986f901b6b31590e49fc3c4dd8
path: v8go
- name: Checkout Demo App
uses: actions/checkout@v2
with:
repository: yaoapp/demo-app
path: app
- name: Move Kun, Xun, Gou, V8Go
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
ls -l .
ls -l ../
@ -218,6 +227,12 @@ jobs:
run: |
make test
- name: Run widgets test
env:
YAO_ROOT: ${{ env.DEMO_APP }}
run: |
make test-widgets
- name: Codecov Report
uses: codecov/codecov-action@v2
with:

View file

@ -42,6 +42,8 @@ env:
MONGO_TEST_USER: "root"
MONGO_TEST_PASS: "123456"
DEMO_APP: ${{ github.WORKSPACE }}/../app
jobs:
unit-test:
runs-on: ubuntu-latest
@ -87,12 +89,19 @@ jobs:
ref: 5e91d3d9dcabd2986f901b6b31590e49fc3c4dd8
path: v8go
- name: Checkout Demo App
uses: actions/checkout@v2
with:
repository: yaoapp/demo-app
path: app
- name: Move Kun, Xun, Gou, V8Go
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
ls -l .
ls -l ../
@ -173,6 +182,12 @@ jobs:
run: |
make test
- name: Run widgets test
env:
YAO_ROOT: ${{ env.DEMO_APP }}
run: |
make test-widgets
- name: Codecov Report
uses: codecov/codecov-action@v2
with:

View file

@ -8,9 +8,11 @@ VERSION := $(shell grep 'const VERSION =' share/const.go |awk '{print $$4}' |sed
COMMIT := $(shell git log | head -n 1 | awk '{print substr($$2, 0, 12)}')
# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TESTFOLDER := $(shell $(GO) list ./... | grep -vE 'examples|tests*|config')
TESTFOLDER := $(shell $(GO) list ./... | grep -vE 'examples|tests*|config|widgets')
TESTTAGS ?= ""
TESTWIDGETS := $(shell $(GO) list ./widgets/...)
# Unit Test
.PHONY: test
test:
@ -37,6 +39,32 @@ test:
fi; \
done
# Unit Test
.PHONY: test-widgets
test-widgets:
echo "mode: count" > coverage.out
for d in $(TESTWIDGETS); do \
$(GO) test -tags $(TESTTAGS) -v -covermode=count -coverprofile=profile.out -coverpkg=$$(echo $$d | sed "s/\/test$$//g") $$d > tmp.out; \
cat tmp.out; \
if grep -q "^--- FAIL" tmp.out; then \
rm tmp.out; \
exit 1; \
elif grep -q "build failed" tmp.out; then \
rm tmp.out; \
exit 1; \
elif grep -q "setup failed" tmp.out; then \
rm tmp.out; \
exit 1; \
elif grep -q "runtime error" tmp.out; then \
rm tmp.out; \
exit 1; \
fi; \
if [ -f profile.out ]; then \
cat profile.out | grep -v "mode:" >> coverage.out; \
rm profile.out; \
fi; \
done
.PHONY: fmt
fmt:
$(GOFMT) -w $(GOFILES)

View file

@ -15,6 +15,7 @@ func init() {
lang.RegisterWidget("kanban", "page")
lang.RegisterWidget("screen", "page")
lang.RegisterWidget("pages", "page")
lang.RegisterWidget("logins", "login")
}
// Load language packs
@ -25,6 +26,8 @@ func Load(cfg config.Config) error {
return err
}
// Set default
lang.Pick("default").AsDefault()
name := os.Getenv("YAO_LANG")
if name != "" {
if _, has := lang.Dicts[name]; !has {

View file

@ -30,6 +30,11 @@ func Walk(root string, typeName string, cb func(root, filename string)) error {
return err
}
// ID parse unique name root: "/tests/apis" file: "/tests/apis/foo/bar.http.json"
func ID(root string, file string) string {
return SpecName(root, file)
}
// SpecName 解析名称 root: "/tests/apis" file: "/tests/apis/foo/bar.http.json"
func SpecName(root string, file string) string {
filename := strings.TrimPrefix(file, root+"/") // "foo/bar.http.json"

193
widgets/app/app.go Normal file
View file

@ -0,0 +1,193 @@
package app
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/lang"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/widgets/login"
)
//
// API:
// GET /api/__yao/app/setting -> Default process: yao.app.Xgen
// GET /api/__yao/app/menu -> Default process: yao.app.Menu
//
// Process:
// yao.app.Setting Return the App DSL
// yao.app.Xgen Return the Xgen setting ( merge app & login )
// yao.app.Menu Return the menu list
//
// Setting the application setting
var Setting *DSL
// Load the app DSL
func Load(cfg config.Config) error {
file := filepath.Join(cfg.Root, "app.json")
file, err := filepath.Abs(file)
if err != nil {
return err
}
data, err := ioutil.ReadFile(file)
if err != nil {
return err
}
dsl := &DSL{}
err = jsoniter.Unmarshal(data, dsl)
if err != nil {
return nil
}
// Apply a language pack
if lang.Default != nil {
lang.Default.Apply(dsl)
}
Setting = dsl
return nil
}
// exportAPI export login api
func exportAPI() error {
if Setting == nil {
return fmt.Errorf("the app does not init")
}
http := gou.HTTP{
Name: "Widget App API",
Description: "Widget App API",
Version: share.VERSION,
Guard: "bearer-jwt",
Group: "__yao/app",
Paths: []gou.Path{},
}
process := "yao.app.Xgen"
if Setting.Optional.Setting != "" {
process = Setting.Optional.Setting
}
path := gou.Path{
Label: "App Setting",
Description: "App Setting",
Guard: "-",
Path: "/setting",
Method: "GET",
Process: process,
In: []string{},
Out: gou.Out{Status: 200, Type: "application/json"},
}
http.Paths = append(http.Paths, path)
process = "yao.app.Menu"
args := []string{}
if Setting.Menu.Process != "" {
process = Setting.Menu.Process
args = Setting.Menu.Args
}
path = gou.Path{
Label: "App Menu",
Description: "App Menu",
Path: "/menu",
Method: "GET",
Process: process,
In: args,
Out: gou.Out{Status: 200, Type: "application/json"},
}
http.Paths = append(http.Paths, path)
// api source
source, err := jsoniter.Marshal(http)
if err != nil {
return err
}
// load apis
_, err = gou.LoadAPIReturn(string(source), "widgets.app")
return err
}
// Export export login api
func Export() error {
exportProcess()
return exportAPI()
}
func exportProcess() {
gou.RegisterProcessHandler("yao.app.setting", processSetting)
gou.RegisterProcessHandler("yao.app.xgen", processXgen)
gou.AliasProcess("flows.xiang.menu", "yao.app.menu")
}
func processSetting(process *gou.Process) interface{} {
if Setting == nil {
exception.New("the app does not init", 500).Throw()
return nil
}
return *Setting
}
func processXgen(process *gou.Process) interface{} {
if Setting == nil {
exception.New("the app does not init", 500).Throw()
}
mode := os.Getenv("YAO_ENV")
if mode == "" {
mode = "production"
}
xgenLogin := map[string]map[string]interface{}{
"entry": {"admin": "/x/Welcome"},
}
if admin, has := login.Logins["admin"]; has {
xgenLogin["entry"]["admin"] = admin.Layout.Entry
xgenLogin["admin"] = map[string]interface{}{
"captcha": "/api/__yao/login/admin/captcha",
"login": "/api/__yao/login/admin",
}
}
if user, has := login.Logins["user"]; has {
xgenLogin["entry"]["user"] = user.Layout.Entry
xgenLogin["user"] = map[string]interface{}{
"captcha": "/api/__yao/login/user/captcha",
"login": "/api/__yao/login/user",
}
}
xgenSetting := map[string]interface{}{
"name": Setting.Name,
"description": Setting.Description,
"mode": mode,
"apiPrefix": "__yao",
"token": "localStorage",
"optional": Setting.Optional,
"login": xgenLogin,
}
return xgenSetting
}
// Lang for applying a language pack
func (dsl *DSL) Lang(trans func(widget string, inst string, value *string) bool) {
widget := "app"
trans(widget, "app", &dsl.Name)
trans(widget, "app", &dsl.Short)
trans(widget, "app", &dsl.Description)
}

161
widgets/app/app_test.go Normal file
View file

@ -0,0 +1,161 @@
package app
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/lang"
"github.com/yaoapp/yao/widgets/login"
)
func TestLoad(t *testing.T) {
lang.Load(config.Conf)
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Demo Application", Setting.Name)
assert.Equal(t, "Demo", Setting.Short)
assert.Equal(t, "Another yao application", Setting.Description)
assert.Equal(t, []string{"demo"}, Setting.Menu.Args)
assert.Equal(t, "flows.app.menu", Setting.Menu.Process)
assert.Equal(t, true, Setting.Optional.HideNotification)
assert.Equal(t, false, Setting.Optional.HideSetting)
}
func TestLoadHK(t *testing.T) {
os.Setenv("YAO_LANG", "zh-hk")
lang.Load(config.Conf)
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "示例應用", Setting.Name)
assert.Equal(t, "演示", Setting.Short)
assert.Equal(t, "又一個YAO應用", Setting.Description)
assert.Equal(t, []string{"demo"}, Setting.Menu.Args)
assert.Equal(t, "flows.app.menu", Setting.Menu.Process)
assert.Equal(t, true, Setting.Optional.HideNotification)
assert.Equal(t, false, Setting.Optional.HideSetting)
}
func TestLoadCN(t *testing.T) {
os.Setenv("YAO_LANG", "zh-cn")
lang.Load(config.Conf)
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "示例应用", Setting.Name)
assert.Equal(t, "演示", Setting.Short)
assert.Equal(t, "又一个 YAO 应用", Setting.Description)
assert.Equal(t, []string{"demo"}, Setting.Menu.Args)
assert.Equal(t, "flows.app.menu", Setting.Menu.Process)
assert.Equal(t, true, Setting.Optional.HideNotification)
assert.Equal(t, false, Setting.Optional.HideSetting)
}
func TestExport(t *testing.T) {
err := login.Load(config.Conf)
if err != nil {
t.Fatal(err)
}
err = Load(config.Conf)
if err != nil {
t.Fatal(err)
}
err = Export()
if err != nil {
t.Fatal(err)
}
api, has := gou.APIs["widgets.app"]
assert.True(t, has)
assert.Equal(t, 2, len(api.HTTP.Paths))
_, has = gou.ThirdHandlers["yao.app.setting"]
assert.True(t, has)
_, has = gou.ThirdHandlers["yao.app.xgen"]
assert.True(t, has)
_, has = gou.ThirdHandlers["yao.app.menu"]
assert.True(t, has)
}
func TestProcessSetting(t *testing.T) {
loadApp(t)
res, err := gou.NewProcess("yao.app.Setting").Exec()
if err != nil {
t.Fatal(err)
}
setting, ok := res.(DSL)
assert.True(t, ok)
assert.Equal(t, "Demo Application", setting.Name)
assert.Equal(t, "Demo", setting.Short)
assert.Equal(t, "Another yao application", setting.Description)
assert.Equal(t, []string{"demo"}, setting.Menu.Args)
assert.Equal(t, "flows.app.menu", setting.Menu.Process)
assert.Equal(t, true, setting.Optional.HideNotification)
assert.Equal(t, false, setting.Optional.HideSetting)
}
func TestProcessXgen(t *testing.T) {
loadApp(t)
res, err := gou.NewProcess("yao.app.Xgen").Exec()
if err != nil {
t.Fatal(err)
}
xgen := any.Of(res).MapStr().Dot()
assert.Equal(t, "__yao", xgen.Get("apiPrefix"))
assert.Equal(t, "Another yao application", xgen.Get("description"))
assert.Equal(t, "/api/__yao/login/admin/captcha", xgen.Get("login.admin.captcha"))
assert.Equal(t, "/api/__yao/login/admin", xgen.Get("login.admin.login"))
assert.Equal(t, "/x/Table/pet", xgen.Get("login.entry.admin"))
assert.Equal(t, "/x/Table/dash", xgen.Get("login.entry.user"))
assert.Equal(t, "/api/__yao/login/user/captcha", xgen.Get("login.user.captcha"))
assert.Equal(t, "/api/__yao/login/user", xgen.Get("login.user.login"))
assert.Equal(t, os.Getenv("YAO_ENV"), xgen.Get("mode"))
assert.Equal(t, "Demo Application", xgen.Get("name"))
assert.Equal(t, true, xgen.Get("optional.hideNotification"))
assert.Equal(t, "localStorage", xgen.Get("token"))
}
func loadApp(t *testing.T) {
os.Setenv("YAO_LANG", "")
lang.Load(config.Conf)
err := login.Load(config.Conf)
if err != nil {
t.Fatal(err)
}
err = Load(config.Conf)
if err != nil {
t.Fatal(err)
}
err = Export()
if err != nil {
t.Fatal(err)
}
}

25
widgets/app/types.go Normal file
View file

@ -0,0 +1,25 @@
package app
// DSL the app DSL
type DSL struct {
Name string `json:"name,omitempty"`
Short string `json:"short,omitempty"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
Theme string `json:"theme,omitempty"`
Menu MenuDSL `json:"menu,omitempty"`
Optional OptionalDSL `json:"optional,omitempty"`
}
// MenuDSL the menu DSL
type MenuDSL struct {
Process string `json:"process,omitempty"`
Args []string `json:"args,omitempty"`
}
// OptionalDSL the Optional DSL
type OptionalDSL struct {
HideNotification bool `json:"hideNotification,omitempty"`
HideSetting bool `json:"hideSetting,omitempty"`
Setting string `json:"setting,omitempty"` // custom setting process
}

133
widgets/login/login.go Normal file
View file

@ -0,0 +1,133 @@
package login
import (
"fmt"
"path/filepath"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/lang"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/share"
)
//
// API:
// GET /api/__yao/login/:id/captcha -> Default process: yao.utils.Captcha :query
// POST /api/__yao/login/:id -> Default process: yao.user.Login :payload
//
// Logins the loaded login widgets
var Logins map[string]*DSL = map[string]*DSL{}
// Load load task
func Load(cfg config.Config) error {
var root = filepath.Join(cfg.Root, "logins")
return LoadFrom(root, "")
}
// LoadFrom load from dir
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return fmt.Errorf("%s does not exists", dir)
}
messages := []string{}
err := share.Walk(dir, ".json", func(root, filename string) {
id := prefix + share.ID(root, filename)
data := share.ReadFile(filename)
dsl := &DSL{ID: id}
err := jsoniter.Unmarshal(data, dsl)
if err != nil {
messages = append(messages, err.Error())
}
// Apply a language pack
if lang.Default != nil {
lang.Default.Apply(dsl)
}
Logins[id] = dsl
})
return err
}
// Export export login api
func Export() error {
return exportAPI()
}
// exportAPI export login api
func exportAPI() error {
http := gou.HTTP{
Name: "Widget Login API",
Description: "Widget Login API",
Version: share.VERSION,
Guard: "bearer-jwt",
Group: "__yao/login",
Paths: []gou.Path{},
}
for _, dsl := range Logins {
// login action
process := "yao.user.Login"
args := []string{":payload"}
if dsl.Action.Process != "" {
process = dsl.Action.Process
args = dsl.Action.Args
}
path := gou.Path{
Label: fmt.Sprintf("%s login", dsl.ID),
Description: fmt.Sprintf("%s login", dsl.ID),
Guard: "-",
Path: fmt.Sprintf("/%s", dsl.ID),
Method: "POST",
Process: process,
In: args,
Out: gou.Out{Status: 200, Type: "application/json"},
}
http.Paths = append(http.Paths, path)
// captcha
process = "yao.utils.Captcha"
args = []string{":query"}
if dsl.Layout.Captcha != "" {
process = dsl.Layout.Captcha
}
path = gou.Path{
Label: fmt.Sprintf("%s captcha", dsl.ID),
Description: fmt.Sprintf("%s captcha", dsl.ID),
Guard: "-",
Path: fmt.Sprintf("/%s/captcha", dsl.ID),
Method: "GET",
Process: process,
In: args,
Out: gou.Out{Status: 200, Type: "application/json"},
}
http.Paths = append(http.Paths, path)
}
// api source
source, err := jsoniter.Marshal(http)
if err != nil {
return err
}
// load apis
_, err = gou.LoadAPIReturn(string(source), "widgets.login")
return err
}
// Lang for applying a language pack
func (dsl *DSL) Lang(trans func(widget string, inst string, value *string) bool) {
widget := "login"
trans(widget, dsl.ID, &dsl.Name)
trans(widget, dsl.ID, &dsl.Layout.Slogan)
trans(widget, dsl.ID, &dsl.Layout.Site)
}

124
widgets/login/login_test.go Normal file
View file

@ -0,0 +1,124 @@
package login
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/lang"
)
func TestLoad(t *testing.T) {
lang.Load(config.Conf)
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 2, len(Logins))
assert.Equal(t, "admin", Logins["admin"].ID)
assert.Equal(t, "Admin Login", Logins["admin"].Name)
assert.Equal(t, "yao.user.login", Logins["admin"].Action.Process)
assert.Equal(t, []string{":payload"}, Logins["admin"].Action.Args)
assert.Equal(t, "yao.utils.Captcha", Logins["admin"].Layout.Captcha)
assert.Equal(t, "/images/admin-cover.png", Logins["admin"].Layout.Cover)
assert.Equal(t, "/x/Table/pet", Logins["admin"].Layout.Entry)
assert.Equal(t, "https://yaoapps.com", Logins["admin"].Layout.Site)
assert.Equal(t, "Make Your Dream With Yao App Engine", Logins["admin"].Layout.Slogan)
assert.Equal(t, "user", Logins["user"].ID)
assert.Equal(t, "User Login", Logins["user"].Name)
assert.Equal(t, "scripts.user.Login", Logins["user"].Action.Process)
assert.Equal(t, []string{":payload"}, Logins["user"].Action.Args)
assert.Equal(t, "yao.utils.Captcha", Logins["user"].Layout.Captcha)
assert.Equal(t, "/images/user-cover.png", Logins["user"].Layout.Cover)
assert.Equal(t, "/x/Table/dash", Logins["user"].Layout.Entry)
assert.Equal(t, "https://yaoapps.com/docs", Logins["user"].Layout.Site)
assert.Equal(t, "Make Your Dream With Yao App Engine", Logins["user"].Layout.Slogan)
}
func TestLoadHK(t *testing.T) {
os.Setenv("YAO_LANG", "zh-hk")
lang.Load(config.Conf)
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 2, len(Logins))
assert.Equal(t, "admin", Logins["admin"].ID)
assert.Equal(t, "管理員登錄", Logins["admin"].Name)
assert.Equal(t, "yao.user.login", Logins["admin"].Action.Process)
assert.Equal(t, []string{":payload"}, Logins["admin"].Action.Args)
assert.Equal(t, "yao.utils.Captcha", Logins["admin"].Layout.Captcha)
assert.Equal(t, "/images/admin-cover.png", Logins["admin"].Layout.Cover)
assert.Equal(t, "/x/Table/pet", Logins["admin"].Layout.Entry)
assert.Equal(t, "https://yaoapps.com", Logins["admin"].Layout.Site)
assert.Equal(t, "夢想讓我們與眾不同", Logins["admin"].Layout.Slogan)
assert.Equal(t, "user", Logins["user"].ID)
assert.Equal(t, "用戶登錄", Logins["user"].Name)
assert.Equal(t, "scripts.user.Login", Logins["user"].Action.Process)
assert.Equal(t, []string{":payload"}, Logins["user"].Action.Args)
assert.Equal(t, "yao.utils.Captcha", Logins["user"].Layout.Captcha)
assert.Equal(t, "/images/user-cover.png", Logins["user"].Layout.Cover)
assert.Equal(t, "/x/Table/dash", Logins["user"].Layout.Entry)
assert.Equal(t, "https://yaoapps.com/docs", Logins["user"].Layout.Site)
assert.Equal(t, "夢想讓我們與眾不同", Logins["user"].Layout.Slogan)
}
func TestLoadCN(t *testing.T) {
os.Setenv("YAO_LANG", "zh-cn")
lang.Load(config.Conf)
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 2, len(Logins))
assert.Equal(t, "admin", Logins["admin"].ID)
assert.Equal(t, "管理员登录", Logins["admin"].Name)
assert.Equal(t, "yao.user.login", Logins["admin"].Action.Process)
assert.Equal(t, []string{":payload"}, Logins["admin"].Action.Args)
assert.Equal(t, "yao.utils.Captcha", Logins["admin"].Layout.Captcha)
assert.Equal(t, "/images/admin-cover.png", Logins["admin"].Layout.Cover)
assert.Equal(t, "/x/Table/pet", Logins["admin"].Layout.Entry)
assert.Equal(t, "https://yaoapps.com", Logins["admin"].Layout.Site)
assert.Equal(t, "梦想让我们与众不同", Logins["admin"].Layout.Slogan)
assert.Equal(t, "user", Logins["user"].ID)
assert.Equal(t, "用户登录", Logins["user"].Name)
assert.Equal(t, "scripts.user.Login", Logins["user"].Action.Process)
assert.Equal(t, []string{":payload"}, Logins["user"].Action.Args)
assert.Equal(t, "yao.utils.Captcha", Logins["user"].Layout.Captcha)
assert.Equal(t, "/images/user-cover.png", Logins["user"].Layout.Cover)
assert.Equal(t, "/x/Table/dash", Logins["user"].Layout.Entry)
assert.Equal(t, "https://yaoapps.com/docs", Logins["user"].Layout.Site)
assert.Equal(t, "梦想让我们与众不同", Logins["user"].Layout.Slogan)
}
func TestExport(t *testing.T) {
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
err = Export()
if err != nil {
t.Fatal(err)
}
api, has := gou.APIs["widgets.login"]
assert.True(t, has)
assert.Equal(t, 4, len(api.HTTP.Paths))
}

24
widgets/login/types.go Normal file
View file

@ -0,0 +1,24 @@
package login
// DSL the app DSL
type DSL struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Action ActionDSL `json:"action,omitempty"`
Layout LayoutDSL `json:"layout,omitempty"`
}
// ActionDSL the login action DSL
type ActionDSL struct {
Process string `json:"process,omitempty"`
Args []string `json:"args,omitempty"`
}
// LayoutDSL the login page layoutDSL
type LayoutDSL struct {
Entry string `json:"entry,omitempty"`
Captcha string `json:"captcha,omitempty"`
Cover string `json:"cover,omitempty"`
Slogan string `json:"slogan,omitempty"`
Site string `json:"site,omitempty"`
}

24
widgets/widgets.go Normal file
View file

@ -0,0 +1,24 @@
package widgets
import (
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/widgets/app"
"github.com/yaoapp/yao/widgets/login"
)
// Load the widgets
func Load(cfg config.Config) error {
err := login.Load(cfg)
if err != nil {
return err
}
// app login
err = app.Load(cfg)
if err != nil {
return err
}
return nil
}

13
widgets/widgets_test.go Normal file
View file

@ -0,0 +1,13 @@
package widgets
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/config"
)
func TestLoad(t *testing.T) {
err := Load(config.Conf)
assert.Nil(t, err)
}