diff --git a/api/apps.go b/api/apps.go index d6c29932..344f9073 100644 --- a/api/apps.go +++ b/api/apps.go @@ -129,6 +129,8 @@ func deleteApp(w http.ResponseWriter, r *http.Request) { return } + delete(util.Config.Apps, appID) + w.WriteHeader(http.StatusNoContent) } diff --git a/api/router.go b/api/router.go index d9a1921f..fd4bd7ea 100644 --- a/api/router.go +++ b/api/router.go @@ -131,7 +131,7 @@ func Route() *mux.Router { appsAPI := adminAPI.PathPrefix("/apps").Subrouter() appsAPI.Use(appMiddleware) appsAPI.Path("/{app_id}").HandlerFunc(getApp).Methods("GET", "HEAD") - appsAPI.Path("/{app_id}").HandlerFunc(setApp).Methods("PUT") + appsAPI.Path("/{app_id}").HandlerFunc(setApp).Methods("PUT", "POST") appsAPI.Path("/{app_id}/active").HandlerFunc(setAppActive).Methods("POST") appsAPI.Path("/{app_id}").HandlerFunc(deleteApp).Methods("DELETE") diff --git a/db/Option.go b/db/Option.go index 5758e6b5..dabd0c25 100644 --- a/db/Option.go +++ b/db/Option.go @@ -11,7 +11,7 @@ type Option struct { } func ValidateOptionKey(key string) error { - m, err := regexp.Match(`^(?:\w.)+$`, []byte(key)) + m, err := regexp.Match(`^[\w.]+$`, []byte(key)) if err != nil { return err } diff --git a/db/bolt/option.go b/db/bolt/option.go index 16093aa6..86ff6c27 100644 --- a/db/bolt/option.go +++ b/db/bolt/option.go @@ -81,5 +81,19 @@ func (d *BoltDb) DeleteOptions(filter string) (err error) { return } + var options []db.Option + + err = d.getObjects(0, db.OptionProps, db.RetrieveQueryParams{}, func(i interface{}) bool { + opt := i.(db.Option) + return opt.Key == filter || strings.HasPrefix(opt.Key, filter+".") + }, &options) + + for _, opt := range options { + err = d.DeleteOption(opt.Key) + if err != nil { + return + } + } + return } diff --git a/util/config.go b/util/config.go index efd0bd69..c4191121 100644 --- a/util/config.go +++ b/util/config.go @@ -398,6 +398,18 @@ func CastValueToKind(value interface{}, kind reflect.Kind) (res interface{}, ok res = value switch kind { + case reflect.Slice: + if reflect.ValueOf(value).Kind() == reflect.String { + var arr []string + err := json.Unmarshal([]byte(value.(string)), &arr) + if err != nil { + panic(err) + } + res = arr + ok = true + } + case reflect.String: + ok = true case reflect.Int: if reflect.ValueOf(value).Kind() != reflect.Int { res = castStringToInt(fmt.Sprintf("%v", reflect.ValueOf(value))) @@ -418,6 +430,7 @@ func CastValueToKind(value interface{}, kind reflect.Kind) (res interface{}, ok res = mapValue ok = true } + default: } return diff --git a/web/src/components/AppForm.vue b/web/src/components/AppForm.vue index 25e35c6a..813047a2 100644 --- a/web/src/components/AppForm.vue +++ b/web/src/components/AppForm.vue @@ -48,31 +48,37 @@ import ItemFormBase from '@/components/ItemFormBase'; export default { mixins: [ItemFormBase], - watch: { - itemId(val) { - this.id = val; - }, - }, - - created() { - this.id = this.itemId; - }, - computed: { isNew() { - return false; + return this.itemId === ''; }, }, data() { return { - id: '', + id: null, }; }, + watch: { + itemId() { + this.id = this.itemId; + }, + }, + methods: { + beforeLoadData() { + if (!this.isNew) { + this.id = this.itemId; + } + }, + + afterReset() { + this.id = null; + }, + getItemsUrl() { - return '/api/apps'; + return `/api/apps/${this.id}`; }, getSingleItemUrl() { diff --git a/web/src/components/ItemFormBase.js b/web/src/components/ItemFormBase.js index 8fd74c08..115b90ad 100644 --- a/web/src/components/ItemFormBase.js +++ b/web/src/components/ItemFormBase.js @@ -69,6 +69,7 @@ export default { if (this.$refs.form) { this.$refs.form.resetValidation(); } + await this.afterReset(); await this.loadData(); }, @@ -84,10 +85,18 @@ export default { }, + afterReset() { + + }, + afterSave() { }, + beforeLoadData() { + + }, + afterLoadData() { }, @@ -97,6 +106,8 @@ export default { }, async loadData() { + await this.beforeLoadData(); + if (this.isNew) { this.item = this.getNewItem(); } else {