Добавление и исправление комментариев, начало добавление валидации, сообщение прокрути viewport на форме

This commit is contained in:
XeRo 2026-01-20 17:40:21 +05:00
parent c7ff7662ba
commit e37cabadcc
14 changed files with 371 additions and 297 deletions

View file

@ -2,10 +2,13 @@ package setup
import (
"bubble/types"
"errors"
"fmt"
"github.com/charmbracelet/bubbles/textinput"
"github.com/expr-lang/expr"
"github.com/sirupsen/logrus"
"io"
"io/fs"
"net/http"
"os"
"os/exec"
@ -18,8 +21,7 @@ import (
// userRE - с начала строки, делит все по знаку двоеточия, берется первые 3 группы, пример user_name:x:1000:
var userRE = regexp.MustCompile(`^([^:]+):[^:]*:([0-9]+):`)
// ParamsForCondition — собирает все текущие значения переменных приложения
// для использования в expr-условиях (condition)
// ParamsForCondition получение словаря переменных с приведением типов для проверки условий
func ParamsForCondition(app *types.PackageApplication) map[string]interface{} {
params := make(map[string]interface{})
@ -77,7 +79,7 @@ func ParamsForCondition(app *types.PackageApplication) map[string]interface{} {
return params
}
// CheckCondition — проверяет условие visibility (condition) для секции или поля
// CheckCondition проверяет равно ли переданное условие
func CheckCondition(condition string, app *types.PackageApplication) bool {
if condition == "" {
return true
@ -99,7 +101,7 @@ func CheckCondition(condition string, app *types.PackageApplication) bool {
return boolResult
}
// ParamsForCompute — аналогично, но только по переменным (как в твоём старом коде)
// ParamsForCompute получение словаря переменных без приведения типов, для вычисления
func ParamsForCompute(app *types.PackageApplication) map[string]interface{} {
params := make(map[string]interface{})
@ -129,7 +131,7 @@ func ParamsForCompute(app *types.PackageApplication) map[string]interface{} {
return params
}
// ComputeValue — вычисляет значение для compute-поля
// ComputeValue вычисляет значение для поля compute.
func ComputeValue(computeExpr string, app *types.PackageApplication) (interface{}, error) {
if computeExpr == "" {
return nil, nil
@ -172,6 +174,44 @@ func Recompute(app *types.PackageApplication) {
}
}
// ValidateField создает функцию типа textinput.ValidateFunc для проверки значения полей
func ValidateField(fieldName, variableName string, validations []types.FieldValidate, app *types.PackageApplication) textinput.ValidateFunc {
if len(validations) == 0 {
return nil
}
return func(text string) error {
env := ParamsForCompute(app)
env[variableName] = text //todo text это строка, если использовать функцию типа textinput.ValidateFunc, то словим ошибку типов
options := append([]expr.Option{
expr.Env(env),
expr.AllowUndefinedVariables(),
}, DefineExprCustomFunctions()...)
for _, validate := range validations {
program, err := expr.Compile(validate.Rule, options...)
prefix := fmt.Sprintf("Валидация поля %s,", fieldName)
if err != nil {
msg := fmt.Errorf("ошибка компиляции правила: %s, err: %v", validate.Rule, err)
logrus.Errorf("%s %v", prefix, msg)
return msg
}
result, err := expr.Run(program, env)
if err != nil {
msg := fmt.Errorf("ошибка выполнения правила: %s, err: %v", validate.Rule, err)
logrus.Errorf("%s %v", prefix, msg)
return msg
}
if boolValue, ok := result.(bool); ok && !boolValue {
return fmt.Errorf("%s", validate.Message)
} else if !ok {
msg := fmt.Errorf("возвращаемое значение правила: %s не булево", validate.Rule)
logrus.Errorf("%s %v", prefix, msg)
return msg
}
}
return nil
}
}
// DefineExprCustomFunctions возвращает собственные функции expr
func DefineExprCustomFunctions() []expr.Option {
return []expr.Option{
@ -270,8 +310,17 @@ func DefineExprCustomFunctions() []expr.Option {
return false, nil
}
path := fmt.Sprintf("%v", args[0])
_, err := os.Stat(path)
return err == nil, nil
fileInfo, err := os.Stat(path)
if err == nil && !fileInfo.IsDir() {
return true, nil
} else if err == nil && fileInfo.IsDir() {
return false, fmt.Errorf("file is dir")
}
if errors.Is(err, fs.ErrNotExist) {
return false, fmt.Errorf("no such directory or file")
} else {
return false, err
}
}, new(func(string) bool),
),
//проверяет наличие директории в системе
@ -282,13 +331,16 @@ func DefineExprCustomFunctions() []expr.Option {
}
path := fmt.Sprintf("%v", args[0])
fileInfo, err := os.Stat(path)
if err != nil {
return nil, err
}
if fileInfo.IsDir() {
if err == nil && fileInfo.IsDir() {
return true, nil
} else if err == nil && !fileInfo.IsDir() {
return false, fmt.Errorf("file is not a dir")
}
if errors.Is(err, fs.ErrNotExist) {
return false, fmt.Errorf("no such directory or file")
} else {
return false, err
}
return false, nil
}, new(func(string) bool),
),
//проверяет доступность порта