From 4d72952b2c0133889b79f28cf89ce7758ae96e55 Mon Sep 17 00:00:00 2001 From: Fabien Masson Date: Mon, 31 Aug 2026 21:23:35 +0200 Subject: [PATCH] gestion des providers --- backend/cmd/serve.go | 13 +- backend/internal/adapter/database/factory.go | 1 + backend/internal/adapter/database/turso/db.go | 4 + .../migrations/000001_create_tables.down.sql | 1 - .../migrations/000001_create_tables.up.sql | 24 +-- .../database/turso/provider_repository.go | 61 +++++++ .../adapter/database/turso/user_repository.go | 6 +- backend/internal/adapter/llm/llm.go | 76 +++++++++ backend/internal/domain/llm.go | 26 +++ backend/internal/domain/provider.go | 24 +++ backend/internal/domain/select.go | 6 + backend/internal/domain/user.go | 29 ++-- backend/internal/http/handlers/provider.go | 123 ++++++++++++++ backend/internal/http/handlers/user.go | 3 +- backend/internal/http/router.go | 11 +- backend/internal/service/provider/service.go | 76 +++++++++ backend/internal/service/user/service.go | 24 +++ backend/lassistanoque.db-wal | Bin 267832 -> 313152 bytes backend/web/src/lib/api/endpoints/provider.ts | 13 ++ backend/web/src/lib/api/endpoints/user.ts | 4 +- .../web/src/lib/components/FormError.svelte | 2 - backend/web/src/lib/components/Sidebar.svelte | 41 +++-- backend/web/src/lib/state/auth.svelte.ts | 8 +- backend/web/src/lib/state/space.svelte.ts | 6 + backend/web/src/lib/types/api.ts | 50 ++++++ backend/web/src/lib/utilities/validators.ts | 5 + .../(authenticated)/(chat)/+page.svelte | 3 +- .../src/routes/(authenticated)/+layout.svelte | 7 +- .../(authenticated)/profile/+page.svelte | 58 +++---- .../(authenticated)/settings/+page.svelte | 2 +- .../settings/models/+page.svelte | 158 +++++++++++++++++- .../(authenticated)/settings/models/+page.ts | 8 +- .../settings/models/ProviderForm.svelte | 142 ++++++++++++++++ backend/web/src/routes/layout.css | 52 ++++-- .../web/static/assets/fontello/config.json | 12 ++ .../assets/fontello/css/fontello-codes.css | 2 + .../assets/fontello/css/fontello-embedded.css | 14 +- .../fontello/css/fontello-ie7-codes.css | 2 + .../assets/fontello/css/fontello-ie7.css | 2 + .../static/assets/fontello/css/fontello.css | 16 +- backend/web/static/assets/fontello/demo.html | 26 ++- .../static/assets/fontello/font/fontello.eot | Bin 10860 -> 11456 bytes .../static/assets/fontello/font/fontello.svg | 4 + .../static/assets/fontello/font/fontello.ttf | Bin 10692 -> 11288 bytes .../static/assets/fontello/font/fontello.woff | Bin 6668 -> 7024 bytes .../assets/fontello/font/fontello.woff2 | Bin 5592 -> 5952 bytes 46 files changed, 995 insertions(+), 150 deletions(-) create mode 100644 backend/internal/adapter/database/turso/provider_repository.go create mode 100644 backend/internal/adapter/llm/llm.go create mode 100644 backend/internal/domain/llm.go create mode 100644 backend/internal/domain/provider.go create mode 100644 backend/internal/domain/select.go create mode 100644 backend/internal/http/handlers/provider.go create mode 100644 backend/internal/service/provider/service.go create mode 100644 backend/web/src/lib/api/endpoints/provider.ts create mode 100644 backend/web/src/lib/state/space.svelte.ts create mode 100644 backend/web/src/routes/(authenticated)/settings/models/ProviderForm.svelte diff --git a/backend/cmd/serve.go b/backend/cmd/serve.go index 86f2bf4..1629c98 100644 --- a/backend/cmd/serve.go +++ b/backend/cmd/serve.go @@ -8,9 +8,11 @@ import ( "trankilou.fr/lassistanoque/backend/internal/adapter/auth/password" "trankilou.fr/lassistanoque/backend/internal/adapter/database" "trankilou.fr/lassistanoque/backend/internal/adapter/file" + "trankilou.fr/lassistanoque/backend/internal/adapter/llm" "trankilou.fr/lassistanoque/backend/internal/adapter/security" "trankilou.fr/lassistanoque/backend/internal/http" "trankilou.fr/lassistanoque/backend/internal/service/auth" + "trankilou.fr/lassistanoque/backend/internal/service/provider" "trankilou.fr/lassistanoque/backend/internal/service/storage" "trankilou.fr/lassistanoque/backend/internal/service/user" ) @@ -56,6 +58,7 @@ func runServe() { // Adapters tokenManager := security.NewJwtTokenManager(12*time.Hour, 7*24*time.Hour, "lassistanoque") pwdAuth := password.NewPasswordAuthenticator(tokenManager, db.UserRepository()) + llmEngine := llm.NewAnyLLMEngine() // services authService := auth.NewService( @@ -67,13 +70,15 @@ func runServe() { ) userService := user.NewService(db.UserRepository()) storageService := storage.NewService(store) + providerService := provider.NewService(db.ProviderRepository(), db.UserRepository(), llmEngine) // http server router := http.NewRouter(http.Dependencies{ - StorageService: storageService, - AuthService: authService, - UserService: userService, - TokenManager: tokenManager, + StorageService: storageService, + AuthService: authService, + UserService: userService, + TokenManager: tokenManager, + ProviderService: providerService, }) if err := router.Start(); err != nil { diff --git a/backend/internal/adapter/database/factory.go b/backend/internal/adapter/database/factory.go index d3253e7..4a8a48c 100644 --- a/backend/internal/adapter/database/factory.go +++ b/backend/internal/adapter/database/factory.go @@ -12,6 +12,7 @@ type Database interface { SettingsRepository() domain.SettingsRepository UserRepository() domain.UserRepository FileRepository() domain.FileRepository + ProviderRepository() domain.ProviderRepository Migrate() error Close() } diff --git a/backend/internal/adapter/database/turso/db.go b/backend/internal/adapter/database/turso/db.go index 4d6303e..5ed7968 100644 --- a/backend/internal/adapter/database/turso/db.go +++ b/backend/internal/adapter/database/turso/db.go @@ -67,3 +67,7 @@ func (db *TursoDB) SettingsRepository() domain.SettingsRepository { func (db *TursoDB) FileRepository() domain.FileRepository { return NewTursoFileRepository(db.DB) } + +func (db *TursoDB) ProviderRepository() domain.ProviderRepository { + return NewTursoModelRepository(db.DB) +} diff --git a/backend/internal/adapter/database/turso/migrations/000001_create_tables.down.sql b/backend/internal/adapter/database/turso/migrations/000001_create_tables.down.sql index 6c17ca8..b62c63c 100644 --- a/backend/internal/adapter/database/turso/migrations/000001_create_tables.down.sql +++ b/backend/internal/adapter/database/turso/migrations/000001_create_tables.down.sql @@ -11,4 +11,3 @@ drop table tools; drop table tasks; drop table history; drop table files; -drop table share; diff --git a/backend/internal/adapter/database/turso/migrations/000001_create_tables.up.sql b/backend/internal/adapter/database/turso/migrations/000001_create_tables.up.sql index dcf6abb..9671553 100644 --- a/backend/internal/adapter/database/turso/migrations/000001_create_tables.up.sql +++ b/backend/internal/adapter/database/turso/migrations/000001_create_tables.up.sql @@ -1,25 +1,16 @@ create table providers ( id text not null primary key, team_id text not null, + type text not null, name text not null, key text, url text, + models text, _date_created numeric not null default current_timestamp, _date_updated numeric, _version text not null ); -create table models ( - id text not null primary key, - team_id text not null, - provider_id text not null, - name text not null default '', - modelname text not null default '', - configuration text not null default '{}', - _date_created numeric not null default current_timestamp, - _date_updated numeric, - _version text not null -); create table settings ( id text not null primary key, @@ -150,14 +141,3 @@ create table files ( _date_updated numeric , _version text not null ); - -create table share ( - id text not null primary key, - object_id text not null, - object_type text not null, - team_id text not null, - enabled numeric not null default 0, - _date_created numeric not null default current_timestamp, - _date_updated numeric, - _version text not null -); diff --git a/backend/internal/adapter/database/turso/provider_repository.go b/backend/internal/adapter/database/turso/provider_repository.go new file mode 100644 index 0000000..6aea95c --- /dev/null +++ b/backend/internal/adapter/database/turso/provider_repository.go @@ -0,0 +1,61 @@ +package turso + +import ( + "database/sql" + "log" + + "gitea.trankilou.fr/fabien/lasebuche" + "trankilou.fr/lassistanoque/backend/internal/domain" +) + +type TursoModelRepository struct { + db *sql.DB + providerTable lasebuche.Table[domain.Provider] +} + +func NewTursoModelRepository(db *sql.DB) *TursoModelRepository { + dialect := lasebuche.NewSqliteDialect() + providerTable, err := lasebuche.NewTable[domain.Provider](db, dialect, "providers") + if err != nil { + log.Fatalf("error creating lasebuche team table") + } + + return &TursoModelRepository{ + db: db, + providerTable: providerTable, + } +} + +func (r *TursoModelRepository) ListProviders(userID string, teamID string) ([]*domain.Provider, error) { + return r.providerTable.SelectWhere( + "team_id=$1 and team_id in (select team_id from user_teams where user_id=$2)", + teamID, + userID, + ) +} + +func (r *TursoModelRepository) GetProvider(userID string, teamID string, id string) (*domain.Provider, error) { + return r.providerTable.SelectOne( + "id=$1 and team_id=$2 and team_id in (select team_id from user_teams where user_id=$3)", + id, + teamID, + userID, + ) +} + +func (r *TursoModelRepository) CreateProvider(userID string, provider *domain.Provider) (*domain.Provider, error) { + return r.providerTable.Insert(provider) +} + +func (r *TursoModelRepository) UpdateProvider(userID string, provider *domain.Provider) (*domain.Provider, error) { + return r.providerTable.Update(provider) +} + +func (r *TursoModelRepository) DeleteProvider(userID string, teamID string, id string) error { + return r.providerTable.DeleteWhere( + "id=$1 and team_id=$2 and team_id in (select team_id from user_teams where user_id=$3)", + id, + teamID, + userID, + ) +} diff --git a/backend/internal/adapter/database/turso/user_repository.go b/backend/internal/adapter/database/turso/user_repository.go index 94b8a53..4596b57 100644 --- a/backend/internal/adapter/database/turso/user_repository.go +++ b/backend/internal/adapter/database/turso/user_repository.go @@ -73,7 +73,7 @@ func (ur *TursoUserRepository) FindTeam(userid string, teamid string) (*domain.T } func (ur *TursoUserRepository) ListTeams(userid string) ([]*domain.Team, error) { - return ur.TeamTable.SelectWhere("user_id=$1", userid) + return ur.TeamTable.SelectWhere("id in (select team_id from user_teams where user_id=$1)", userid) } func (ur *TursoUserRepository) CreateTeam(userid string, team *domain.Team) (*domain.Team, error) { @@ -123,10 +123,6 @@ func (ur *TursoUserRepository) DeleteUserTeam(userid string, teamid string) erro return ur.UserTeamTable.Delete(teamid) } -func (ur *TursoUserRepository) PopulateUserWithTeams(user *domain.User) (*domain.UserWithTeams, error) { - return nil, nil -} - func (ur *TursoUserRepository) ListUserAddresses(id string) ([]*domain.UserAddress, error) { return ur.AddressTable.SelectWhere("user_id=$1", id) } diff --git a/backend/internal/adapter/llm/llm.go b/backend/internal/adapter/llm/llm.go new file mode 100644 index 0000000..da3ceb1 --- /dev/null +++ b/backend/internal/adapter/llm/llm.go @@ -0,0 +1,76 @@ +package llm + +import ( + "context" + "fmt" + + anyllm "github.com/mozilla-ai/any-llm-go" + "github.com/mozilla-ai/any-llm-go/providers/anthropic" + "github.com/mozilla-ai/any-llm-go/providers/ollama" + "github.com/mozilla-ai/any-llm-go/providers/openai" + "trankilou.fr/lassistanoque/backend/internal/domain" +) + +var providerTypes = []domain.Item{ + {ID: "anthropic", Text: "Anthropic"}, + {ID: "openai", Text: "OpenAI"}, + {ID: "ollama", Text: "Ollama"}, + {ID: "openaicomp", Text: "OpenAI compatible"}, + {ID: "openrouter", Text: "Openrouter"}, +} + +type AnyLLMEngine struct { +} + +func NewAnyLLMEngine() *AnyLLMEngine { + return &AnyLLMEngine{} +} + +func (e *AnyLLMEngine) ListProviderTypes() []domain.Item { + return providerTypes +} + +func providerFactory(provider *domain.Provider) (anyllm.Provider, error) { + switch provider.Type { + case "ollama": + return ollama.New( + anyllm.WithBaseURL(provider.URL), + ) + case "openai": + return openai.New( + anyllm.WithAPIKey(provider.APIKey), + ) + case "openaicomp": + return openai.New( + anyllm.WithBaseURL(provider.URL), + anyllm.WithAPIKey(provider.APIKey), + ) + case "anthropic": + return anthropic.New( + anyllm.WithAPIKey(provider.APIKey), + ) + } + return nil, fmt.Errorf("unknown provider type: %s", provider.Type) +} + +func (e *AnyLLMEngine) ListModelsFromProvider(ctx context.Context, provider *domain.Provider) ([]string, error) { + + models := make([]string, 0) + + prov, err := providerFactory(provider) + if err != nil { + return nil, err + } + if lister, ok := prov.(anyllm.ModelLister); ok { + response, err := lister.ListModels(ctx) + if err != nil { + return nil, err + } + for _, m := range response.Data { + models = append(models, m.ID) + } + } else { + models = append(models, "Default") + } + return models, nil +} diff --git a/backend/internal/domain/llm.go b/backend/internal/domain/llm.go new file mode 100644 index 0000000..8561108 --- /dev/null +++ b/backend/internal/domain/llm.go @@ -0,0 +1,26 @@ +package domain + +import "context" + +type LLMModelDetail struct { + ParentModel string `json:"parent_model"` + Format string `json:"format"` + Family string `json:"family"` + Families []string `json:"families"` + ParameterSize string `json:"parameter_size"` + QuantizationLevel string `json:"quantization_level"` +} + +type LLMModel struct { + Name string `json:"name"` + Model string `json:"model"` + ModifiedAt int64 `json:"modified_at"` + Size int64 `json:"size"` + Digest string `json:"digest"` + Detail *LLMModelDetail `json:"detail"` +} + +type LLMEngine interface { + ListProviderTypes() []Item + ListModelsFromProvider(ctx context.Context, provider *Provider) ([]string, error) +} diff --git a/backend/internal/domain/provider.go b/backend/internal/domain/provider.go new file mode 100644 index 0000000..0b0c2e1 --- /dev/null +++ b/backend/internal/domain/provider.go @@ -0,0 +1,24 @@ +package domain + +import "time" + +type Provider struct { + ID string `db:"id" json:"id"` + TeamID string `db:"team_id" json:"teamId"` + Type string `db:"type" json:"type"` + Name string `db:"name" json:"name"` + APIKey string `db:"key" json:"apiKey"` + URL string `db:"url" json:"baseUrl"` + Models string `db:"models" json:"models"` + DateCreated time.Time `db:"_date_created" json:"_date_created"` + DateUpdated *time.Time `db:"_date_updated" json:"_date_updated"` + VersionId string `db:"_version" json:"_version"` +} + +type ProviderRepository interface { + ListProviders(userID string, teamID string) ([]*Provider, error) + GetProvider(userID string, teamID string, id string) (*Provider, error) + CreateProvider(userID string, provider *Provider) (*Provider, error) + UpdateProvider(userID string, provider *Provider) (*Provider, error) + DeleteProvider(userID string, teamID string, id string) error +} diff --git a/backend/internal/domain/select.go b/backend/internal/domain/select.go new file mode 100644 index 0000000..8d77f39 --- /dev/null +++ b/backend/internal/domain/select.go @@ -0,0 +1,6 @@ +package domain + +type Item struct { + ID string `json:"id"` + Text string `json:"text"` +} diff --git a/backend/internal/domain/user.go b/backend/internal/domain/user.go index 9358d53..2cb7933 100644 --- a/backend/internal/domain/user.go +++ b/backend/internal/domain/user.go @@ -15,27 +15,27 @@ type User struct { Theme string `db:"theme" json:"theme"` Lang string `db:"lang" json:"lang"` Timezone string `db:"timezone" json:"timezone"` - DateCreated time.Time `db:"_date_created" json:"_date_created"` - DateUpdated *time.Time `db:"_date_updated" json:"_date_updated"` + DateCreated time.Time `db:"_date_created" json:"_dateCreated"` + DateUpdated *time.Time `db:"_date_updated" json:"_dateUpdated"` VersionId string `db:"_version" json:"_version"` } type Team struct { ID string `db:"id" json:"id"` Label string `db:"label" json:"label"` - DefaultModelID *string `db:"default_model_id" json:"default_model_id"` - DateCreated time.Time `db:"_date_created" json:"_date_created"` - DateUpdated *time.Time `db:"_date_updated" json:"_date_updated"` + DefaultModelID *string `db:"default_model_id" json:"defaultModelId"` + DateCreated time.Time `db:"_date_created" json:"_dateCreated"` + DateUpdated *time.Time `db:"_date_updated" json:"_dateUpdated"` VersionId string `db:"_version" json:"_version"` } type UserTeam struct { ID string `db:"id" json:"id"` - UserID string `db:"user_id" json:"user_id"` - TeamID string `db:"team_id" json:"team_id"` + UserID string `db:"user_id" json:"userId"` + TeamID string `db:"team_id" json:"teamId"` Administrator bool `db:"administrator" json:"administrator"` - DateCreated time.Time `db:"_date_created" json:"_date_created"` - DateUpdated *time.Time `db:"_date_updated" json:"_date_updated"` + DateCreated time.Time `db:"_date_created" json:"_dateCreated"` + DateUpdated *time.Time `db:"_date_updated" json:"_dateUpdated"` VersionId string `db:"_version" json:"_version"` } @@ -44,8 +44,8 @@ type UserAddress struct { UserID string `db:"user_id" json:"user_id"` Type string `db:"type" json:"type"` Address string `db:"address" json:"address"` - DateCreated time.Time `db:"_date_created" json:"_date_created"` - DateUpdated *time.Time `db:"_date_updated" json:"_date_updated"` + DateCreated time.Time `db:"_date_created" json:"_dateCreated"` + DateUpdated *time.Time `db:"_date_updated" json:"_dateUpdated"` VersionId string `db:"_version" json:"_version"` } @@ -55,8 +55,9 @@ type TeamRelation struct { } type UserWithTeams struct { - User *User `json:"user"` - Teams []*TeamRelation `json:"teams"` + User *User `json:"user"` + UserTeams []*UserTeam `json:"user_teams"` + Teams []*Team `json:"teams"` } func AddressTypes() []string { @@ -88,8 +89,6 @@ type UserRepository interface { UpdateUserTeam(userid string, team *UserTeam) (*UserTeam, error) DeleteUserTeam(userid string, teamid string) error - PopulateUserWithTeams(user *User) (*UserWithTeams, error) - ListUserAddresses(userid string) ([]*UserAddress, error) GetUserAddress(addrID string) (*UserAddress, error) CreateUserAddress(addr *UserAddress) (*UserAddress, error) diff --git a/backend/internal/http/handlers/provider.go b/backend/internal/http/handlers/provider.go new file mode 100644 index 0000000..fadffa0 --- /dev/null +++ b/backend/internal/http/handlers/provider.go @@ -0,0 +1,123 @@ +package handlers + +import ( + "net/http" + + "github.com/labstack/echo/v5" + "trankilou.fr/lassistanoque/backend/internal/domain" + "trankilou.fr/lassistanoque/backend/internal/service/auth" + "trankilou.fr/lassistanoque/backend/internal/service/provider" +) + +func NewModelGroup(prefix string, e *echo.Group, service *provider.Service, middlewares ...echo.MiddlewareFunc) *echo.Group { + modelHandler := &ModelHandler{ + providerService: service, + } + model := e.Group(prefix, middlewares...) + + model.GET("/providerTypes", modelHandler.ListProviderTypes) + model.GET("/:space", modelHandler.ListProviders) + model.POST("/:space/avalable-models", modelHandler.ListAvailableModels) + model.GET("/:space/:provider", modelHandler.GetProvider) + model.PUT("/:space", modelHandler.UpdateProvider) + model.POST("/:space", modelHandler.CreateProvider) + model.DELETE("/:space/:provider", modelHandler.DeleteProvider) + + return model +} + +type ModelHandler struct { + providerService *provider.Service +} + +func (h *ModelHandler) ListProviderTypes(c *echo.Context) error { + return c.JSON(http.StatusOK, h.providerService.ListProviderTypes()) +} + +func (h *ModelHandler) ListProviders(c *echo.Context) error { + userID := c.Get(auth.ContextUserIDKey).(string) + teamID := c.Param("space") + providers, err := h.providerService.ListProviders(userID, teamID) + if err != nil { + c.Logger().Error("error listing providers: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error listing providers") + } + return c.JSON(http.StatusOK, providers) +} + +func (h *ModelHandler) GetProvider(c *echo.Context) error { + userID := c.Get(auth.ContextUserIDKey).(string) + teamID := c.Param("space") + providerID := c.Param("provider") + provider, err := h.providerService.GetProvider(userID, teamID, providerID) + if err != nil { + c.Logger().Error("error getting provider: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error getting provider") + } + return c.JSON(http.StatusOK, provider) +} + +func (h *ModelHandler) CreateProvider(c *echo.Context) error { + userID := c.Get(auth.ContextUserIDKey).(string) + teamID := c.Param("space") + var provider domain.Provider + err := c.Bind(&provider) + if err != nil { + c.Logger().Error("error binding provider: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error binding provider") + } + provider.TeamID = teamID + updprovider, err := h.providerService.CreateProvider(userID, &provider) + if err != nil { + c.Logger().Error("error creating provider: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error creating provider") + } + return c.JSON(http.StatusOK, updprovider) +} + +func (h *ModelHandler) UpdateProvider(c *echo.Context) error { + userID := c.Get(auth.ContextUserIDKey).(string) + teamID := c.Param("space") + var provider domain.Provider + err := c.Bind(&provider) + if err != nil { + c.Logger().Error("error binding provider: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error binding provider") + } + provider.TeamID = teamID + updprovider, err := h.providerService.UpdateProvider(userID, &provider) + if err != nil { + c.Logger().Error("error updating provider: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error creating provider") + } + return c.JSON(http.StatusOK, updprovider) +} + +func (h *ModelHandler) DeleteProvider(c *echo.Context) error { + userID := c.Get(auth.ContextUserIDKey).(string) + teamID := c.Param("space") + providerID := c.Param("provider") + err := h.providerService.DeleteProvider(userID, teamID, providerID) + if err != nil { + c.Logger().Error("error creating provider: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error creating provider") + } + return c.JSON(http.StatusOK, providerID) +} + +func (h *ModelHandler) ListAvailableModels(c *echo.Context) error { + teamID := c.Param("space") + var provider domain.Provider + err := c.Bind(&provider) + if err != nil { + c.Logger().Error("error binding provider: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error binding provider") + } + provider.TeamID = teamID + list, err := h.providerService.ListAvailableModels(c.Request().Context(), &provider) + if err != nil { + c.Logger().Error("error listing models: %s", err) + return echo.NewHTTPError(http.StatusBadRequest, "error creating provider") + } + return c.JSON(http.StatusOK, list) +} diff --git a/backend/internal/http/handlers/user.go b/backend/internal/http/handlers/user.go index d2395d2..585683d 100644 --- a/backend/internal/http/handlers/user.go +++ b/backend/internal/http/handlers/user.go @@ -13,7 +13,6 @@ func NewUserGroup(prefix string, e *echo.Group, service *user.Service, middlewar userHandler := &UserHandler{ userService: service, } - _ = userHandler auth := e.Group(prefix, middlewares...) auth.GET("/me", userHandler.Me) auth.PUT("/:id", userHandler.Update) @@ -30,7 +29,7 @@ type UserHandler struct { func (h UserHandler) Me(c *echo.Context) error { userID := c.Get(auth.ContextUserIDKey).(string) - user, err := h.userService.GetUser(userID) + user, err := h.userService.GetUserWithTeams(userID) if err != nil { return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } diff --git a/backend/internal/http/router.go b/backend/internal/http/router.go index d228e8f..cd9cbe9 100644 --- a/backend/internal/http/router.go +++ b/backend/internal/http/router.go @@ -11,6 +11,7 @@ import ( "trankilou.fr/lassistanoque/backend/internal/config" "trankilou.fr/lassistanoque/backend/internal/http/handlers" "trankilou.fr/lassistanoque/backend/internal/service/auth" + "trankilou.fr/lassistanoque/backend/internal/service/provider" "trankilou.fr/lassistanoque/backend/internal/service/storage" "trankilou.fr/lassistanoque/backend/internal/service/user" ) @@ -32,10 +33,11 @@ type Router struct { } type Dependencies struct { - StorageService *storage.Service - AuthService *auth.Service - UserService *user.Service - TokenManager auth.TokenManager + StorageService *storage.Service + AuthService *auth.Service + UserService *user.Service + ProviderService *provider.Service + TokenManager auth.TokenManager } func NewRouter(deps Dependencies) *Router { @@ -71,6 +73,7 @@ func NewRouter(deps Dependencies) *Router { _ = handlers.NewAuthGroup("/auth", api, deps.AuthService) _ = handlers.NewUserGroup("/user", api, deps.UserService, deps.TokenManager.TokenMiddleware) _ = handlers.NewMiscGroup("/misc", api, deps.TokenManager.TokenMiddleware) + _ = handlers.NewModelGroup("/provider", api, deps.ProviderService, deps.TokenManager.TokenMiddleware) return &Router{ echo: e, diff --git a/backend/internal/service/provider/service.go b/backend/internal/service/provider/service.go new file mode 100644 index 0000000..813dd36 --- /dev/null +++ b/backend/internal/service/provider/service.go @@ -0,0 +1,76 @@ +package provider + +import ( + "context" + "fmt" + + "trankilou.fr/lassistanoque/backend/internal/domain" +) + +type Service struct { + repo domain.ProviderRepository + repoUser domain.UserRepository + llmengine domain.LLMEngine +} + +func NewService( + repo domain.ProviderRepository, + repoUser domain.UserRepository, + llmengine domain.LLMEngine, +) *Service { + return &Service{ + repo, + repoUser, + llmengine, + } +} + +func (s *Service) ListProviderTypes() []domain.Item { + return s.llmengine.ListProviderTypes() +} + +func (s *Service) ListProviders(userID string, teamID string) ([]*domain.Provider, error) { + return s.repo.ListProviders(userID, teamID) +} + +func (s *Service) GetProvider(userID string, teamID string, id string) (*domain.Provider, error) { + return s.repo.GetProvider(userID, teamID, id) +} + +func (s *Service) CreateProvider(userID string, provider *domain.Provider) (*domain.Provider, error) { + + if _, err := s.repoUser.FindUserTeam(userID, provider.TeamID); err != nil { + return nil, fmt.Errorf("error finding user in team: %s", err) + } + + return s.repo.CreateProvider(userID, provider) +} + +func (s *Service) UpdateProvider(userID string, provider *domain.Provider) (*domain.Provider, error) { + if _, err := s.repoUser.FindUserTeam(userID, provider.TeamID); err != nil { + return nil, fmt.Errorf("error finding user in team: %s", err) + } + + if _, err := s.repo.GetProvider(userID, provider.TeamID, provider.ID); err != nil { + return nil, fmt.Errorf("error finding provider: %s", err) + } + + return s.repo.UpdateProvider(userID, provider) +} + +func (s *Service) DeleteProvider(userID string, teamID string, id string) error { + if _, err := s.repoUser.FindUserTeam(userID, teamID); err != nil { + return fmt.Errorf("error finding user in team: %s", err) + } + + if _, err := s.repo.GetProvider(userID, teamID, id); err != nil { + return fmt.Errorf("error finding provider: %s", err) + } + + return s.repo.DeleteProvider(userID, teamID, id) + +} + +func (s *Service) ListAvailableModels(ctx context.Context, provider *domain.Provider) ([]string, error) { + return s.llmengine.ListModelsFromProvider(ctx, provider) +} diff --git a/backend/internal/service/user/service.go b/backend/internal/service/user/service.go index 29f27cb..67cfb5c 100644 --- a/backend/internal/service/user/service.go +++ b/backend/internal/service/user/service.go @@ -27,6 +27,30 @@ func (s *Service) GetUser(id string) (*domain.User, error) { return user, nil } +func (s *Service) GetUserWithTeams(id string) (*domain.UserWithTeams, error) { + u, err := s.GetUser(id) + if err != nil { + return nil, err + } + + teams, err := s.repo.ListTeams(u.ID) + if err != nil { + return nil, err + } + + userTeams, err := s.repo.ListUserTeams(u.ID) + if err != nil { + return nil, err + } + + ut := &domain.UserWithTeams{ + User: u, + UserTeams: userTeams, + Teams: teams, + } + return ut, nil +} + func (s *Service) UpdateUser(updUser *domain.User, fromAdmin bool) (*domain.User, error) { user, err := s.repo.FindUser(updUser.ID) if err != nil { diff --git a/backend/lassistanoque.db-wal b/backend/lassistanoque.db-wal index 5ecb3790474dc011d6cc45b24d2038031519856b..a8b7f8821d9aa7553b2032d58a7048c21a92c2f0 100644 GIT binary patch literal 313152 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 delta 5114 zcmeHKdr(tX8qc|bgjXIQAw*sgYXK#2Z=N@(tpNdn@C@&2F_44=L*9T;trFiPE*8c3Q2Ey*CN;#>JWbv9r6*Y-a8` z%y-W3JLmhI@5P~wGX{3CQP~=rlOnhnOQEnS#BXF!EO_4Jrb2NCCl0(7bPg8*vYa<= zx=%}%rtCpO*zC#8T4j{!)(Ry+_X{Ni72xKA&4QB=xL?L)ej% z8sMAnR9|+LG&8V0D(D_7feNUhq4>E};+x#GWxuZe)dg1=p50|6g{*FIrn%5^rVmYG zBokNl|JbfO%kxt%MZ6xdJe(i)P3WOeH+_h{m2RRfqw#|m1#^OE)M02HR1G+k8!k1w z%=JrklKc1r5FQund@hF0<#Ivq3l4RoQR^_9jdt(A_0%<`f?y7fo0H%Ix>(mcny8={ zXMVK1_z{Q)9M7<39so03546IdXlF#!=Hn0_%-H-7=xY$^QZ%Q=MRhM@dsX-Fe5$qT zR=a~3BHalPbR?KX0Ay6^v?I*z--Vo5nq@G zGRA`7kSWt-tx-Xt&V_VWacevX@wBw^0c{?Q#(kbg=vvrn)@Y6P2E;ehovL6um&XII z0Iyb`)Hl*{DsmN-x%^5+wlbIRmAS^%D9vIsw;MFBaXrVi$QV(HKOhTlrPd&1_^5iuiA|`^2c;w1yt*SYA zkKy^%1pUVtS+6%Fpe46M{D&~fkS%?Gyr3y4xQU&L1fd#4W&MLxnwS$kb*y&sFg6=Vea;{!>3hs`V>BASdS zt>3=pcLT0rY`Kk$$a(+RCp`AM={`gZ8DZais%?38{&s9rKN(@%G`u2P`Juvxz;o4) zZ(c@s7OhT6K879oJsCkQZu`@T!R(Db#7r`xvMs;6qS*8rHhvmMWAFd-$J3HOFl++Ufkl%~fA*7S|B~2|vYL4MXle_Eb&j=@ zxs|z;v5HY1ksZMZI~>*@S|0i={XBga%}84qbSY?nx|!PIQM0qCP+Ag^faP|*+NNzl zyi>B1pXjR}N#11W6?%tR0jba{a!siDd~;)qw#m_8(C{7Fl@5MMX(hj;N~uhrTyP=U zX!m>oaor=2z%18Uoe?Cs6?Z{u9N$?J?>*}khW9L;!Kk%+ha{}`E>M8rI2uO=E)MjTd$E48e@eh2e*m)q;NkWqxc;CH51Q#z#=6z_K@8w| zzEDenTYMiRKCLBlPC&`TpFV+{B^F$E99|$g@|ib*#3YiJN{%b%@pPw{{ydySUYm2K zGVNi}s{$X4PhR>cJbprWGUGcxY!-R#_3O7ko~10_?@L!i7n3~coQ=Z{_jh*>tPJdz zb}T8EJTr0cZ{&W7s8dA0GzI6{bC7QJgTr%gdjbybQrz1IbB1^L4-Tk>cUM{0F+P2+97}y4%4Ef; z(1HSOfvDQ3HX!-6hPLv~0yIzOZuLNOvzzrQxkDors=BfbwTjwoV`WZNp5mE2L+RrD z*4*~`oRu22vc7V$+N>(F=9SdsH`{ZxE9Kg%Vnb&&Y_}A3xD{vd2pji6Axng!N(3P+ zlt?n9Fe(*FB#3ApEX;!88fjriO@*$#tyrrmt0Z+tsZ#HVPBI;we_7MUi)YKMpih$QO^|9&GSV{CXEW;qMJ$68ZpLUZ88 z8rY^*cP>F~I;%t3V$8K$)JZcX?zI&i?7u!xbD3ys0P7lsbqy=r3w^~BOnVD_(+vEZVuHT? zLh~(S}lzlR{OLzAuucz%TT{ft?Cwu zNFb2Z*XVV|4kc2ltWufq3lY6Z^3?w`bx`YbY_dv2~uZ05woN>?2?xROW=*7fK z1Ln6B=C^nW7-Ob7LjX(0<8_zLXM}Ph8LD#GviMnzJ&-=!;TRc)2cg=oIRr0-N1tQ7`_05>wgJ{<5ka%%ae~}d?zxeRoZcrBRB!#N?pSeX|5Hs6Q8~~I z1d+(ZQVD|iVoW10skYloq&iDYd$p=fQr_t3Dtnxum;OBaZOR4x`6m-}_R3qA-`h3f z_n=Vg=g2IRh^?6l+#b~UkH|HzsV6zQw ax0%Ea?Z4!uF*+zHt6dile}H!u?0*7k6f_S2 diff --git a/backend/web/src/lib/api/endpoints/provider.ts b/backend/web/src/lib/api/endpoints/provider.ts new file mode 100644 index 0000000..a263923 --- /dev/null +++ b/backend/web/src/lib/api/endpoints/provider.ts @@ -0,0 +1,13 @@ +import { api } from '../client'; +import type { Provider, Item } from "$lib/types/api" +import { space } from "$lib/state/space.svelte" + +export const providerApi = { + providerTypes: () => api.get('/provider/providerTypes'), + getProviders: () => api.get(`/provider/${space.id}`), + getProvider: (id: string) => api.get(`/provider/${space.id}/${id}`), + createProvider: (data: Partial) => api.post(`/provider/${space.id}`, data), + updateProvider: (data: Partial) => api.put(`/provider/${space.id}`, data), + deleteProvider: (id: string) => api.delete(`/provider/${space.id}/${id}`), + getAvailableModels: (data: Partial) => api.post(`/provider/${space.id}/avalable-models`, data), +}; diff --git a/backend/web/src/lib/api/endpoints/user.ts b/backend/web/src/lib/api/endpoints/user.ts index e4a8250..c2901c8 100644 --- a/backend/web/src/lib/api/endpoints/user.ts +++ b/backend/web/src/lib/api/endpoints/user.ts @@ -1,8 +1,8 @@ import { api } from '../client'; -import type { User, Address } from "$lib/types/api" +import type { User, Address, UserWithTeams } from "$lib/types/api" export const userApi = { - me: () => api.get('/user/me'), + me: () => api.get('/user/me'), update: (id: string, data: Partial) => api.put(`/user/${id}`, data), listAddresses: (id: string) => api.get(`/user/${id}/address`), diff --git a/backend/web/src/lib/components/FormError.svelte b/backend/web/src/lib/components/FormError.svelte index 8d7eccd..93a7af9 100644 --- a/backend/web/src/lib/components/FormError.svelte +++ b/backend/web/src/lib/components/FormError.svelte @@ -8,6 +8,4 @@ {#if errors.has(key)} {errors.get(key)} -{:else} -  {/if} diff --git a/backend/web/src/lib/components/Sidebar.svelte b/backend/web/src/lib/components/Sidebar.svelte index faf0a97..d209f38 100644 --- a/backend/web/src/lib/components/Sidebar.svelte +++ b/backend/web/src/lib/components/Sidebar.svelte @@ -3,6 +3,7 @@ import Menu from "$lib/components/Menu.svelte" import { logout } from "$lib/state/auth.svelte" import logo from "$lib/assets/logo-txt.png" + import { space } from '$lib/state/space.svelte' let {handleMenuDesktop, handleMenuMobile} = $props(); @@ -12,7 +13,7 @@ -
+
{#if uiState.menuContentVisible}
logo @@ -25,24 +26,38 @@
+{#if uiState.menuContentVisible} +
+
+ +
+
+{/if} -
+
{#if uiState.menuContentVisible} -
-
Fabien Masson
-
- Modifier +
+
+
+ FM +
+
Fabien Masson
-
-
-
diff --git a/backend/web/src/lib/state/auth.svelte.ts b/backend/web/src/lib/state/auth.svelte.ts index 4f086fd..a9ea9a4 100644 --- a/backend/web/src/lib/state/auth.svelte.ts +++ b/backend/web/src/lib/state/auth.svelte.ts @@ -1,15 +1,13 @@ -import { type User } from "$lib/types/api" +import type { User } from "$lib/types/api" type AuthState = { - user: User | null; - status: 'loading' | 'authenticated' | 'unauthenticated'; - //accessToken: string | null + user: User | null + status: 'loading' | 'authenticated' | 'unauthenticated' } export const auth: AuthState = $state({ user: null, status: 'loading', - //accessToken: null }) export const logout = () => { diff --git a/backend/web/src/lib/state/space.svelte.ts b/backend/web/src/lib/state/space.svelte.ts new file mode 100644 index 0000000..78275d4 --- /dev/null +++ b/backend/web/src/lib/state/space.svelte.ts @@ -0,0 +1,6 @@ +import type { Team } from "$lib/types/api" + +export const space = $state({ + spaces: [] as Team[], + id: "", +}); diff --git a/backend/web/src/lib/types/api.ts b/backend/web/src/lib/types/api.ts index 185e268..9a3134d 100644 --- a/backend/web/src/lib/types/api.ts +++ b/backend/web/src/lib/types/api.ts @@ -1,3 +1,8 @@ +export type Item = { + id: string + text: string +} + export interface User { id: string firstname: string @@ -9,9 +14,54 @@ export interface User { _version: string } +export interface UserTeam { + id: string + userId: string + teamId: string + administrator: boolean + _version: string +} + +export interface Team { + id: string + label: string + defaultModelId: string + _version: string +} + +export interface UserWithTeams { + user: User + userTeams: UserTeam[] + teams: Team[] +} + export interface Address { id: string type: string address: string _version: string } + +export interface Provider { + id: string + teamId: string + type: string + name: string + apiKey: string + baseUrl: string + models: string + _date_created: string + _date_updated: string + _version: string +} + +export interface Model { + id: string + teamId: string + providerId: string + modelName: string + configuration: object + _date_created: string + _date_updated: string + _version: string +} diff --git a/backend/web/src/lib/utilities/validators.ts b/backend/web/src/lib/utilities/validators.ts index ee66096..95d8095 100644 --- a/backend/web/src/lib/utilities/validators.ts +++ b/backend/web/src/lib/utilities/validators.ts @@ -1,5 +1,10 @@ const emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; +const urlRegex: RegExp = /^https?:\/\/([a-zA-Z0-9.-]+|\[[0-9a-fA-F:.]+\])(:\d+)?(\/[^\s]*)?$/; export function validateEmail(input: string): boolean { return emailRegex.test(input); } + +export function validateUrl(input: string): boolean { + return urlRegex.test(input); +} diff --git a/backend/web/src/routes/(authenticated)/(chat)/+page.svelte b/backend/web/src/routes/(authenticated)/(chat)/+page.svelte index b872b49..0b1bff7 100644 --- a/backend/web/src/routes/(authenticated)/(chat)/+page.svelte +++ b/backend/web/src/routes/(authenticated)/(chat)/+page.svelte @@ -1,7 +1,8 @@ - +
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur? +
diff --git a/backend/web/src/routes/(authenticated)/+layout.svelte b/backend/web/src/routes/(authenticated)/+layout.svelte index a4444c7..63d3b0b 100644 --- a/backend/web/src/routes/(authenticated)/+layout.svelte +++ b/backend/web/src/routes/(authenticated)/+layout.svelte @@ -3,6 +3,7 @@ import { page } from '$app/state'; import {uiState} from "$lib/state/ui.svelte" import { auth } from '$lib/state/auth.svelte' + import { space } from '$lib/state/space.svelte' import Sidebar from "$lib/components/Sidebar.svelte" import { goto } from '$app/navigation' import { onMount } from "svelte"; @@ -39,7 +40,9 @@ onMount(async () => { handleResize() if (data.me) { - auth.user = data.me + auth.user = data.me.user + space.spaces = data.me.teams + space.id = data.me.teams[0].id themeToLocalStorage(auth.user.theme) applyTheme() auth.status = 'authenticated' @@ -64,7 +67,7 @@
-
+

{page.data.title} {#if page.data.back} diff --git a/backend/web/src/routes/(authenticated)/profile/+page.svelte b/backend/web/src/routes/(authenticated)/profile/+page.svelte index 321f77f..ca0af48 100644 --- a/backend/web/src/routes/(authenticated)/profile/+page.svelte +++ b/backend/web/src/routes/(authenticated)/profile/+page.svelte @@ -2,7 +2,7 @@ import { SvelteMap } from 'svelte/reactivity'; import type { PageProps } from './$types'; - import type { User, Address } from '$lib/types/api' + import type { User, Address, Item } from '$lib/types/api' import { userApi } from '$lib/api/endpoints/user' import { miscApi } from '$lib/api/endpoints/misc' import FormError from '$lib/components/FormError.svelte'; @@ -13,15 +13,15 @@ let { data }: PageProps = $props(); - let form : User = $state(data.me) + let form : User = $state(data.me.user) let addresses : Address[] = $state([] as Address[]) let newAddress : Address = $state({} as Address) - let timezones = $state([] as string[]) + let timezones = $state([] as Item[]) let errors = new SvelteMap() onMount(async ()=> { addresses = await userApi.listAddresses(form.id) - timezones = await miscApi.listTimezones() + timezones = (await miscApi.listTimezones()).map((it)=>{return {id:it, text:it}}) }) $effect(()=>{ @@ -64,24 +64,26 @@ -
+

Mon compte

{errors.clear()}}> - - - +
+ + + +
-
-
- +
+
+
-
- +
+
-
+
-
+
- +
-
+
+ +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
    + {#each availableModels as model (model.value)} + {#if model.value} +
  1. + +
  2. + {/if} + {/each} +
+
+
+ +
+ + +
+ +
+
diff --git a/backend/web/src/routes/layout.css b/backend/web/src/routes/layout.css index 5531ffb..0184019 100644 --- a/backend/web/src/routes/layout.css +++ b/backend/web/src/routes/layout.css @@ -8,35 +8,45 @@ html { @apply h-full; } body { - @apply h-full bg-stone-100 text-stone-900 dark:bg-stone-900 dark:text-stone-200; + @apply h-full bg-stone-100 text-stone-950 dark:bg-stone-950 dark:text-stone-100; } -label { +.formelement > label { @apply text-xs text-stone-600 uppercase dark:text-stone-400; } hr { @apply border-stone-200 dark:border-stone-800; } h2 { - @apply mb-4 font-bold; + @apply mb-4 text-base font-bold; +} + +.container { + @apply mx-auto max-w-3xl; } .pointer { @apply cursor-pointer; } .bt { + appearance: button; @apply cursor-pointer rounded bg-stone-300 px-4 py-1 font-bold hover:bg-stone-200 dark:bg-stone-800 dark:hover:bg-stone-700; + &.small { + @apply px-2 py-1; + } } .menuitem { - @apply text-stone-800 text-stone-950 dark:text-stone-300 hover:dark:text-stone-50; + @apply text-stone-950 dark:text-stone-300 hover:dark:text-stone-50; } .header { - @apply p-2 text-lg; + @apply py-2 text-lg font-bold; + /* h1 { - @apply rounded bg-stone-200 px-2 font-bold text-sky-600 dark:bg-stone-800 dark:text-sky-200; + @apply rounded bg-stone-200 px-2 font-bold uppercase dark:bg-stone-800; } + */ &.settings { h1 { @@ -53,10 +63,6 @@ h2 { @apply text-sky-500; } -.formgroup { - @apply rounded border border-stone-300 bg-stone-100 p-2 dark:border-stone-700 dark:bg-stone-900; -} - #outer { @apply flex h-full flex-row; } @@ -94,7 +100,7 @@ h2 { @apply ml-10; } #sidebar { - @apply fixed left-0 h-full w-full bg-stone-100 dark:bg-stone-900; + @apply fixed left-0 h-full w-full bg-stone-100 dark:bg-stone-950; } .mobileMenuClosed { #sidebar { @@ -103,14 +109,24 @@ h2 { } } -/* svelte select */ +/* form */ -.textinput { - @apply h-8 w-full rounded border-stone-700 bg-white px-2 py-1 text-stone-900 dark:bg-stone-800 dark:text-stone-100; +.formgroup { + @apply rounded border border-stone-300 bg-stone-100 p-2 text-sm dark:border-stone-700 dark:bg-stone-900; } +.formelement { + @apply mb-3; +} + +.textinput { + @apply h-8 w-full rounded border-stone-700 bg-stone-50 px-2 py-1 text-sm text-stone-900 dark:bg-stone-950 dark:text-stone-100; +} + +/* svelte select */ + .svelte-select { - @apply relative flex h-8 w-full border-none text-stone-900 dark:bg-stone-800 dark:text-stone-100; + @apply relative flex h-8 w-full border-none text-stone-900 dark:bg-stone-950 dark:text-stone-100; } .svelte-select .value-container { @@ -187,7 +203,7 @@ h2 { } .svelte-select-list .list-group-title { - @apply h-8 cursor-default px-5 text-sm leading-10 font-medium overflow-ellipsis whitespace-nowrap text-gray-400 uppercase; + @apply h-8 cursor-default px-5 text-sm leading-10 font-medium text-ellipsis whitespace-nowrap text-gray-400 uppercase; } .svelte-select-list .empty { @@ -195,7 +211,7 @@ h2 { } .svelte-select-item { - @apply h-8 cursor-default overflow-hidden px-5 leading-10 overflow-ellipsis whitespace-nowrap text-gray-800; + @apply h-8 cursor-default overflow-hidden px-5 leading-10 text-ellipsis whitespace-nowrap text-gray-800; } .item.group-item { @@ -223,7 +239,7 @@ h2 { } .multi-item { - @apply mt-1 mr-1 flex h-8 max-w-full cursor-default items-center overflow-hidden rounded-sm border border-gray-200 bg-gray-100 pr-1 pl-1 leading-8 overflow-ellipsis whitespace-nowrap; + @apply mt-1 mr-1 flex h-8 max-w-full cursor-default items-center overflow-hidden rounded-sm border border-gray-200 bg-gray-100 pr-1 pl-1 leading-8 text-ellipsis whitespace-nowrap; } .multi-item.disabled { diff --git a/backend/web/static/assets/fontello/config.json b/backend/web/static/assets/fontello/config.json index 3fb6ec7..2dac8a1 100644 --- a/backend/web/static/assets/fontello/config.json +++ b/backend/web/static/assets/fontello/config.json @@ -119,6 +119,18 @@ "css": "cancel", "code": 59401, "src": "fontawesome" + }, + { + "uid": "44e04715aecbca7f266a17d5a7863c68", + "css": "plus", + "code": 59402, + "src": "fontawesome" + }, + { + "uid": "f48ae54adfb27d8ada53d0fd9e34ee10", + "css": "trash-empty", + "code": 59403, + "src": "fontawesome" } ] } \ No newline at end of file diff --git a/backend/web/static/assets/fontello/css/fontello-codes.css b/backend/web/static/assets/fontello/css/fontello-codes.css index 819938a..7482433 100644 --- a/backend/web/static/assets/fontello/css/fontello-codes.css +++ b/backend/web/static/assets/fontello/css/fontello-codes.css @@ -9,6 +9,8 @@ .icon-logout:before { content: '\e807'; } /* '' */ .icon-left-big:before { content: '\e808'; } /* '' */ .icon-cancel:before { content: '\e809'; } /* '' */ +.icon-plus:before { content: '\e80a'; } /* '' */ +.icon-trash-empty:before { content: '\e80b'; } /* '' */ .icon-facebook:before { content: '\f09a'; } /* '' */ .icon-tasks:before { content: '\f0ae'; } /* '' */ .icon-menu:before { content: '\f0c9'; } /* '' */ diff --git a/backend/web/static/assets/fontello/css/fontello-embedded.css b/backend/web/static/assets/fontello/css/fontello-embedded.css index c9d9a5e..fd801f6 100644 --- a/backend/web/static/assets/fontello/css/fontello-embedded.css +++ b/backend/web/static/assets/fontello/css/fontello-embedded.css @@ -1,15 +1,15 @@ @font-face { font-family: 'fontello'; - src: url('../font/fontello.eot?82712141'); - src: url('../font/fontello.eot?82712141#iefix') format('embedded-opentype'), - url('../font/fontello.svg?82712141#fontello') format('svg'); + src: url('../font/fontello.eot?20532310'); + src: url('../font/fontello.eot?20532310#iefix') format('embedded-opentype'), + url('../font/fontello.svg?20532310#fontello') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'fontello'; - src: url('data:application/octet-stream;base64,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') format('woff'), - url('data:application/octet-stream;base64,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LLIAAEcrLbBULLIAAUcrLbBVLLIBAEcrLbBWLLIBAUcrLbBXLLMAAABDKy2wWCyzAAEAQystsFksswEAAEMrLbBaLLMBAQBDKy2wWyyzAAABQystsFwsswABAUMrLbBdLLMBAAFDKy2wXiyzAQEBQystsF8ssgAARSstsGAssgABRSstsGEssgEARSstsGIssgEBRSstsGMssgAASCstsGQssgABSCstsGUssgEASCstsGYssgEBSCstsGcsswAAAEQrLbBoLLMAAQBEKy2waSyzAQAARCstsGosswEBAEQrLbBrLLMAAAFEKy2wbCyzAAEBRCstsG0sswEAAUQrLbBuLLMBAQFEKy2wbyyxADwrLrEwARQrLbBwLLEAPCuwQCstsHEssQA8K7BBKy2wciywABaxADwrsEIrLbBzLLEBPCuwQCstsHQssQE8K7BBKy2wdSywABaxATwrsEIrLbB2LLEAPSsusTABFCstsHcssQA9K7BAKy2weCyxAD0rsEErLbB5LLEAPSuwQistsHossQE9K7BAKy2weyyxAT0rsEErLbB8LLEBPSuwQistsH0ssQA+Ky6xMAEUKy2wfiyxAD4rsEArLbB/LLEAPiuwQSstsIAssQA+K7BCKy2wgSyxAT4rsEArLbCCLLEBPiuwQSstsIMssQE+K7BCKy2whCyxAD8rLrEwARQrLbCFLLEAPyuwQCstsIYssQA/K7BBKy2whyyxAD8rsEIrLbCILLEBPyuwQCstsIkssQE/K7BBKy2wiiyxAT8rsEIrLbCLLLILAANFUFiwBhuyBAIDRVgjIRshWVlCK7AIZbADJFB4sQUBFUVYMFktAEu4AMhSWLEBAY5ZsAG5CAAIAGNwsQAHQrEAACqxAAdCsQAKKrEAB0KxAAoqsQAHQrkAAAALKrEAB0K5AAAACyq5AAMAAESxJAGIUViwQIhYuQADAGREsSgBiFFYuAgAiFi5AAMAAERZG7EnAYhRWLoIgAABBECIY1RYuQADAABEWVlZWVmxAA4quAH/hbAEjbECAESzBWQGAERE') format('truetype'); + src: url('data:application/octet-stream;base64,d09GRgABAAAAABtwAA8AAAAALBgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAARAAAAGA+I1PFY21hcAAAAdgAAADdAAAC0G9nGq1jdnQgAAACuAAAAAsAAAAOAAAAAGZwZ20AAALEAAAG7QAADgxiLvl6Z2FzcAAACbQAAAAIAAAACAAAABBnbHlmAAAJvAAADjQAABQUeuV0NWhlYWQAABfwAAAAMwAAADYxnQn3aGhlYQAAGCQAAAAgAAAAJAhaBINobXR4AAAYRAAAADUAAABYTP3//WxvY2EAABh8AAAALgAAAC48eDhibWF4cAAAGKwAAAAgAAAAIAFODsduYW1lAAAYzAAAAXUAAALNzZ0dHnBvc3QAABpEAAAAsAAAAO6/M3V0cHJlcAAAGvQAAAB6AAAAnH62O7Z4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgYW5gnMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDAdeMHy8xRz0P4shinkNwzSgMCOKIiYAkDgNb3ic5ZLLbcMwEAWHsaJ8rHxsRanCDbqNHA0YcAUuIadc3IHhCvbIrcB5a+4t6iArjAA+EFyCs8A9sBAb0UH5oRD1rbTc8gXPt7zjS+tP3pX0tqy7eqwnH33rez/42S/XKxjz+UwVnbX580V+pw6dbtbzwCNP6r9k4IVX3tR9xZqRDyZt7WdP/l81xK8MuZrCQSP8WaI3xZLwbUk4tyRmwRK9PZbIApbIB5bIDJbEjFgiW1gSt6u7hgxSjw25pJ4asoqPDfnFtw2ZxvcNOccPDWLvuaE5wC8Npl/P3VtNAAAAeJxjYEAGAAAOAAEAeJytV2tbG8cVntUNjAEDQtjNuu4oY1GXHckkcRxiKw7ZZVEcJanAuN11brtIuE2TXpLe6DW9X5Q/c1a0T51v+Wl5z8xKAQfcp89TPui8M/POnOucWUhoSeJ+FMZSdh+J+Z0uVe49iOiGS9fi5KEc3o+o0Eg/mxbTot9X+269TiImEaitkXBEkPhNcjTJ5GGTClrVVb1JRS0HR8XlmvADqgYySfyssBz4WaMYUCHYO5Q0qwCCdECl3uGoUCjgGKofXK7z7Gi+5viXJaDyR1WnijVFohcdxKMVp2AUljQVPaoFEeujlSDICa4cSPq8R6XVB6NrzlwQ9kOqhFGdio14960IZHcYSer1MLUJNm0w2ohjmVk2LLqGqXwkaZ3X15n5eS+SiMYwlTTTixLMSF6bYXST0c3ETeI4dhEtmg36JHYjEl0m1zF2u3SF0ZVu+mhB9JnxqCz243iQxuR4cZx7EMsB/FF+3KSylrCg1Ejh01TQi2hK+TStfGQAW5ImVUy4EQk5yKb2fcmL7K5rzedfEknYp/JaHYuBHMohdGXr5QYitBMlPTfdjSMV12NJm/cirLkcl9yUJk1pOhd4I1GwaZ7GUPkK5aL8lAr7D8npwxCaWmvSOS3Z2nm4VRL7kk+gzSRmSrJlrJ3Ro3PzIgj9tfqkcM7rk4U0a09xPJgQwPVEhkOVclJNsIXLCSHpwsixlUitSresirkzttNV7BLul64d3zSvjUNHc7OiGEKLq+rxGor4gs4KhZAG6VaTFjSoUtKF4DU+AAAZogUe7WK0YPK1iIMWTFAkYtCHZloMEjlMJC0ibE1a0t29KCsNtuKrNHegDptU1d2dqHvPTrp1zFfN/LLOxFJwP8qWlgJyUp8WPb5yKC0/u8A/C/ghZwW5KDZ6Ucbhg7/+EBmG2oW1usK2MXbtOm/BTeaZGJ50YH8HsyeTdUYKMyGqCvFCQd0ZOY5jslXTIhOFcC+iJeXLkOZRfnOIcOLL5D+XLjliUVSF7/scgWWsOWm2PO3Rp577NMK1Ah9rXpMu6sxheQnxZvk1nRVZPqWzEktXZ2WWl3VWYfl1nU2xvKKzaZbf0Nk5lp5W4/hTJUGklWyR8w7flibpY4srk8WP7GLz2OLqZPFjuyi1oAvemX7CqX9bV9nP4/7V4Z+EXU/DP5YK/rG8Cv9YNuAfy1X4x/Kb8I/lNfjH8lvwj+Ua/GPZ0rJtCva6htpLiUTTc5LApBSXsMU1u67pukfXcR+fwVXoyDOyqdINxY39iQyXvX92nOJsvhJyxdEza1nZqYURmiJ7+dyx8JzFuaHl88by53Ga5YRf1Ylre6otPC9W/iX4b+uO2shuODX29SbiAQdOtx+XJd1o0gu6dbHdpI3/RkVh90F/ESkSKw3Zkh1uCQjt3eGwozroIREePnRdvEgbjlNbRoRvoXet0EXQSminDUPLZoVP5wPvYNhSUraHOPP2SZps2fOoovwxW1LCPWVzJzoqybJ0j0qr5adinzvtDJq2MjvUdkKV4PHrmnC3s69SKUgGisp4VLFcClIXOOFO9/ieFKah/6tt5FhBwza/WDOB0YLzTlGibE+toIkgGWUUXPkrp+JENqLBRhTxm3fSL3WhENrjWEjMllfzWKg2wvTSZIlmzPq26rBSzuKdSQjZGRtpEntRS7bxoLP1+aRku/JUUKWB0d3j3y42iadVe54txSX/8jFLgnG6Ev7AedzlcYo30T9aHMVtuhhEPRdvqmzHrWzdWca9feXE6q7bO7Hqn7r3STsCTbe8Jync0nTbG8I2rjE4dSYVCW3ROnaExmWuz1Ub+RQfaL51nQtU4fq0cPPs+ds6m8FbM97yP5Z05/9VxewT97G2Qqs6Vi/1OLezgwZ8yxtH5VWMbnt1lccl92YSgrsIQc1ee3yN4IZXW3QTt/y1M+a7OM5ZrtILwK9rehHiDY5iiHDLbTy842i9qbmg6Q3Ab+uRENsAPQCHwY4eOWZmF8DM3GNOB2CPOQzuM4fBd5jD4Lv6CL0wAIqAHINifeTYuQdAdu4t5jmM3maeQe8wz6B3mWfQe6wzBEhYJ4OUdTLYZ50M+sx5FWDAHAYHzGHwkDkMvmfs2gL6vrGL0fvGLkY/MHYx+sDYxehDYxejHxq7GP3I2MXox4hxe5LAn5gRbQJ+ZOErgB9z0M3Ix+ineGtzzs8sZM7PDcfJOb/A5pcmp/7SjMyOQwt5x68sZPqvcU5O+I2FTPithUz4Hbh3Juf93owM/RMLmf4HC5n+R+zMCX+ykAl/tpAJfwH35cl5fzUjQ/+bhUz/u4VM/wd25oR/WsiEoYVM+FSPzpsvW6q4o1KhGOKfJrTB2Pdo+oCKV3uH48e6+QUl2gFBAAAAAAEAAf//AA94nJ1YXWwb2XW+5975J8Xf+aEkihY5/BMlUTJJkbYkU7R+aYmWZFmWTO2ubLf2ypWNrnfXdRzDcZ2s5cQvduFuWjQNEjsrJwGyCdYLIwGKNi0apw/75KKBtw9NH4o+OAgKFylQwMaa7rlDOvGi3aaoJM7MvXNneM8533fOd0QoIc8/YI/oT0iCzJGxyui+MCUwBoz0AGWspgGDuRzQfQQIbBHCyBZhlLI6YYweI5TRA+OV8qgdswXJ6gXdA3YsJcmSbMeSQ8lCcWiMFuVSmZaykCqUIRcBS5fkCOwAcwfTZQ+kkvgr4UNmPlcslXFVKgIssHnv1GBu+pDRSSU3UBAYg7Do8QhT87B57+G9zYeLk6Jb6VQFUWBANTmsr0znBv/0TLd/bXt8qgZt1WW4s/9KTd1piYImgyAAk/AlETEU8KXPTsxfqdWu/NPEuZTH1KIuJkoaUEUDQbR2qrMsN1C4OtubSZ0n0vPnzzeFAbZE/CRHRsgkWSFHyBuV0wsetB1qflBd6hZxKa4tHyhU2fKi2+iWDCI6TITLbo2CREC6RCQB/y4RQbjiQe8SVscTI8faAH16YP21tfrK8tLi3Oy+mYnxsfLw7nZDby/ZwagvIO3oBcefpUIe/VfKlSRDB12yo7Ek+lTESVrGkBVLuYhg4Y0Y+j1n4kUWytQUdSllJ1PFoQJ3cRmsXOrXS+bWhuf6KzAlZMajyQSj7yxNNEKTiyC4fd3J4agUz1YXp9t7fEpsV7Lb54Fnf7d8bhn/4NqlDy7Ti/cuwEQ5O7d7rZ8lEtHJtDA107q/zib7+n5qdkCb4ZtvvDI+Pz8e2TW+q5A0Q+EOavo6NGomC7vGw/TGCH9gufG4fole+OF56co/9GZhku2d9xltoRC0bqOPyPNz7BZzEYXoJEvylcEkoiKdCjAqEEAn1ggT2BYRqLBFKKGIVUCsApwL2/2hgCh19pYKSQ+NQDEBUmwAkoUSRCDhYJC7o5QzLVP3gmEV0Zc586Ee0WmoIwSvN94xhs0Rw4CL5jL8WVvnlxZO3rx5snu6XVXfO00zc1Gv1uUxaaA7IHT8Z+MdXd+jj5hwsbT8czMxtw43H/wR1X1SQF7/wiht79c1gj+cd3fZmmPPJpmqjJ+o1/YKRBhBvJBCutOHsEaTREHckgDnX5jDgPMP7aT03KuvHDywr9qbiXUHA7IU6oVCMuYBM1dMGLrkRcxwgxzzBoBTUuoFJCXSTZZinHYFpFspOQBIzaECN7rUmsznduAAf0cgZyJTrVIxZ7VeJuNEBOjI0vklunJ2BcKKfFJzBdOS6F1sk+X97R2qLPguKm5fp7Ug+aRpUxCVtOZVXpcV0MSTisdKNNcq+0MdqsL8F2U3eMPWguiVq7ogqM3FGqw3Q3+e3/dFjM6c5JGMRRBH25Ra2KfJG6p7VJQqEdEjuXPecKcX3LKztr2ju192y/riS0tdI6I4EW4t7fCB+0UM6EfMTQwSIYlKDAkrbjEAAT6FI3IuaPn9Vk6Swr2JJu+GCmVmmTlkHGPIpiwU0ScfTe9sxHdOa6FMuX/fR7OZ8WRYuYEkEb70/pWp0cOHRweXV0bTUK0my8sr8DeHLzkkIkTEfTxh/4pYkIiX7CZlUgW5YlTKIz5MMTIRCohvWtuL+5qb+0BbPFwZJDKCXRYuEyLgvbeQHgLCf0PBgSSCdJKIlIqrRBTpEUJFutA594ELn+tprZfh//CA9f/6osrOlx9Bal7+rc/U6/WKScjkxJ7RndmeZKTTDKInJF3FipIopWQjb0AS8WwiRINGKwB+ZGw0Z0UAb6SSOCXJft20orniHijgQpNZYA+BnELsIoR1+PfKocoQGKp6Xw3gJ74+0RicWF+fgAd2RGVyp6K1uRuDiQIU4/AgURDjSqh0u3HtNn0jfzvv6/Md8v3V3kN7dxTh5otXNH682XzB+Dp4hKAUVgRWSLTeMS3jGxS4catx7RZkC7cLXu8hXx+SmDz/Chui/4aIi1eiTS7j7FVCAegq0hqOECx4C2YiqQtSB5ZUuZWuxgDtRuOKVjTFR8hJMNmQ3viqOWxkTPO9xue64vEuuPaeaWYwY8EpHYYjeuNdXc8Yo8Z7mchMJAN39FEcGo2v6g7+n7BTWPtTpELGK2M6fjHUiIRBkcTLRGRUZFixGEaPXMZNUgnoBh+wVSz/WAcxtAum3Z7IJDCndCE5TC9girCb8eHZw7CcqZTdig8vVk2T0BS7aU8pj+nHRGPgBMUdKMqH3K0fYjmG5tBx6D2JSpRKrsbfu8LmU49pep6aYRcMuLI0IHpUATASX5lY1xSXKmFywWTYOI8PClSBPo+r8UDTvbdNz0OvDrcxWas4wfNwMx51jEeXEw9evLnUucorzstmJi3TduLhANCpFJhFnSrSBJgXojmT1eNdjc9tG0bGGDG45+E0RgL9vQ3XuuKwjhHYxgD0tm7AKcPoMYfN7fSLvTymP6NXSZxEKp2xdp8sICxqKHAwDyF7yDk9rDuoSDhfPwDyC2i0ELEDSi92Y5n0Z94aAnd7Gw81Hz/7fjP2ere3vWdMfnHnjve/L/Rm+QJnT09YAHOTTXoqSQSD0PSP6IiYVZGLmCOUi5gFO5+w8zbPktxJKRsPjmwZwgOvME6cOSgsI4+uCnSbj7rNU2Y3PEIa4yBincILPvgRn/2FibPGL1qzZjdfjnmB102+Hy/ZQQZQkU2QDXK8cmx1ikpKT7Tdr3K9RWsIXryQgFwWKCWyRORLxENUxaNueNuogrpMAkXaILLLJa8SWXYdIS7ZtXDi+LH1V+oHlxZq+2b2julxPcl/bB8XYX69WUFb0LZ+yzjoj/r1COSjKLogjwXXlmTR4Gv8LfHmbxFgBHglzvNaiweIaEpc0ZzDjd9cXtfk5qWsVRtuRaHwgCpK49rTTkG8KwnwS00ptrLPEF/3fkrtMz+0Mmrq+8ikHzX+mk/CXn78jOvGcep/9tita5pOT+wVAcSD+I3PHmcnx7M06GziNSMMEf01zcHFXWqhLta5FsOxhJkDs9lVHiL0/AY+j8kMAYLnIwISmS7YfvwJRnmqAAMzQhfkZduPv0McGfkctVYHY9vm9e9dv3722BKb++N0evNO4zB8986Fk28RJ/ZP2COMPSMycZFO0ovxP1J5tQ9EVwE0IQxM1fG7hRreFQWXuIGVR1MFbYOouDeVbWDOU2SqYNhxxzJs4Eslsorck47wkrMwXMoNZNLJZILv1O9zY9gT0aFoCj+J/JDNcS1Hm2jGUmPyapRqjUutsd0aY9xNOoLq8WsP6eiz+3Di448hYno+OYoZyPSwW87pM0eV6sOZj2eePbruzFz3opwHzw0Pnrw3+BT4bvAUyA+ONn7C1uj9FidKlUIaOxkFjUUioLwQmChg3sZcwjB/Y+hglUvmIzzlLGCbNpTMO9rmJeu4Newl66zW2H55XNd9nzxubtnPd/jZo+MzzuVMc+tVxw7nCJ4ZbscMf4DnQMHh922sSW7STvJkjcxVqvWl+RnM421oEKM1FWRF3iK82RKcZgstYzw9iiiQRUlypIV0DLWGdODQst01V4oFesNBjccS+9MsK2MTIP76yiok7ZijiHmN0iMMiVhmJdS6ghzLCinUeiX+QYIjRC0kqmnoMtYqTywbd1Nfdy4SgN99aXB4fq+1kj6aOhQar0G8uDSbXc/OLu2KXYqZs8ubK7ne6qvzteGgXfOG96ztWVo7ODv86kiXt/Y9M5um8Vy6EBMyfaFPDSbW3ZLkXp/YWe0z3VTpSNdunp3qLcd0VFhaKLYrPnX2Sr0/V9ndN6AHshnYXdnZX2/1GCpytJsMkrcrGqKCdaC8pbWmjGzHEi9utfomaCb2LcrrTEsvGpje/4eb/8uDKOXUaDQeDTh1IIFNB7b2yRgeqUNx3uXneTOBdwzdRPHMGxMZvRqBLtCZagxUq535wem1rkN3Lh1Nnw22n0mPD3V19enx2jej8UhET9KDvwP0/emp3w8EkmB/+Q+/FUvG9XiiqzA2dYZ+MbZsRzSZHTxvUYVi093S+aKEeaMNEYXZKt6JzAjzqlrrSYUMFXPXLNf6Vx1u1Dk3jnFuHOiOmDrjnZVlemgWe2wRNT/KFxHhkuC9kC5bppP0x7gSKJZ4/5RAYSaa7J81evTbf/vto1SDijvipifbnt2gEmu8G4oIdnc3aOopxQXoK3nwL9xu+iZDdfNmG1y+mxxP0kw5ffeEIEC7W7wP8HbwcElfNH4lt7XJvzIWjbenhsWQhDfui45ueP4c41x1anSxkg8gy4PAmcL5gorm93CNKBCeDTH4dYLvPUawmThgJOxUwucU7CiCmv/vhnMC4yMjGTzAqxfngg3fh3fl1//y84e/cXacTp/51sp3zv/B5OvVC1X8G1wqpH3if8CfJ2Kf//Hpybdu/eDWW5NvnpmYvfAnF2bDyWKf8WKPm+yXiMUw11mGHtRQ2wScxubT7XrEMJnU3gumzBz0cJGDGOJNqgp44nqL/WNQuM68iibJz76s+WXR5Qb4l2fv/1xnQXZL1VmtzfrkOz5VZCfvtFEh4P4JnX/2yStKv0ZDYosXdfTXTjJN1iqrGWBiFyiskqCCMpKnkowVREF0K9jFCNjOoHYAiatfFMWEKSK6VEbQyBIvKIQi1ShHDCUH7GSqZ8iyrbjKFYPuoVz7ONrMtJrezFJMMy3U8Ey6A3jDHaEJoykfmoKgpZRYHR26cvQHo4JYk/xCz7mJ4ZOLGZqtnX7jeHq/P2g9xYza56+Ofm1pFWPT+LqmfMjr+RccsQDrODm5tE/yCPux8RoaztY2z27WsunEfl8/6udQMFDdXZ48+43Zp/whW9F+iuf/At+wL894nGNgZGBgAOKjq3cqxvPbfGXgZ34BFGF4titZG0b///8/i5WNOQjI5WBgAokCAHVPDRMAeJxjYGRgYA76n8XAwMr6////v6xsDEARFCAGAI/xBeZ4nGN+wcDADMQs+v//My8AsiMZGJhOQcRAbJgYsyACM1mjyQPFWFlBfKAZL4AYKA4AvJYQOQAAAAAAAAAAkAFUAbwCfgLCA7gD/gSABMYFEAVYBhwGVgbiB0gH7ghyCOIJNAl6CgoAAAABAAAAFgBrAAYAAAAAAAIAJABOAI0AAACADgwAAAAAeJx1kN9OwjAUh3/lnwqJGk28tVcGYhywRC5ISEgwcKM3xHBrxhjbyFhJV0h4Dd/Bh/ElfBZ/jGKMxC1dv/P19LQ7AK7wBYH988ixZ4FTRnsu4AQ9y0X6J8sl8rPlMmp4tVyhf7NcxT1CyzVc450VROmM0QIflgUuxYXlAs7FreUi/YPlErlnuYwb8WK5Qu9brmIiMss13InPgVptdRxGRtYHDem23I6cbqWiilMvkd7aREpnsi/nKjVBkijHV8sDj4NwnXj6EB7mSaCzWKWy7bQOahSkgfZMMNtVzzaha8xczrVayqHNkCutFoFvnMiYVbfZ/H0eBlBYYQuNmK2KYCBRp21wdtHi6JCmzJDM3GfFSOEhofGw5o4oX8kY9znmjFLagBkJ2YHP7/LIj0kh9yesoo9W/8YT0u6MOPcSbdZtHWWNSGme6eV29nP3DBue5tIa7trdUue3khj+qSHZj93agsand/KuGNoumnz/+b9v5nGEUQAAAHicbchRbgIhFEZhfmVwdFpbbWtXMYu6g1cgIhC4pHH3xvja7+0ctVIvO/W/E1ZYQ2OAwQYjtthhwhvesccHPnHAEV/4xg9O+FXaepKhN67N/FVO1q9tdvo5NJ+DbGtwXuYlOBOzy13GyJdXW0qWoy6xt0kqNT/zrch9vJDlJefrINSuTd84deOC+L4MVErkvat07iQhp9lSMS5nF3kqVLjOJVLijQ9Ncr0r9QBvsTmxeJxj8N7BcCIoYiMjY1/kBsadHAwcDMkFGxnYnTYyMGhBaC4UeicDAwM3EmsnAzMDg8tGFcaOwIgNDh0RIH6Ky0YNEH8HBwNEgMElUnqjOkhoF0cDAyOLQ0dyCEwCBDYy8GntYPzfuoGldyMTg8tm1hQ2BhcXAJQcKgcAAA==') format('woff'), + url('data:application/octet-stream;base64,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') format('truetype'); } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ @@ -17,7 +17,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; - src: url('../font/fontello.svg?82712141#fontello') format('svg'); + src: url('../font/fontello.svg?20532310#fontello') format('svg'); } } */ @@ -67,6 +67,8 @@ .icon-logout:before { content: '\e807'; } /* '' */ .icon-left-big:before { content: '\e808'; } /* '' */ .icon-cancel:before { content: '\e809'; } /* '' */ +.icon-plus:before { content: '\e80a'; } /* '' */ +.icon-trash-empty:before { content: '\e80b'; } /* '' */ .icon-facebook:before { content: '\f09a'; } /* '' */ .icon-tasks:before { content: '\f0ae'; } /* '' */ .icon-menu:before { content: '\f0c9'; } /* '' */ diff --git a/backend/web/static/assets/fontello/css/fontello-ie7-codes.css b/backend/web/static/assets/fontello/css/fontello-ie7-codes.css index a8aeb37..0c2ad43 100644 --- a/backend/web/static/assets/fontello/css/fontello-ie7-codes.css +++ b/backend/web/static/assets/fontello/css/fontello-ie7-codes.css @@ -9,6 +9,8 @@ .icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-left-big { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-trash-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-tasks { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/backend/web/static/assets/fontello/css/fontello-ie7.css b/backend/web/static/assets/fontello/css/fontello-ie7.css index 1d5224e..dee2b0c 100644 --- a/backend/web/static/assets/fontello/css/fontello-ie7.css +++ b/backend/web/static/assets/fontello/css/fontello-ie7.css @@ -20,6 +20,8 @@ .icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-left-big { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-trash-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-tasks { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/backend/web/static/assets/fontello/css/fontello.css b/backend/web/static/assets/fontello/css/fontello.css index a7562cf..badfbb6 100644 --- a/backend/web/static/assets/fontello/css/fontello.css +++ b/backend/web/static/assets/fontello/css/fontello.css @@ -1,11 +1,11 @@ @font-face { font-family: 'fontello'; - src: url('../font/fontello.eot?90952797'); - src: url('../font/fontello.eot?90952797#iefix') format('embedded-opentype'), - url('../font/fontello.woff2?90952797') format('woff2'), - url('../font/fontello.woff?90952797') format('woff'), - url('../font/fontello.ttf?90952797') format('truetype'), - url('../font/fontello.svg?90952797#fontello') format('svg'); + src: url('../font/fontello.eot?1806785'); + src: url('../font/fontello.eot?1806785#iefix') format('embedded-opentype'), + url('../font/fontello.woff2?1806785') format('woff2'), + url('../font/fontello.woff?1806785') format('woff'), + url('../font/fontello.ttf?1806785') format('truetype'), + url('../font/fontello.svg?1806785#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; - src: url('../font/fontello.svg?90952797#fontello') format('svg'); + src: url('../font/fontello.svg?1806785#fontello') format('svg'); } } */ @@ -64,6 +64,8 @@ .icon-logout:before { content: '\e807'; } /* '' */ .icon-left-big:before { content: '\e808'; } /* '' */ .icon-cancel:before { content: '\e809'; } /* '' */ +.icon-plus:before { content: '\e80a'; } /* '' */ +.icon-trash-empty:before { content: '\e80b'; } /* '' */ .icon-facebook:before { content: '\f09a'; } /* '' */ .icon-tasks:before { content: '\f0ae'; } /* '' */ .icon-menu:before { content: '\f0c9'; } /* '' */ diff --git a/backend/web/static/assets/fontello/demo.html b/backend/web/static/assets/fontello/demo.html index 50fb7d2..9aee99a 100644 --- a/backend/web/static/assets/fontello/demo.html +++ b/backend/web/static/assets/fontello/demo.html @@ -146,11 +146,11 @@ } @font-face { font-family: 'fontello'; - src: url('./font/fontello.eot?42653923'); - src: url('./font/fontello.eot?42653923#iefix') format('embedded-opentype'), - url('./font/fontello.woff?42653923') format('woff'), - url('./font/fontello.ttf?42653923') format('truetype'), - url('./font/fontello.svg?42653923#fontello') format('svg'); + src: url('./font/fontello.eot?13627011'); + src: url('./font/fontello.eot?13627011#iefix') format('embedded-opentype'), + url('./font/fontello.woff?13627011') format('woff'), + url('./font/fontello.ttf?13627011') format('truetype'), + url('./font/fontello.svg?13627011#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -245,34 +245,42 @@
icon-cancel0xe809
+
+ icon-plus0xe80a +
+
+ icon-trash-empty0xe80b +
+
+
icon-facebook0xf09a
icon-tasks0xf0ae
-
-
icon-menu0xf0c9
icon-github0xf113
+
+
icon-apple0xf179
icon-graduation-cap0xf19d
-
-
icon-google0xf1a0
icon-paper-plane0xf1d8
+
+
icon-history0xf1da
diff --git a/backend/web/static/assets/fontello/font/fontello.eot b/backend/web/static/assets/fontello/font/fontello.eot index 11e6f232e8c0a4ba9115e4087a9dab8529a03913..834321e9254dcc53d8052494e3f419c5930e1b1c 100644 GIT binary patch delta 1152 zcmah|Z)g)|7=NC-%X^o*n0W2wZnkNfcx_^rtaDA%4C-8~lXXy5nZs6{t7j7vuvw2b zjF;1{3@^{3uT1e;tg?vBo`@bNetDyW{u#p5O0% z?!EVUxV!)Em3{0=8sLTW2{s_q9-OV682X}G1Hjz?aA>M**)zqq71HMcxa(6NR$}DS z)p3YI@Q7V3AMSm+NZKYDC|YyGu#xlxu~eL1II{S2B?}-d0ccvOVC7#~_WwpNJW1;V zB{HP_!pEe4B;8diSLR38_dZ)E<1rZ%(=$`nw)s~N18f>0-CMTiZG1cUJ?VMUu@9_r z;o5RXl=LY&;5B<@uCkUnRso2VX#Jr*TdqfC)WA2@rVU6Y3g2^&u7T<3v16a!4JInVD`gV=@*=VOV2HlY(e& zPUNx_lG*-&T!z9R_UT4A)2H(-F})tskLoe38&M!93>24N#HmT8HmSeN`5KmFNQX7 zQb6VyN~{Q?qKM-lipnG?qB2&d& z&-?fv-Kxe_EsB|V-*&`IGLbZy=%cALH!|Zi6_rNw8oImXwquT_(uou>Dob6G+zemI z)qnCYWzn-md884LBo420lGOO@k9NU#feCm|mInH}8(X{kG3!2lF6mF}7mXMF$rVY) z%Z)YH#9=r7N8ZSD>iVOACd(RE81^Ch_H-GNy#A>7jUByQYx6`0!x4;X2j$gt=$06% zoqbT73~l=rLVTURRk;1_RO)Yb(nbz-CvT)VUUfbS#D^?K@P#o<26GRA#NY(o2Q1U0HD6Yu~-P(!Lh_3n-lI A&Hw-a delta 577 zcmX>Q`6h%dM~i{sh~`8#GnOc!r3Dimy6Z16Ffax%Ffb$}=Oz~9TUBuZ`5PD*n6@OB zl_&tkfk2uENbscHUTbvCl4^NF!TY%#eiO5W?*~4 zIe7|`tDpu08l3!!NfW4%ZL%WspUDQy?EE0NF)(}qlMD>PlXY0C>Oah4U;tqTZXmr5 zf*F7cKb(YM23`h+kHQelzz3u&A((+5NY8~}P)L4U0Kp7`K>7v*GYA3cTM*13%)rFJ z@P7mI3#P*istn!?_6|0lGEAFoSp~Q@rwZO@mnm2(6cx{J^Ob?0`31;{&sMdA0tZBE zPEL?CXB3${LsDn*8A)47FV<^pHf)dB)7YAjmdGc OPLnsv25gc$zy|=wT8$R~ diff --git a/backend/web/static/assets/fontello/font/fontello.svg b/backend/web/static/assets/fontello/font/fontello.svg index 88ab2d0..027acb8 100644 --- a/backend/web/static/assets/fontello/font/fontello.svg +++ b/backend/web/static/assets/fontello/font/fontello.svg @@ -26,6 +26,10 @@ + + + + diff --git a/backend/web/static/assets/fontello/font/fontello.ttf b/backend/web/static/assets/fontello/font/fontello.ttf index a2ef454c5bd0cbbf6386ad26b812807c80f9e0fe..6e4e3b3f5637f0e190bdc722d0aa9f385266480d 100644 GIT binary patch delta 1134 zcmah|U1%It6h7z9?47$a+ucqwJ8RR;X46S_jT@t8vsocEHmSuZ!4xA+wA6H(-R?rO zW=yt{1nCB>f-n9}ABqqVeAJ3H(t?P2Nf5z8AH~O@vPEs12hj@IdS<8kAc(Vk=R4nb z&%JxkVPH`HitWso+Afj)6o6fyeWjWtpPu%U6vC&SQsq?NofXm! z$xz8&B!<1Dr-?;rZu#`ekJTK2yb53#<)U49WG(nRz`^Rxyb)Uoeo=ren1o#T1X4XrrQjeP;!+YeL)PV%N zuDQS95xp1w^>asAk77WScJL2hX4pboLf(1UjFd#(RcWPGr!zf(Mtl!m;qCW*z#igH zd_b7^8y^q>*lG3Q&2nei2k69WK7jso=K~+$)qdv#4C3#bkmw%k1-V{2BQW~TND)QKq{Z3kj@PZ=Cc%ru-}YD zv;C&jk~Hf{^Ng9qdMtq?60tLsc;c$(-Z06H-bmDZ+e~`(zya=FZeAz?9qzODFsD1Sc>dnBBU~of|o$iG-V1DMVkRl z(I$!o`^DqWPd+;_{?wBrj~iV^s+OY1+RHmKs2e487Cx!`#&G5Eb`zL=(ReW1f#~L9a7+z;W zG~WDkzZ|&CW&Bwcg9F`-hr0(b=WYKu9qctfi#-rbUlJ-_ZEScZj(G7u@(LUDNywQnh923R~b^Uz!2PMAs(XU%Gk%PZMM5@!f3O{`@ zoB5mF^JX4R_e-;vNxHjj9&VrJaej<%D`Uz{u^_gC1Hl#5d&RvE%3L3gX%f{x-FCl> kCdS-_wozSn=FTo^)dhR8{9v)-RF~b)+m5aW_HTs$0@T6fU;qFB delta 528 zcmbOcaU^(xa{UDc2F3se28M*>+{A)>t12!ae**&p)0X725(S_*5J>X?3BI&~^xP!9 zpH)D<43Nu{o>*J}6c+&US%5T0dQN3pW9xZM1_qWC1_r@D8L5dWhP8p87#PG7fbwP; zKmm>@mPR0d29U3kky}#Xc026Tv<6FKLY5$vjzFZB_&cn&N47aX#nMK78Iox)NQlg#=xMdG4V$%wU!dkOukj00Rp{A5dHj=mTa3wild}-!QrgYA~R|$xcj~oAa5t z8Mzp~fX!iG5T4w^T$S}<76StaGjIdxbr8$|boYmo5X`{K!0=HRf*JULbR`5c@B`_& z5DW^uj|(7}K@dpafM5n8Abksh8H6`Cu&8ov-YamQU8Z2EP*gm>%~u9~<`*E>JX_Tc z@;ZptoV-KAoKa-*2ML|YDw4L6UaZ&HY}g*Lr?Fq-(BR19_y<%53JHrB{^Ww{ diff --git a/backend/web/static/assets/fontello/font/fontello.woff b/backend/web/static/assets/fontello/font/fontello.woff index 43dc1f8db3ca86c8c30645a2e94c36116ca906eb..7a434f97781013c5f665197f22ea56511e8108fb 100644 GIT binary patch delta 4569 zcmXY!byQT}*N2Bj!XZXF24?6kVFc-rRzg5PI>ce<6y_3wGJxRFEuf%;bPCc#3K9|` z-6bGMBkz3Q^*d`l>z@7W&%XDZKX07$!Cgpzp{6E?0EAzxo*?jlPhqCF5GA0;!QIXi z1R|Kmn>i4O@Vkc#OSyx;FBHFT#5+nnxAB0SJzd=Kt{Vg*-NP#?d(rb?7ds#P?5$dS zoBV&!xFCa^@va4*kp_Vvkl;068CNGeM-Yhd0H2Ycee|~f0(HZUqkzvZ>R{*a6`w5;gv7|y30*Oz?>F5}}2-FcyOHX}AA#B_A7 zcPFRr{73^`d^-mdmHLDiJmsRFyQD3I;J z9=L1EHNc%a=vwcm_7SG`k)`%grFO@eb6c9zHI#mdrZP&PZhD`~QjJNVKJRIu&cK~g zBYMHq_WMowh;}jRBAbypOMOtyXTn=#fVnl2b;j@O#{4;7&%${=9K(RPqUU)esr|Md zZd{9g7L)2|k*c@%8QE|$kP`nnV9JlJ%PXgBty|203H3ypnoeGbkD&V2BqfXhb613= z7<{=}5Z(aR=fo(=ky9`VJZ#5h{%%sccUUl2^btNh)av6BID%LR7!FY9=NeH0Y!fyO zA4Ckjts2<;D$XNL8g~qGDk~z0Y-0N!N=%NV?d)T)ORm0W7smlh9wk~y`SX#zhNOR+ zWRA#Rn5Q3$?8U0}t9rS{F{~M7q*f;iCUY?o=%%fb?}B{D#+|_Lv1dX{YR-yg!YN*+ zf`r1ALHiT7sEfo=Z64W&G)$2|<>n!|@ey7xwSIdQn^a)AWkT}ER#^s7R-v~+dULGT z0Jy&hDIs;Gva(9DEot7_#~F$uI@lg!Aw@K2Q_d%88+H4>Nu102EU04ObFzMEQf=j%k+w|IY zDW2)#zRR)(!@vZ@PrwP_Gw#VJ4Dezuv)Z20U7w8JxDXQOal{q&6Bq6a>r1O9#X=iH z=lYjELPj1l7SFy2(LtJ3&u)af01Y81=9|TzAHbsHv8ST#>InIU7v*_8bff*X;xgmS zZNt2m7ic$s<*cPFj}}QqB_)m-nXjdZ(rQb$-7fA)yYW(f!F2)0IC8+Y>97$U^Ym;f zXlp>}*x3%dmvhSOo=;PYDop4*^4VqZp^e&v>;6gUfERG*P>2iCDDzE{(@!(deyr5s z&wp*ITt=8pIeVQS#_xBMN}&yoSC$|!LV~bSbn4J0+r%%0$x% z)#mY6m6}QFD!;Ix4V(0?up{u^`{Q4w6>JKX6+g3L{Kx>JYRGn!s^mI>l$jn=^Qy*> zXC&JZX_&FmHVK?(Oh45=+n?mUr2qo-;9EYSZ1Y6s(1!ma2+)GMa2uB!Nx0NKhjlNo&`8>?OiyqJk)!;yUR0`)9^9DYfgSPt)#v?@q$> z>PSxsUIJ?DC7oA{PO^brlM$OKrOnWf-+EZeWYvJ&g;R~V;q2A7aT+vQv&m1Ui~Cti zUYH~c(vHHKeC9oi8GlvR)VCIXvGE_gSk~3Gh84)sqD1x%!Y?(bHnoQIspz<3bf|6# zp(H>Aicv6cQP=b9#|GHW))?OXXbLCi41^<_1JG9_3>oF))Za&T2N*oh*J}b6v}!UA z9nG7<;j~|m|D}8y?Rup}mS(0o{;-^Pa8T$#_LUd{&aK`Zs$h46F;9G*w#(~eMABq$ zG5}N5laQpPcr&ZL!HO9!8DY&JO3%I6+K|XW*a@h0gu^3zv9FUcrRtC^ zfL2wb`8(n?oHB3cS$W#h%|Y1Tn~Q>h;WSPax2ONgM<#auVzm2KyK_f#W^x_hk5d)! z!L55RSpE-=Fb`$ALnOC)q^1xE?TD0i(Exe8$I9{aqvvW1nwB~E7gduiY{B8#s=M4T z{mxDY@&{;`N`h^u7x}&_jxuGN+vJ4-Wd7<--o*uVO{|eIgpid3=p&jHosYg>y!P&f z!T|aGog?-?*FWafUIajv)?>}2(JeC}9cT9fU%rDpCVu>&c3whcg%#51RqD0J;7Hj( z`E;Mlh7+5va6`dba1;GH)~rBZbY<66m0(kFjO7iDa3G~K_a{mtvQ(3%l+QR2u&23# zc`V(d)u$~!lQ@4?f%nwJkn8&7hdIg2}V2(U-Pf>*4qN0b^44wq)SDziT&&tbq~kM)zjL%uvS6iC?WRd-kgM>w?T*r~86o+4&RvJC{X-m^Y(}2)0FzC!HGVZ^; z1p597lCF^>I7Xb#Sb#|Sv0@!R;?AmxW0GjxSd!Kxyl$nQYF@5f_tsdm5ptJC2=MtT%^ISfw`fIjLmd43s5L%jK?pE#z;8CXh^}I*u+rzY;lI_n@^U4&)g= zdJ;?a+EvGDG`lMvSg?9JwYvVH%#;SYE|&5S7r_wf~}VnRO^LBs}(kS;?Mm_}dS(hMpA5lN{st~$*o zw5hQ%pR?6HCUclw|GRJ9hCZ35%eq|g4L&kh5f3>Xj!N>Nhkr zG772#tD6x>b5ZI2IQ$aDGJl68tuZ`B%b3JH@?)cHio5Nwv15ttv{$bra#5G38uKgZ z%>lMX+-iUta2)G*jM$&p_i>n}AI*2AP>Q)q{N^R1mF0>va`@wx>=v(EUNy(!@Js(* z#P;EH@YZI{rRVZW0+)TTA_BwQcU);Xyd|ZTvfY)D;F5d4`S+03X+bvG2sJpjMfMDG zhB|=sf#2LkcTR3zGw|u8sItg2lf-LqziXjM=eL~)a8{k-fWxM3itaj0VNKXJ>u&Op z{Lgisokp2mo}IGEX>^d)RA`<83NnNq|-;XZ~xQA6ANeUvX%U9|7w z_v$%7#tcIe+@%uVOLsXgEaX5B{dX}S2;WODd>s@&2BV5GcjlRBj$j+45SR$&`KJ;A zQx}1kJlm9<6f_iO4KTI|5Ty%S2z}-mh_0x^DrVk;uvDnDG)iY#j|_|MVXQG3HG^3~ zP4nBOM|Df@tdF8k%l0gu$jixJZ9hnBIJpl)(P>pOo0*e+M^?=|Z9Ow%?DP7GCd!RyLt-;Le{I55nuA)-4;rpdR)5mZ#PJDG z^O|4V2$Bj9pqf)Z9Ac$sZe+q*+ z;o$>y!?DOVqT}nWPYYmTtSxX3Zo8w4`x{tLDt^~58ZA+e)RN9%SMYcgWj{VQc3$u@ zsF0dAYDREAW{CW#(LHZr#gO|4 z$hvL|^pI={1s#a}LS68x`5ig4T7Au8GaS=Hgr2^HDu1zT0U!7ucxu~7qj`Xay8bpv zhWLi!=$^!vvcF^BpaTD~tyuZF`Bq`U(80*|jL!22%=)QkJU>k?wZxfU#QuHF$_zPM z_^wIk24t5%BJ*ZH+J|rj24hxeFJ;__pk8dp^J z(<@dh!S|udKzkmaecsLCRzJ{yx?Y^LO!COhNN+vhV|4E7x6eDYPsrL$d)*^GWf9FW z@o<(n8@E2b7u+qLF)>eBG{ko7`8JYiS-*rLa5*^k+Tmg2a0`aFf8=Y~xzp$x=~lNx@QPTYEOuh4W4`SkERe^5-R4W#F#0C%&A=J!52G5(j_Klrt%c*u4gOI-S@ z%NqyoME=gVx|I7lRGT?JWTYo0GI5~SOcdC~o`0)QfHO1V-G^jzcJ^lPW3s{s^Q0@) zk*1iXq*&(6@*MO^U~n6tEm+>>jS6r5(Xw1e9;Xut)s0iXt}U7 zKoEB{8{)L+f+m321=b5$uxj4i+$hDS#3RW2)@*GFV+cWhhSUH(=zl}EFY$ff7nt6!sJKm|LiX zykiy%W8%LJYDuL*;D6}u=Dgp2aMaTuwv_m_2`aZFAe{Lob+Z<^I<)&$T?{$hh`?XOwp^I*5(WcHaIi=8H~-B{rv69)L^p0-Twk1 zofnCG?)h|`M~=Q`&>Gj5W@f3AS}0o8pe-n)bX49K+LE}&v#|r6_$;EoAm_IdarTwU sL}#_N)b}@>t9ZspLezyZNYJEln8#>29<1-(D)blRQH7{VN@NcCKR=6l4gdfE delta 4190 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 diff --git a/backend/web/static/assets/fontello/font/fontello.woff2 b/backend/web/static/assets/fontello/font/fontello.woff2 index 711cc9933c4fc8586cf01f367997ff1dce15a707..934d71eef867743efae724bdad67dcd12872804d 100644 GIT binary patch literal 5952 zcmV-G7r*FtPew8T0RR9102e?24*&oF04x{)02bx|0RR9100000000000000000000 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