43 changed files with 6603 additions and 0 deletions
+77
View File
@@ -49,3 +49,80 @@ Als Quelltext-Editor / IDE kommt VSCode zum Einsatz.
### DBeaver
Ist der Datenbank-Editor
## Technische Dokumentation
### 20.09.2026 Grundsätzliche technische Entscheidungen
#### Systeme:
- Programmiersprache : - GO
- Javascript
- SQL
- Datenbank: Postgresql
- Webtechnologie: HTMX
#### Grundlegende technische Entscheidungen
- Jedes relevante Objekt (z.B. Produkte) hat eine Darstellung als:
- Node (Raumdarstellung)
- Form (Darstellung des Objektes und Editiermöglichkeit) - List (Listen /Tabellensicht
- Alle Objekte werden in der API über ihre eindeutige ID angesprochen. Über die ID kann ich den Typ des Objektes herausfinden
- Objekte werden nur bei Bedarf aus der Datenbank geladen.
- Objekte werden nach dem Laden oder Anlegen gechached!
- Weboberflächen zur Pflege der Daten aber auch die Seiten zur Nutzung des CPQ müssen responsive sein!
- Nutzung des 12- Spalten loyouts!
- Alle Images haben einen Alternativen Text
- Struktur der Oberfläche und die Darstellung werden strikt getrennt (HTML + CSS)
- Die Entwicklung erfolgt über die Definition von Tickets
- Jedes Ticket verursacht ein Brauch und einen Merge!
### Open Source - Pakete
#### Go:
##### Viper
Viper dient zum Laden uns Auswerten von Config-Dateien. In diesem Case werden die HTTP-Servereinstellungen und die Datenbankverbindung ausgewertet.
````
go get github.com/spf13/viper
````
##### PostgreSQL
Die Datenbank des Systems ist in dem Datenbankmanagementsystem PostgreSQL abgelegt. Zum einen braucht es eine Installation des Systems, auf dem die Software Zugriff hat und zum anderen benötigt das System die entsprechenden PostgreSQL Treiber für Go.
````
go get github.com/lib/pq
````
##### Gin Gonic
Webserver Library zum Routing der API.
````
go get -u github.com/gin-gonic/gin
go get github.com/gin-contrib/cors
go get github.com/gin-contrib/sessions
````
##### Go Air
Go Air ist ein Live-Reload-Tool für Go-Anwendungen, das die Entwicklungsproduktivität erhöht.
````
go install github.com/air-verse/air@latest
export PATH="$PATH:$(go env GOPATH)/bin"
````
Den Export ggf. in der .bashrc oder .zshrc hinzufügen.
#### HTML Erweiterungen
ggf. später lokal runter laden ...
##### HTMX
HTMX ist eine JavaScript-Bibliothek, die es ermöglicht, HTML direkt über AJAX-Anfragen zu aktualisieren.
````
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
````
+8
View File
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}
+17
View File
@@ -0,0 +1,17 @@
# Database configuration
# Connection string is in Go pq driver format:
# host=<host> port=<port> user=<databaseUser>
# password=<databaseUserPassword> dbname=<databaseName>
[database]
connection_string = "host=192.168.178.50 port=5432 user=tsindt password=XD14ko8d dbname=xcpq sslmode=disable"
##connection_string = "host=localhost port=5432 user=tsindt password=XD14ko8d dbname=xcpq sslmode=disable"
driver_name = "postgres"
################################################################
# HTTP server configuration
[http]
server_address = ":8088"
################################################################
+23
View File
@@ -0,0 +1,23 @@
package main
import (
"log"
_ "github.com/lib/pq"
"SimplyCPQ2/cmd/server"
"SimplyCPQ2/internal/config"
)
func main() {
log.Println("Starting XCPQ Editor Service")
log.Println("Reading configuration")
config := config.InitConfig("config")
log.Println("Initializing database")
dbHandler := server.InitDatabase(config)
log.Println("Initializing HTTP server")
httpServer := server.InitHttpServer(config, dbHandler)
httpServer.Start()
log.Println("XCPQ Editor Service Stopped")
}
+26
View File
@@ -0,0 +1,26 @@
package server
import (
"log"
"database/sql"
"github.com/spf13/viper"
_ "github.com/lib/pq"
)
func InitDatabase(config *viper.Viper) *sql.DB {
connectionString := config.GetString("database.connection_string")
driverName := config.GetString("database.driver_name")
if connectionString == "" {
log.Fatalf("Database connection string is missing")
}
dbHandler, err := sql.Open(driverName, connectionString)
if err != nil {
log.Fatalf("Error while initializing database: %v", err)
}
err = dbHandler.Ping()
if err != nil {
dbHandler.Close()
log.Fatalf("Error while validating database: %v", err)
}
return dbHandler
}
+104
View File
@@ -0,0 +1,104 @@
package server
import (
handler "SimplyCPQ2/internal/handler"
"SimplyCPQ2/internal/repositories"
"SimplyCPQ2/internal/services"
"database/sql"
"log"
"net/http"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
)
type HttpServer struct {
config *viper.Viper
router *gin.Engine
dbHandler *sql.DB
importHandler *handler.ImportHandler
importRepository *repositories.ImportRepository
valueRepository *repositories.ValueRepository
propertyRepository *repositories.PropertyRepository
propertyTypeRepository *repositories.PropertyTypeRepository
propertyTypeGroupRepository *repositories.PropertyTypeGroupRepository
}
func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
// db initialization can be done here if needed
// repository initialisation:
valueRepository := repositories.NewValueRepository(dbHandler)
propertyRepository := repositories.NewPropertyRepository(dbHandler, valueRepository)
propertyTypeRepository := repositories.NewPropertyTypeRepository(dbHandler, propertyRepository)
propertyTypeGroupRepository := repositories.NewPropertyTypesGroupRepository(dbHandler, propertyTypeRepository)
importRepository := repositories.NewImportRepository(dbHandler, valueRepository, propertyTypeRepository, propertyTypeGroupRepository, propertyRepository)
// service initialisation:
importService := services.NewImportService(importRepository)
propertyTypesService := services.NewPropertyTypeService(propertyTypeRepository, propertyTypeGroupRepository)
// handler initialisation:
importHandler := handler.NewImportHandler(importService)
mainHandler := handler.NewMainHandler(propertyTypesService)
propertyTypeHandler := handler.NewPropertyTypeHandler(propertyTypesService)
// Service API
router := gin.Default()
// initialize templates
router.LoadHTMLGlob("../templates/**/*.html")
router.Use(cors.Default())
// static content
router.Static("/static", "../static")
router.GET("/", mainHandler.Home)
router.GET("/properties/rootnodes", propertyTypeHandler.GetRootPropertyTypeGroups)
//router.GET("/properties", handler.PropertiesHandler)
/* old routes
// properties
router.GET("/properties/:id/childs", PropertyTypeHandler.GetPropertyTypesGroupDirectChildsById)
*/
/*
router.GET("/products", handlers.ProductsHandler)
router.GET("/conditions", handlers.ConditionsHandler)
router.GET("/translations", handlers.TranslationsHandler)
*/
// import
router.POST("/importPropertyTypes", importHandler.ImportPropertyTypeGroups)
// test endpoint
router.GET("/test", Test)
// server
return HttpServer{
config: config,
router: router,
dbHandler: dbHandler,
importHandler: importHandler,
importRepository: importRepository,
valueRepository: valueRepository,
propertyRepository: propertyRepository,
propertyTypeRepository: propertyTypeRepository,
propertyTypeGroupRepository: propertyTypeGroupRepository,
}
}
func (hs HttpServer) Start() {
err := hs.router.Run(hs.config.GetString("http.server_address"))
if err != nil {
log.Fatalf("Error while starting HTTP server: %v", err)
}
}
func Test(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"message": "Test",
})
}
+1
View File
@@ -0,0 +1 @@
exit status 1
Binary file not shown.
+51
View File
@@ -0,0 +1,51 @@
module SimplyCPQ2
go 1.25.0
require (
github.com/gin-contrib/cors v1.7.8
github.com/gin-gonic/gin v1.12.0
github.com/lib/pq v1.12.3
github.com/spf13/viper v1.21.0
)
require (
github.com/bytedance/gopkg v0.1.4 // indirect
github.com/bytedance/sonic v1.15.2 // indirect
github.com/bytedance/sonic/loader v0.5.1 // indirect
github.com/cloudwego/base64x v0.1.7 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/gin-contrib/sse v1.1.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.30.3 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/goccy/go-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.4.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.23 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.60.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
go.mongodb.org/mongo-driver/v2 v2.8.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.29.0 // indirect
golang.org/x/crypto v0.55.0 // indirect
golang.org/x/net v0.57.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.41.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)
+124
View File
@@ -0,0 +1,124 @@
github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
github.com/bytedance/sonic v1.15.2 h1:90H+rcF/FwLXwfB1cudOLq/je83n683Utf4Cbp0xHCo=
github.com/bytedance/sonic v1.15.2/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA=
github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/cloudwego/base64x v0.1.7 h1:NppS+Fgzg5ovhn4NkUXaDT3x9jldgH5ToMCqzBSi2zI=
github.com/cloudwego/base64x v0.1.7/go.mod h1:Cu1PV9zfrSf7ET2tIbWbbEy7jO7HHJ13q4X2SQ8aWYg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/cors v1.7.8 h1:U0jjyXlWXMEx27hFE6hmdg/TOZviYgsOGGT+kLmUZrc=
github.com/gin-contrib/cors v1.7.8/go.mod h1:u3nLI2pP1IlJn7tbvL7iiubDO9quBZ8FXP9LxmqpsPI=
github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko=
github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s=
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJLJuaYTeAH0DYy8=
github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw=
github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/mattn/go-isatty v0.0.23 h1:cYwCQTQf3HB6xUC+BtyCLZNr7IzbOmoZbmssVNzSyiQ=
github.com/mattn/go-isatty v0.0.23/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY=
github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0=
github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
go.mongodb.org/mongo-driver/v2 v2.8.0 h1:CxWDGQYY8QQwNjAl/aq2sfWakdnWZynnqJ9F4DhHbP8=
go.mongodb.org/mongo-driver/v2 v2.8.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.29.0 h1:8sSET5wB0+exBm0FGmOtdHMqjlRdV2DRD3/IV6OZgho=
golang.org/x/arch v0.29.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+19
View File
@@ -0,0 +1,19 @@
package config
import (
"log"
"github.com/spf13/viper"
)
func InitConfig(fileName string) *viper.Viper {
config := viper.New()
config.SetConfigName(fileName)
config.AddConfigPath(".")
config.AddConfigPath("$HOME")
err := config.ReadInConfig()
if err != nil {
log.Fatal("Error while parsing configuration file! ", err)
}
return config
}
@@ -0,0 +1,21 @@
package handlers
import (
"SimplyCPQ2/internal/services"
"github.com/gin-gonic/gin"
)
type ImportHandler struct {
importService *services.Import_Service
}
func NewImportHandler(i *services.Import_Service) *ImportHandler {
return &ImportHandler{
importService: i,
}
}
func (h *ImportHandler) ImportPropertyTypeGroups(ctx *gin.Context) {
// Implement the logic to import property types groups here
}
+22
View File
@@ -0,0 +1,22 @@
package handlers
import (
"SimplyCPQ2/internal/services"
"github.com/gin-gonic/gin"
)
type MainHandler struct {
propertyTypeService *services.PropertyTypeService
}
func NewMainHandler(p *services.PropertyTypeService) *MainHandler {
return &MainHandler{
propertyTypeService: p,
}
}
func (h *MainHandler) Home(ctx *gin.Context) {
// Implement the logic for the main handler's home endpoint here
ctx.HTML(200, "index.html", nil)
}
@@ -0,0 +1,21 @@
package handlers
import (
"SimplyCPQ2/internal/services"
"github.com/gin-gonic/gin"
)
type PropertyTypeHandler struct {
propertyTypeService *services.PropertyTypeService
}
func NewPropertyTypeHandler(propertyTypeService *services.PropertyTypeService) *PropertyTypeHandler {
return &PropertyTypeHandler{
propertyTypeService: propertyTypeService,
}
}
func (h *PropertyTypeHandler) GetRootPropertyTypeGroups(ctx *gin.Context) {
// Implement the logic to get root property types groups here
}
+9
View File
@@ -0,0 +1,9 @@
package models
type Product struct {
Id int
Name string
Description string
ImageURL string
Properties []Property
}
@@ -0,0 +1,9 @@
package models
type ProductGroup struct {
Id int `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
ImageURL string `json:"ImageURL,omitempty"`
Properties []Property `json:"properties,omitempty"`
}
+13
View File
@@ -0,0 +1,13 @@
package models
type Property struct {
Id int `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
ImageURL string `json:"ImageURL,omitempty"`
//Property_Type *Property_Type `json:"property_type,omitempty"`
Parent_Property *Property `json:"parent_property,omitempty"`
Products_Group *ProductGroup `json:"products_group,omitempty"`
Product *Product `json:"products,omitempty"`
Values []Value `json:"values,omitempty"`
}
@@ -0,0 +1,9 @@
package models
type Property_Type struct {
Id int `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
ImageURL string `json:"ImageURL,omitempty"`
Property Property `json:"property"`
}
@@ -0,0 +1,10 @@
package models
type PropertyTypeGroup struct {
Id int `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
ImageURL string `json:"ImageURL,omitempty"`
PropertyTypes []Property_Type `json:"PropertyTypes,omitempty"`
PropertyTypeGroups []PropertyTypeGroup `json:"PropertyTypeGroups,omitempty"`
}
+7
View File
@@ -0,0 +1,7 @@
package models
type Value struct {
Id int `json:"id,omitempty"`
Value string `json:"value"`
ImageURL string `json:"ImageURL,omitempty"`
}
@@ -0,0 +1,23 @@
package repositories
import (
"database/sql"
)
type ImportRepository struct {
db *sql.DB
vr *ValueRepository
pt *PropertyTypeRepository
ptg *PropertyTypeGroupRepository
pr *PropertyRepository
}
func NewImportRepository(db *sql.DB, vr *ValueRepository, pt *PropertyTypeRepository, ptg *PropertyTypeGroupRepository, pr *PropertyRepository) *ImportRepository {
return &ImportRepository{
db: db,
vr: vr,
pt: pt,
ptg: ptg,
pr: pr,
}
}
@@ -0,0 +1,17 @@
package repositories
import (
"database/sql"
)
type PropertyRepository struct {
db *sql.DB
vr *ValueRepository
}
func NewPropertyRepository(db *sql.DB, valueRepository *ValueRepository) *PropertyRepository {
return &PropertyRepository{
db: db,
vr: valueRepository,
}
}
@@ -0,0 +1,17 @@
package repositories
import (
"database/sql"
)
type PropertyTypeGroupRepository struct {
db *sql.DB
PropertyTypeRepository *PropertyTypeRepository
}
func NewPropertyTypesGroupRepository(db *sql.DB, PropertyTypeRepository *PropertyTypeRepository) *PropertyTypeGroupRepository {
return &PropertyTypeGroupRepository{
db: db,
PropertyTypeRepository: PropertyTypeRepository,
}
}
@@ -0,0 +1,17 @@
package repositories
import (
"database/sql"
)
type PropertyTypeRepository struct {
db *sql.DB
pr *PropertyRepository
}
func NewPropertyTypeRepository(db *sql.DB, propertyRepository *PropertyRepository) *PropertyTypeRepository {
return &PropertyTypeRepository{
db: db,
pr: propertyRepository,
}
}
@@ -0,0 +1,15 @@
package repositories
import (
"database/sql"
)
type ValueRepository struct {
db *sql.DB
}
func NewValueRepository(db *sql.DB) *ValueRepository {
return &ValueRepository{
db: db,
}
}
@@ -0,0 +1,15 @@
package services
import (
"SimplyCPQ2/internal/repositories"
)
type Import_Service struct {
importRepository *repositories.ImportRepository
}
func NewImportService(importRepository *repositories.ImportRepository) *Import_Service {
return &Import_Service{
importRepository: importRepository,
}
}
@@ -0,0 +1,18 @@
package services
import (
"SimplyCPQ2/internal/repositories"
)
type PropertyTypeService struct {
// Add any dependencies or fields needed for the service here
PropertyTypes_Repository *repositories.PropertyTypeRepository
PropertyTypeGroups_Repository *repositories.PropertyTypeGroupRepository
}
func NewPropertyTypeService(propertyTypesRepo *repositories.PropertyTypeRepository, propertyTypesGroupsRepo *repositories.PropertyTypeGroupRepository) *PropertyTypeService {
return &PropertyTypeService{
PropertyTypes_Repository: propertyTypesRepo,
PropertyTypeGroups_Repository: propertyTypesGroupsRepo,
}
}
+168
View File
@@ -0,0 +1,168 @@
/** layout Main Bereich */
main {
padding: var(--main-content-padding);
margin: 16px;
height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding));
/* 32px für die Margen */
overflow-y: auto;
/* Scrollbar, wenn der Inhalt zu groß ist */
border: 1px solid var(--secondary-color);
border-radius: var(--box-border-radius);
}
nav {
height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding));
overflow-y: auto;
/* Scrollbar, wenn der Inhalt zu groß ist */
display: flex; /* Macht die Liste horizontal */
justify-content: flex-start; /* Elemente am Anfang ausrichten */
flex-direction: column; /* Elemente vertikal anordnen */
border: 1px solid var(--secondary-color);
border-radius: var(--box-border-radius);
margin-left: 16px;
@media (max-width: 768px) {
height: 100%;
}
padding: 5px;
background-color: var(--primary-color);
color: var(--secondary-font-color);
}
nav ul {
list-style-type: none; /* Entfernt die Standard-Aufzählungszeichen */
flex-wrap: wrap; /* Elemente umbrechen, wenn der Platz nicht ausreicht */
gap: 20px; /* Abstand zwischen den Listenelementen */
}
nav ul li a {
text-decoration: none; /* Entfernt die Unterstreichung */
color: var(--secondary-font-color); /* Setzt die Schriftfarbe */
}
nav ul li a:hover {
text-decoration: underline; /* Unterstreichung beim Überfahren mit der Maus */
font-weight: bold; /* Macht den Text fett */
}
.rootNode {
padding-top: 28px;
/* Einrückung für die Wurzelknoten */
color: var(--primary-color);
font-weight: bold;
}
.editor-container {
height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding) - 96px);
display: flex;
flex-direction: row;
/* Elemente horizontal anordnen */
gap: 16px;
/* Abstand zwischen den Elementen */
padding: 16px;
/* Innenabstand */
border-radius: var(--box-border-radius);
background-color: var(--data-background-color);
}
.editor-view {
margin-top: 8px;
padding: 8px;
border: 1px solid var(--primary-color);
border-radius: var(--box-border-radius);
}
/** tree components */
.node {
justify-content: center;
list-style-type: none;
/* Entfernt die Standard-Aufzählungszeichen */
padding-left: 20px;
/* Einrückung für die Unterlisten */
}
.node img {
height: 12px;
/* Höhe des Bildes */
margin-right: 2px;
/* Abstand zwischen Bild und Text */
}
.leaf {
padding-left: 28px;
/* Einrückung für Blätter */
color: var(--primary-color);
font-weight: lighter;
}
/* form styles */
.cform {
display: flex;
flex-direction: column;
color: var(--primary-color);
gap: 8px;
padding: 16px;
}
.cform label {
padding-top: 8px;
}
.cform input[type="text"],
.cform textarea {
padding: 4px;
border: 1px solid var(--primary-color);
border-radius: var(--box-border-radius);
}
/* Style für allgemeine Elemente */
.box {
border: 1px solid var(--primary-color);
border-radius: var(--box-border-radius);
}
.button_row {
display: flex;
flex-direction: row;
justify-content: flex-end;
gap: 8px;
margin-top: 8px;
}
.button_row button {
padding: 4px 8px;
border: 1px solid var(--primary-color);
border-radius: var(--box-border-radius);
background-color: var(--data-background-color);
cursor: pointer;
display: inline-flex;
justify-content: center;
}
.mt-16 {
margin-top: 16px;
}
/* Table styles */
table {
margin: 16px;
width: 80%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid var(--primary-color);
}
th, td {
padding: 8px;
text-align: left;
}
td {
background-color: var(--data-background-color);
}
th {
color: var(--primary-color);
font-weight: 500;
}
+24
View File
@@ -0,0 +1,24 @@
/** footer styles */
footer {
height: var(--footer-height);
background-color: var(--primary-color);
border: 1px solid var(--secondary-color);
border-radius: var(--box-border-radius);
color: var(--secondary-font-color);
margin: 16px;
@media (max-width: 768px) {
padding: 0px; /* Adjust the padding for smaller screens */
margin: 8px; /* Adjust the margin for smaller screens */
}
}
footer a {
text-decoration: none; /* Entfernt die Unterstreichung */
color: var(--secondary-font-color); /* Setzt die Schriftfarbe */
}
footer a:hover {
text-decoration: underline; /* Unterstreichung beim Überfahren mit der Maus */
font-weight: bold; /* Macht den Text fett */
}
+95
View File
@@ -0,0 +1,95 @@
/** global styles */
/* globale Variablen */
:root {
/* colors */
--primary-color: #1976D2;
--secondary-color: #d27519;
--font-color: #333333;
--secondary-font-color: #f3f5f4;
--background-color: #f3f5f4;
--highlight-color: #f0f0f0;
--error-color: #ff4d4f;
--success-color: #52c41a;
--data-background-color: #ffffff;
/* Dimensions */
--header-height: 64px;
--footer-height: 32px;
--main-content-padding: 20px;
--box-border-radius: 10px;
}
/* 1. Schriftart definieren */
@font-face {
font-family: 'Inter'; /* Name, den du später im CSS verwendest */
src: url('/static/fonts/Inter.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
// 12 Spalten Grid System
.row::after {
content: "";
clear: both;
display: table;
}
[class*="col-"] {
float: left;
padding: 15px;
}
/* Responsive Anpassungen Handy */
[class*="col-"] {
width: 100%;
}
/* Responsive Anpassungen Tablet */
@media screen and (min-width: 600px) {
.col-s-1 {width: 8.33%;}
.col-s-2 {width: 16.66%;}
.col-s-3 {width: 25%;}
.col-s-4 {width: 33.33%;}
.col-s-5 {width: 41.66%;}
.col-s-6 {width: 50%;}
.col-s-7 {width: 58.33%;}
.col-s-8 {width: 66.66%;}
.col-s-9 {width: 75%;}
.col-s-10 {width: 83.33%;}
.col-s-11 {width: 91.66%;}
.col-s-12 {width: 100%;}
}
/* Spaltenbreiten für 12 Spalten Grid */
@media screen and (min-width: 768px) {
.col-1 {width: 8.33%;}
.col-2 {width: 16.66%;}
.col-3 {width: 25%;}
.col-4 {width: 33.33%;}
.col-5 {width: 41.66%;}
.col-6 {width: 50%;}
.col-7 {width: 58.33%;}
.col-8 {width: 66.66%;}
.col-9 {width: 75%;}
.col-10 {width: 83.33%;}
.col-11 {width: 91.66%;}
.col-12 {width: 100%;}
}
/* 2. Schriftart anwenden und Ränder entfernen*/
body {
font-family: 'Inter', Arial, sans-serif;
background-color: var(--background-color);
color: var(--font-color);
}
+48
View File
@@ -0,0 +1,48 @@
/** Header and included nav styles */
/* Style für Header, Navigation, Main Content, Aside und Footer */
header {
display: flex;
justify-content: flex-start;
flex-direction: row;
@media (max-width: 768px) {
flex-direction: column;
justify-content: center;
align-items: center;
}
align-items: center;
height: var(--header-height);
background-color: var(--primary-color);
border: 1px solid var(--secondary-color);
border-radius: var(--box-border-radius);
color: var(--secondary-font-color);
margin: 16px;
padding: 10px;
}
header img {
height: calc(var(--header-height) - 5px); /* Adjust the image height to fit within the header */
margin-left: 10px; /* Space between the image and the header text */
padding-right: 16px; /* Space between the image and the header text */
}
header h1 {
font-weight: 600;
font-size: 2em; /* Adjust the font size as needed */
margin-left: 5px;
padding: 16px;
@media (max-width: 768px) {
font-size: 1em; /* Adjust the font size for smaller screens */
padding: 0px; /* Adjust the padding for smaller screens */
}
}
header p {
font-weight: 100;
margin-left: 16px;
padding-right: 16px;
}
Binary file not shown.
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 43 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1976D2"><path d="M280-280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h400q83 0 141.5 58.5T880-480q0 83-58.5 141.5T680-280H280Zm0-80h400q50 0 85-35t35-85q0-50-35-85t-85-35H280q-50 0-85 35t-35 85q0 50 35 85t85 35Zm42-28 142-142-42-42-100 100-40-40-42 42 82 82Zm158-92Z"/></svg>

After

Width:  |  Height:  |  Size: 378 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1976D2"><path d="M348.5-291.5Q360-303 360-320t-11.5-28.5Q337-360 320-360t-28.5 11.5Q280-337 280-320t11.5 28.5Q303-280 320-280t28.5-11.5Zm0-160Q360-463 360-480t-11.5-28.5Q337-520 320-520t-28.5 11.5Q280-497 280-480t11.5 28.5Q303-440 320-440t28.5-11.5Zm0-160Q360-623 360-640t-11.5-28.5Q337-680 320-680t-28.5 11.5Q280-657 280-640t11.5 28.5Q303-600 320-600t28.5-11.5ZM440-280h240v-80H440v80Zm0-160h240v-80H440v80Zm0-160h240v-80H440v80ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg>

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
+157
View File
@@ -0,0 +1,157 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/css/scpq_global.css">
<link rel="stylesheet" href="/static/css/scpq_header.css">
<link rel="stylesheet" href="/static/css/scpq_footer.css">
<link rel="stylesheet" href="/static/css/scpq_content.css">
<title>Simply CPQ Material Editor V2</title>
</head>
<body>
<header class="row">
<div class="col-8 col-s-12">
<h1>Simply CPQ Material Editor V2</h1>
</div>
</header>
<div class="row">
<nav class="col-2 col-s-12">
<ul>
<li>
<ul>
<details closed>
<summary>
Eigenschaften
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Produkte
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Regeln
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Preiskalkulation
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Übersetzungen
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
</ul>
</nav>
<main>
<div class="col-6 col-s-6">
<h3>Property-Type Group </h3>
<section class="editor-view">
<section id="PropertyTypeGroupData">
<form class="cform" method="post" action="/updatePropertyTypeGroup">
<label for="propertyTypeGroupID">ID:</label>
<input type="text" id="propertyTypeGroupID" name="propertyTypeGroupID" value="{PropertyTypeGroupID}" disabled>
<label for="propertyTypeGroupName">Name:</label>
<input type="text" id="propertyTypeGroupName" name="propertyTypeGroupName" value="{PropertyTypeGroupName}">
<label for="propertyTypeGroupDescription">Beschreibung:</label>
<textarea id="propertyTypeGroupDescription" name="propertyTypeGroupDescription">{PropertyTypeGroupDescription}</textarea>
<div class="button_row">
<button type="submit">Speichern</button>
<button type="submit">Neu</button>
<button type="submit">Löschen</button>
</div>
</form>
</section>
</section>
</div>
<div class="col-6 col-s-12">
<div class="aside">
<h3>Values für {PropertyTypeName}</h3>
<section class="editor-view">
<section id="ValueData">
<table>
<tr>
<th>ID</th>
<th>Value</th>
<th>Description</th>
<th>Actions</th>
</tr>
<tr>
<td>1</td>
<td>Value 1</td>
<td>Description 1</td>
<td>
<div class="button_row">
<button type="button">Edit</button>
<button type="button">Delete</button>
</div>
</td>
</tr>
<tr>
<td>2</td>
<td>Value 2</td>
<td>Description 2</td>
<td>
<div class="button_row">
<button type="button">Edit</button>
<button type="button">Delete</button>
</div>
</td>
</tr>
</table>
</section>
</section>
</div>
</div>
</main>
</div> <!-- Closing the initial row div -->
<footer class="row">
<div class="col-12 col-s-12">
<h6>&copy; 2026 Simply CPQ - All rights reserved - contact: <a href="mailto:Thomas.Sindt@gmx.de">Thomas.Sindt@gmx.de</a></h6>
</div>
</footer> <!-- Closing the footer row div -->
</body>
</html>
+20
View File
@@ -0,0 +1,20 @@
# Use postgres/example user/password credentials
services:
db:
image: postgres
restart: always
# set shared memory limit when using docker compose
shm_size: 128mb
# or set shared memory limit when deploy via swarm stack
#volumes:
# - type: tmpfs
# target: /dev/shm
# tmpfs:
# size: 134217728 # 128*2^20 bytes = 128Mb
ports:
- 5432:5432
environment:
POSTGRES_USER: tsindt
POSTGRES_PASSWORD: XD14ko8d