mirror of
https://github.com/holos-run/holos.git
synced 2026-03-19 08:44:58 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47a5e237e0 | ||
|
|
1279e2351a | ||
|
|
adb8177026 | ||
|
|
4e8fa5abda | ||
|
|
6894f45b6c | ||
|
|
89d25be837 | ||
|
|
5b33e48552 | ||
|
|
79e8ab639a | ||
|
|
a0cc673736 | ||
|
|
d06ecfadc8 | ||
|
|
64a117b0c3 | ||
|
|
cf006be9cf | ||
|
|
45ad3d8e63 | ||
|
|
441c968c4f | ||
|
|
99f2763fdf | ||
|
|
1312395a11 | ||
|
|
615f147bcb | ||
|
|
d0ad3bfc69 | ||
|
|
fe58a33747 | ||
|
|
26e537e768 |
2
Makefile
2
Makefile
@@ -87,6 +87,8 @@ test: ## Run tests.
|
||||
|
||||
.PHONY: lint
|
||||
lint: ## Run linters.
|
||||
buf lint
|
||||
cd internal/frontend/holos && ng lint
|
||||
golangci-lint run
|
||||
|
||||
.PHONY: coverage
|
||||
|
||||
@@ -18,7 +18,3 @@ plugins:
|
||||
out: internal/frontend/holos/src/app/gen
|
||||
opt:
|
||||
- target=ts
|
||||
- plugin: connect-query
|
||||
out: internal/frontend/holos/src/app/gen
|
||||
opt:
|
||||
- target=ts
|
||||
|
||||
@@ -18,6 +18,7 @@ import "encoding/yaml"
|
||||
Issuer?: [Name=_]: #Issuer & {metadata: name: Name}
|
||||
Gateway?: [Name=_]: #Gateway & {metadata: name: Name}
|
||||
ConfigMap?: [Name=_]: #ConfigMap & {metadata: name: Name}
|
||||
ServiceAccount?: [Name=_]: #ServiceAccount & {metadata: name: Name}
|
||||
|
||||
Deployment?: [_]: #Deployment
|
||||
StatefulSet?: [_]: #StatefulSet
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package holos
|
||||
|
||||
let Namespace = "dev-holos"
|
||||
let Holos = "holos"
|
||||
|
||||
// spec represents the output provided to holos
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "dev-holos-app"
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
// OBJECTS represents the kubernetes api objects to manage.
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: Deployment: holos: {
|
||||
metadata: {
|
||||
name: Holos
|
||||
namespace: Namespace
|
||||
labels: app: Holos
|
||||
}
|
||||
spec: {
|
||||
selector: matchLabels: app: Holos
|
||||
template: metadata: labels: {
|
||||
app: Holos
|
||||
"sidecar.istio.io/inject": "true"
|
||||
}
|
||||
strategy: rollingUpdate: maxSurge: 1
|
||||
strategy: rollingUpdate: maxUnavailable: 0
|
||||
template: {
|
||||
spec: {
|
||||
serviceAccountName: Holos
|
||||
securityContext: seccompProfile: type: "RuntimeDefault"
|
||||
containers: [
|
||||
{
|
||||
name: Holos
|
||||
image: "271053619184.dkr.ecr.us-east-2.amazonaws.com/holos-run/holos-server/holos:0.73.1"
|
||||
imagePullPolicy: "Always"
|
||||
env: [
|
||||
{
|
||||
name: "TZ"
|
||||
value: "America/Los_Angeles"
|
||||
},
|
||||
{
|
||||
name: "DATABASE_URL"
|
||||
valueFrom: secretKeyRef: {
|
||||
key: "uri"
|
||||
name: "holos-pguser-holos"
|
||||
}
|
||||
},
|
||||
]
|
||||
ports: [
|
||||
{
|
||||
containerPort: 3000
|
||||
name: "http"
|
||||
protocol: "TCP"
|
||||
},
|
||||
]
|
||||
securityContext: capabilities: drop: ["ALL"]
|
||||
securityContext: allowPrivilegeEscalation: false
|
||||
securityContext: runAsNonRoot: true
|
||||
resources: limits: {
|
||||
cpu: "0.25"
|
||||
memory: "256Mi"
|
||||
}
|
||||
resources: requests: resources.limits
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package holos
|
||||
|
||||
let Namespace = "dev-holos"
|
||||
let Holos = "holos"
|
||||
|
||||
// spec represents the output provided to holos
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "dev-holos-infra"
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let Metadata = {
|
||||
name: Holos
|
||||
namespace: Namespace
|
||||
labels: app: Holos
|
||||
}
|
||||
|
||||
// OBJECTS represents the kubernetes api objects to manage.
|
||||
let OBJECTS = #APIObjects & {
|
||||
// Postgres
|
||||
// Deployment
|
||||
// VirtualService
|
||||
|
||||
apiObjects: ServiceAccount: holos: {
|
||||
metadata: Metadata
|
||||
imagePullSecrets: [{name: "kube-system-ecr-image-pull-creds"}]
|
||||
}
|
||||
|
||||
apiObjects: PostgresCluster: holos: {
|
||||
apiVersion: "postgres-operator.crunchydata.com/v1beta1"
|
||||
metadata: Metadata
|
||||
spec: {
|
||||
image: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.1-0"
|
||||
instances: [{
|
||||
affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: [{
|
||||
podAffinityTerm: {
|
||||
labelSelector: matchLabels: "postgres-operator.crunchydata.com/cluster": "holos"
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
}
|
||||
weight: 1
|
||||
}]
|
||||
dataVolumeClaimSpec: {
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources: requests: storage: "1Gi"
|
||||
}
|
||||
name: "db"
|
||||
replicas: 1
|
||||
}]
|
||||
port: 5432
|
||||
postgresVersion: 16
|
||||
users: [{
|
||||
databases: ["holos"]
|
||||
name: "holos"
|
||||
options: "SUPERUSER"
|
||||
}]
|
||||
backups: pgbackrest: {
|
||||
global: {
|
||||
"archive-async": "y"
|
||||
"archive-push-queue-max": "100MiB"
|
||||
"spool-path": "/pgdata/backups"
|
||||
}
|
||||
image: "registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.47-2"
|
||||
repos: [{
|
||||
name: "repo1"
|
||||
volume: volumeClaimSpec: {
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources: requests: storage: "1Gi"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apiObjects: Service: holos: {
|
||||
apiVersion: "v1"
|
||||
metadata: Metadata
|
||||
spec: {
|
||||
type: "ClusterIP"
|
||||
selector: app: "holos"
|
||||
ports: [{
|
||||
appProtocol: "http2"
|
||||
name: "http"
|
||||
port: 3000
|
||||
protocol: "TCP"
|
||||
targetPort: 3000
|
||||
}, {
|
||||
appProtocol: "http"
|
||||
name: "metrics"
|
||||
port: 9090
|
||||
protocol: "TCP"
|
||||
targetPort: 9090
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
apiObjects: VirtualService: holos: {
|
||||
apiVersion: "networking.istio.io/v1beta1"
|
||||
metadata: Metadata
|
||||
spec: {
|
||||
gateways: ["istio-ingress/default"]
|
||||
hosts: [
|
||||
"app.dev.holos.run",
|
||||
"app.dev.\(#ClusterName).holos.run",
|
||||
]
|
||||
http: [{
|
||||
match: [{
|
||||
uri: prefix: "/ui"
|
||||
}]
|
||||
name: "ui"
|
||||
route: [{
|
||||
destination: {
|
||||
host: "holos"
|
||||
port: number: 3000
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
name: "api"
|
||||
route: [{
|
||||
destination: {
|
||||
host: "holos"
|
||||
port: number: 3000
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
16
hack/setup/bare
Executable file
16
hack/setup/bare
Executable file
@@ -0,0 +1,16 @@
|
||||
#! /bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
TOPLEVEL="$(cd $(dirname "$0") && git rev-parse --show-toplevel)"
|
||||
|
||||
host="jeff.app.dev.k2.holos.run:443"
|
||||
|
||||
read -p "Reset all data in $host? " choice
|
||||
case "$choice" in
|
||||
y|Y) echo "proceeding...";;
|
||||
*) exit 1;;
|
||||
esac
|
||||
|
||||
|
||||
grpcurl -H "x-oidc-id-token: $(holos token)" $host holos.v1alpha1.SystemService.DropTables
|
||||
grpcurl -H "x-oidc-id-token: $(holos token)" $host holos.v1alpha1.SystemService.SeedDatabase
|
||||
@@ -3,5 +3,6 @@ USER root
|
||||
WORKDIR /app
|
||||
ADD bin bin
|
||||
RUN chown -R app: /app
|
||||
USER app
|
||||
# Kubernetes requires the user to be numeric
|
||||
USER 8192
|
||||
ENTRYPOINT bin/holos server
|
||||
|
||||
@@ -38,6 +38,10 @@ var (
|
||||
{Name: "updated_at", Type: field.TypeTime},
|
||||
{Name: "name", Type: field.TypeString},
|
||||
{Name: "display_name", Type: field.TypeString},
|
||||
{Name: "form", Type: field.TypeJSON, Nullable: true},
|
||||
{Name: "model", Type: field.TypeJSON, Nullable: true},
|
||||
{Name: "cue", Type: field.TypeBytes, Nullable: true},
|
||||
{Name: "cue_definition", Type: field.TypeString, Nullable: true},
|
||||
{Name: "creator_id", Type: field.TypeUUID},
|
||||
{Name: "org_id", Type: field.TypeUUID},
|
||||
}
|
||||
@@ -49,17 +53,24 @@ var (
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "platforms_users_creator",
|
||||
Columns: []*schema.Column{PlatformsColumns[5]},
|
||||
Columns: []*schema.Column{PlatformsColumns[9]},
|
||||
RefColumns: []*schema.Column{UsersColumns[0]},
|
||||
OnDelete: schema.NoAction,
|
||||
},
|
||||
{
|
||||
Symbol: "platforms_organizations_organization",
|
||||
Columns: []*schema.Column{PlatformsColumns[6]},
|
||||
Columns: []*schema.Column{PlatformsColumns[10]},
|
||||
RefColumns: []*schema.Column{OrganizationsColumns[0]},
|
||||
OnDelete: schema.NoAction,
|
||||
},
|
||||
},
|
||||
Indexes: []*schema.Index{
|
||||
{
|
||||
Name: "platform_org_id_name",
|
||||
Unique: true,
|
||||
Columns: []*schema.Column{PlatformsColumns[10], PlatformsColumns[3]},
|
||||
},
|
||||
},
|
||||
}
|
||||
// UsersColumns holds the columns for the "users" table.
|
||||
UsersColumns = []*schema.Column{
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/holos-run/holos/internal/ent/platform"
|
||||
"github.com/holos-run/holos/internal/ent/predicate"
|
||||
"github.com/holos-run/holos/internal/ent/user"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -812,6 +813,10 @@ type PlatformMutation struct {
|
||||
updated_at *time.Time
|
||||
name *string
|
||||
display_name *string
|
||||
form **holos.Form
|
||||
model **holos.Model
|
||||
cue *[]byte
|
||||
cue_definition *string
|
||||
clearedFields map[string]struct{}
|
||||
creator *uuid.UUID
|
||||
clearedcreator bool
|
||||
@@ -1142,6 +1147,202 @@ func (m *PlatformMutation) ResetCreatorID() {
|
||||
m.creator = nil
|
||||
}
|
||||
|
||||
// SetForm sets the "form" field.
|
||||
func (m *PlatformMutation) SetForm(h *holos.Form) {
|
||||
m.form = &h
|
||||
}
|
||||
|
||||
// Form returns the value of the "form" field in the mutation.
|
||||
func (m *PlatformMutation) Form() (r *holos.Form, exists bool) {
|
||||
v := m.form
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldForm returns the old "form" field's value of the Platform entity.
|
||||
// If the Platform object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *PlatformMutation) OldForm(ctx context.Context) (v *holos.Form, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldForm is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldForm requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldForm: %w", err)
|
||||
}
|
||||
return oldValue.Form, nil
|
||||
}
|
||||
|
||||
// ClearForm clears the value of the "form" field.
|
||||
func (m *PlatformMutation) ClearForm() {
|
||||
m.form = nil
|
||||
m.clearedFields[platform.FieldForm] = struct{}{}
|
||||
}
|
||||
|
||||
// FormCleared returns if the "form" field was cleared in this mutation.
|
||||
func (m *PlatformMutation) FormCleared() bool {
|
||||
_, ok := m.clearedFields[platform.FieldForm]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetForm resets all changes to the "form" field.
|
||||
func (m *PlatformMutation) ResetForm() {
|
||||
m.form = nil
|
||||
delete(m.clearedFields, platform.FieldForm)
|
||||
}
|
||||
|
||||
// SetModel sets the "model" field.
|
||||
func (m *PlatformMutation) SetModel(h *holos.Model) {
|
||||
m.model = &h
|
||||
}
|
||||
|
||||
// Model returns the value of the "model" field in the mutation.
|
||||
func (m *PlatformMutation) Model() (r *holos.Model, exists bool) {
|
||||
v := m.model
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldModel returns the old "model" field's value of the Platform entity.
|
||||
// If the Platform object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *PlatformMutation) OldModel(ctx context.Context) (v *holos.Model, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldModel is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldModel requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldModel: %w", err)
|
||||
}
|
||||
return oldValue.Model, nil
|
||||
}
|
||||
|
||||
// ClearModel clears the value of the "model" field.
|
||||
func (m *PlatformMutation) ClearModel() {
|
||||
m.model = nil
|
||||
m.clearedFields[platform.FieldModel] = struct{}{}
|
||||
}
|
||||
|
||||
// ModelCleared returns if the "model" field was cleared in this mutation.
|
||||
func (m *PlatformMutation) ModelCleared() bool {
|
||||
_, ok := m.clearedFields[platform.FieldModel]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetModel resets all changes to the "model" field.
|
||||
func (m *PlatformMutation) ResetModel() {
|
||||
m.model = nil
|
||||
delete(m.clearedFields, platform.FieldModel)
|
||||
}
|
||||
|
||||
// SetCue sets the "cue" field.
|
||||
func (m *PlatformMutation) SetCue(b []byte) {
|
||||
m.cue = &b
|
||||
}
|
||||
|
||||
// Cue returns the value of the "cue" field in the mutation.
|
||||
func (m *PlatformMutation) Cue() (r []byte, exists bool) {
|
||||
v := m.cue
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldCue returns the old "cue" field's value of the Platform entity.
|
||||
// If the Platform object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *PlatformMutation) OldCue(ctx context.Context) (v []byte, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldCue is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldCue requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldCue: %w", err)
|
||||
}
|
||||
return oldValue.Cue, nil
|
||||
}
|
||||
|
||||
// ClearCue clears the value of the "cue" field.
|
||||
func (m *PlatformMutation) ClearCue() {
|
||||
m.cue = nil
|
||||
m.clearedFields[platform.FieldCue] = struct{}{}
|
||||
}
|
||||
|
||||
// CueCleared returns if the "cue" field was cleared in this mutation.
|
||||
func (m *PlatformMutation) CueCleared() bool {
|
||||
_, ok := m.clearedFields[platform.FieldCue]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetCue resets all changes to the "cue" field.
|
||||
func (m *PlatformMutation) ResetCue() {
|
||||
m.cue = nil
|
||||
delete(m.clearedFields, platform.FieldCue)
|
||||
}
|
||||
|
||||
// SetCueDefinition sets the "cue_definition" field.
|
||||
func (m *PlatformMutation) SetCueDefinition(s string) {
|
||||
m.cue_definition = &s
|
||||
}
|
||||
|
||||
// CueDefinition returns the value of the "cue_definition" field in the mutation.
|
||||
func (m *PlatformMutation) CueDefinition() (r string, exists bool) {
|
||||
v := m.cue_definition
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldCueDefinition returns the old "cue_definition" field's value of the Platform entity.
|
||||
// If the Platform object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *PlatformMutation) OldCueDefinition(ctx context.Context) (v string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldCueDefinition is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldCueDefinition requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldCueDefinition: %w", err)
|
||||
}
|
||||
return oldValue.CueDefinition, nil
|
||||
}
|
||||
|
||||
// ClearCueDefinition clears the value of the "cue_definition" field.
|
||||
func (m *PlatformMutation) ClearCueDefinition() {
|
||||
m.cue_definition = nil
|
||||
m.clearedFields[platform.FieldCueDefinition] = struct{}{}
|
||||
}
|
||||
|
||||
// CueDefinitionCleared returns if the "cue_definition" field was cleared in this mutation.
|
||||
func (m *PlatformMutation) CueDefinitionCleared() bool {
|
||||
_, ok := m.clearedFields[platform.FieldCueDefinition]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetCueDefinition resets all changes to the "cue_definition" field.
|
||||
func (m *PlatformMutation) ResetCueDefinition() {
|
||||
m.cue_definition = nil
|
||||
delete(m.clearedFields, platform.FieldCueDefinition)
|
||||
}
|
||||
|
||||
// ClearCreator clears the "creator" edge to the User entity.
|
||||
func (m *PlatformMutation) ClearCreator() {
|
||||
m.clearedcreator = true
|
||||
@@ -1243,7 +1444,7 @@ func (m *PlatformMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *PlatformMutation) Fields() []string {
|
||||
fields := make([]string, 0, 6)
|
||||
fields := make([]string, 0, 10)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, platform.FieldCreatedAt)
|
||||
}
|
||||
@@ -1262,6 +1463,18 @@ func (m *PlatformMutation) Fields() []string {
|
||||
if m.creator != nil {
|
||||
fields = append(fields, platform.FieldCreatorID)
|
||||
}
|
||||
if m.form != nil {
|
||||
fields = append(fields, platform.FieldForm)
|
||||
}
|
||||
if m.model != nil {
|
||||
fields = append(fields, platform.FieldModel)
|
||||
}
|
||||
if m.cue != nil {
|
||||
fields = append(fields, platform.FieldCue)
|
||||
}
|
||||
if m.cue_definition != nil {
|
||||
fields = append(fields, platform.FieldCueDefinition)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -1282,6 +1495,14 @@ func (m *PlatformMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.DisplayName()
|
||||
case platform.FieldCreatorID:
|
||||
return m.CreatorID()
|
||||
case platform.FieldForm:
|
||||
return m.Form()
|
||||
case platform.FieldModel:
|
||||
return m.Model()
|
||||
case platform.FieldCue:
|
||||
return m.Cue()
|
||||
case platform.FieldCueDefinition:
|
||||
return m.CueDefinition()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -1303,6 +1524,14 @@ func (m *PlatformMutation) OldField(ctx context.Context, name string) (ent.Value
|
||||
return m.OldDisplayName(ctx)
|
||||
case platform.FieldCreatorID:
|
||||
return m.OldCreatorID(ctx)
|
||||
case platform.FieldForm:
|
||||
return m.OldForm(ctx)
|
||||
case platform.FieldModel:
|
||||
return m.OldModel(ctx)
|
||||
case platform.FieldCue:
|
||||
return m.OldCue(ctx)
|
||||
case platform.FieldCueDefinition:
|
||||
return m.OldCueDefinition(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown Platform field %s", name)
|
||||
}
|
||||
@@ -1354,6 +1583,34 @@ func (m *PlatformMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetCreatorID(v)
|
||||
return nil
|
||||
case platform.FieldForm:
|
||||
v, ok := value.(*holos.Form)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetForm(v)
|
||||
return nil
|
||||
case platform.FieldModel:
|
||||
v, ok := value.(*holos.Model)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetModel(v)
|
||||
return nil
|
||||
case platform.FieldCue:
|
||||
v, ok := value.([]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetCue(v)
|
||||
return nil
|
||||
case platform.FieldCueDefinition:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetCueDefinition(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Platform field %s", name)
|
||||
}
|
||||
@@ -1383,7 +1640,20 @@ func (m *PlatformMutation) AddField(name string, value ent.Value) error {
|
||||
// ClearedFields returns all nullable fields that were cleared during this
|
||||
// mutation.
|
||||
func (m *PlatformMutation) ClearedFields() []string {
|
||||
return nil
|
||||
var fields []string
|
||||
if m.FieldCleared(platform.FieldForm) {
|
||||
fields = append(fields, platform.FieldForm)
|
||||
}
|
||||
if m.FieldCleared(platform.FieldModel) {
|
||||
fields = append(fields, platform.FieldModel)
|
||||
}
|
||||
if m.FieldCleared(platform.FieldCue) {
|
||||
fields = append(fields, platform.FieldCue)
|
||||
}
|
||||
if m.FieldCleared(platform.FieldCueDefinition) {
|
||||
fields = append(fields, platform.FieldCueDefinition)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
// FieldCleared returns a boolean indicating if a field with the given name was
|
||||
@@ -1396,6 +1666,20 @@ func (m *PlatformMutation) FieldCleared(name string) bool {
|
||||
// ClearField clears the value of the field with the given name. It returns an
|
||||
// error if the field is not defined in the schema.
|
||||
func (m *PlatformMutation) ClearField(name string) error {
|
||||
switch name {
|
||||
case platform.FieldForm:
|
||||
m.ClearForm()
|
||||
return nil
|
||||
case platform.FieldModel:
|
||||
m.ClearModel()
|
||||
return nil
|
||||
case platform.FieldCue:
|
||||
m.ClearCue()
|
||||
return nil
|
||||
case platform.FieldCueDefinition:
|
||||
m.ClearCueDefinition()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Platform nullable field %s", name)
|
||||
}
|
||||
|
||||
@@ -1421,6 +1705,18 @@ func (m *PlatformMutation) ResetField(name string) error {
|
||||
case platform.FieldCreatorID:
|
||||
m.ResetCreatorID()
|
||||
return nil
|
||||
case platform.FieldForm:
|
||||
m.ResetForm()
|
||||
return nil
|
||||
case platform.FieldModel:
|
||||
m.ResetModel()
|
||||
return nil
|
||||
case platform.FieldCue:
|
||||
m.ResetCue()
|
||||
return nil
|
||||
case platform.FieldCueDefinition:
|
||||
m.ResetCueDefinition()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Platform field %s", name)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package ent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"github.com/holos-run/holos/internal/ent/organization"
|
||||
"github.com/holos-run/holos/internal/ent/platform"
|
||||
"github.com/holos-run/holos/internal/ent/user"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
)
|
||||
|
||||
// Platform is the model entity for the Platform schema.
|
||||
@@ -32,6 +34,14 @@ type Platform struct {
|
||||
DisplayName string `json:"display_name,omitempty"`
|
||||
// CreatorID holds the value of the "creator_id" field.
|
||||
CreatorID uuid.UUID `json:"creator_id,omitempty"`
|
||||
// JSON representation of FormlyFormConfig[] refer to https://github.com/holos-run/holos/issues/161
|
||||
Form *holos.Form `json:"form,omitempty"`
|
||||
// JSON representation of the form model which holds user input values refer to https://github.com/holos-run/holos/issues/161
|
||||
Model *holos.Model `json:"model,omitempty"`
|
||||
// CUE definition to vet the model against e.g. #PlatformConfig
|
||||
Cue []byte `json:"cue,omitempty"`
|
||||
// The definition name to vet config_values against config_cue e.g. '#PlatformSpec'
|
||||
CueDefinition string `json:"cue_definition,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the PlatformQuery when eager-loading is set.
|
||||
Edges PlatformEdges `json:"edges"`
|
||||
@@ -76,7 +86,9 @@ func (*Platform) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case platform.FieldName, platform.FieldDisplayName:
|
||||
case platform.FieldForm, platform.FieldModel, platform.FieldCue:
|
||||
values[i] = new([]byte)
|
||||
case platform.FieldName, platform.FieldDisplayName, platform.FieldCueDefinition:
|
||||
values[i] = new(sql.NullString)
|
||||
case platform.FieldCreatedAt, platform.FieldUpdatedAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
@@ -139,6 +151,34 @@ func (pl *Platform) assignValues(columns []string, values []any) error {
|
||||
} else if value != nil {
|
||||
pl.CreatorID = *value
|
||||
}
|
||||
case platform.FieldForm:
|
||||
if value, ok := values[i].(*[]byte); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field form", values[i])
|
||||
} else if value != nil && len(*value) > 0 {
|
||||
if err := json.Unmarshal(*value, &pl.Form); err != nil {
|
||||
return fmt.Errorf("unmarshal field form: %w", err)
|
||||
}
|
||||
}
|
||||
case platform.FieldModel:
|
||||
if value, ok := values[i].(*[]byte); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field model", values[i])
|
||||
} else if value != nil && len(*value) > 0 {
|
||||
if err := json.Unmarshal(*value, &pl.Model); err != nil {
|
||||
return fmt.Errorf("unmarshal field model: %w", err)
|
||||
}
|
||||
}
|
||||
case platform.FieldCue:
|
||||
if value, ok := values[i].(*[]byte); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field cue", values[i])
|
||||
} else if value != nil {
|
||||
pl.Cue = *value
|
||||
}
|
||||
case platform.FieldCueDefinition:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field cue_definition", values[i])
|
||||
} else if value.Valid {
|
||||
pl.CueDefinition = value.String
|
||||
}
|
||||
default:
|
||||
pl.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
@@ -202,6 +242,18 @@ func (pl *Platform) String() string {
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("creator_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", pl.CreatorID))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("form=")
|
||||
builder.WriteString(fmt.Sprintf("%v", pl.Form))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("model=")
|
||||
builder.WriteString(fmt.Sprintf("%v", pl.Model))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("cue=")
|
||||
builder.WriteString(fmt.Sprintf("%v", pl.Cue))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("cue_definition=")
|
||||
builder.WriteString(pl.CueDefinition)
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
@@ -27,6 +27,14 @@ const (
|
||||
FieldDisplayName = "display_name"
|
||||
// FieldCreatorID holds the string denoting the creator_id field in the database.
|
||||
FieldCreatorID = "creator_id"
|
||||
// FieldForm holds the string denoting the form field in the database.
|
||||
FieldForm = "form"
|
||||
// FieldModel holds the string denoting the model field in the database.
|
||||
FieldModel = "model"
|
||||
// FieldCue holds the string denoting the cue field in the database.
|
||||
FieldCue = "cue"
|
||||
// FieldCueDefinition holds the string denoting the cue_definition field in the database.
|
||||
FieldCueDefinition = "cue_definition"
|
||||
// EdgeCreator holds the string denoting the creator edge name in mutations.
|
||||
EdgeCreator = "creator"
|
||||
// EdgeOrganization holds the string denoting the organization edge name in mutations.
|
||||
@@ -58,6 +66,10 @@ var Columns = []string{
|
||||
FieldName,
|
||||
FieldDisplayName,
|
||||
FieldCreatorID,
|
||||
FieldForm,
|
||||
FieldModel,
|
||||
FieldCue,
|
||||
FieldCueDefinition,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
@@ -121,6 +133,11 @@ func ByCreatorID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCreatorID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCueDefinition orders the results by the cue_definition field.
|
||||
func ByCueDefinition(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCueDefinition, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCreatorField orders the results by creator field.
|
||||
func ByCreatorField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
|
||||
@@ -86,6 +86,16 @@ func CreatorID(v uuid.UUID) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldEQ(FieldCreatorID, v))
|
||||
}
|
||||
|
||||
// Cue applies equality check predicate on the "cue" field. It's identical to CueEQ.
|
||||
func Cue(v []byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldEQ(FieldCue, v))
|
||||
}
|
||||
|
||||
// CueDefinition applies equality check predicate on the "cue_definition" field. It's identical to CueDefinitionEQ.
|
||||
func CueDefinition(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldEQ(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldEQ(FieldCreatedAt, v))
|
||||
@@ -336,6 +346,151 @@ func CreatorIDNotIn(vs ...uuid.UUID) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNotIn(FieldCreatorID, vs...))
|
||||
}
|
||||
|
||||
// FormIsNil applies the IsNil predicate on the "form" field.
|
||||
func FormIsNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldIsNull(FieldForm))
|
||||
}
|
||||
|
||||
// FormNotNil applies the NotNil predicate on the "form" field.
|
||||
func FormNotNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNotNull(FieldForm))
|
||||
}
|
||||
|
||||
// ModelIsNil applies the IsNil predicate on the "model" field.
|
||||
func ModelIsNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldIsNull(FieldModel))
|
||||
}
|
||||
|
||||
// ModelNotNil applies the NotNil predicate on the "model" field.
|
||||
func ModelNotNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNotNull(FieldModel))
|
||||
}
|
||||
|
||||
// CueEQ applies the EQ predicate on the "cue" field.
|
||||
func CueEQ(v []byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldEQ(FieldCue, v))
|
||||
}
|
||||
|
||||
// CueNEQ applies the NEQ predicate on the "cue" field.
|
||||
func CueNEQ(v []byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNEQ(FieldCue, v))
|
||||
}
|
||||
|
||||
// CueIn applies the In predicate on the "cue" field.
|
||||
func CueIn(vs ...[]byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldIn(FieldCue, vs...))
|
||||
}
|
||||
|
||||
// CueNotIn applies the NotIn predicate on the "cue" field.
|
||||
func CueNotIn(vs ...[]byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNotIn(FieldCue, vs...))
|
||||
}
|
||||
|
||||
// CueGT applies the GT predicate on the "cue" field.
|
||||
func CueGT(v []byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldGT(FieldCue, v))
|
||||
}
|
||||
|
||||
// CueGTE applies the GTE predicate on the "cue" field.
|
||||
func CueGTE(v []byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldGTE(FieldCue, v))
|
||||
}
|
||||
|
||||
// CueLT applies the LT predicate on the "cue" field.
|
||||
func CueLT(v []byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldLT(FieldCue, v))
|
||||
}
|
||||
|
||||
// CueLTE applies the LTE predicate on the "cue" field.
|
||||
func CueLTE(v []byte) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldLTE(FieldCue, v))
|
||||
}
|
||||
|
||||
// CueIsNil applies the IsNil predicate on the "cue" field.
|
||||
func CueIsNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldIsNull(FieldCue))
|
||||
}
|
||||
|
||||
// CueNotNil applies the NotNil predicate on the "cue" field.
|
||||
func CueNotNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNotNull(FieldCue))
|
||||
}
|
||||
|
||||
// CueDefinitionEQ applies the EQ predicate on the "cue_definition" field.
|
||||
func CueDefinitionEQ(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldEQ(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionNEQ applies the NEQ predicate on the "cue_definition" field.
|
||||
func CueDefinitionNEQ(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNEQ(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionIn applies the In predicate on the "cue_definition" field.
|
||||
func CueDefinitionIn(vs ...string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldIn(FieldCueDefinition, vs...))
|
||||
}
|
||||
|
||||
// CueDefinitionNotIn applies the NotIn predicate on the "cue_definition" field.
|
||||
func CueDefinitionNotIn(vs ...string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNotIn(FieldCueDefinition, vs...))
|
||||
}
|
||||
|
||||
// CueDefinitionGT applies the GT predicate on the "cue_definition" field.
|
||||
func CueDefinitionGT(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldGT(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionGTE applies the GTE predicate on the "cue_definition" field.
|
||||
func CueDefinitionGTE(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldGTE(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionLT applies the LT predicate on the "cue_definition" field.
|
||||
func CueDefinitionLT(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldLT(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionLTE applies the LTE predicate on the "cue_definition" field.
|
||||
func CueDefinitionLTE(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldLTE(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionContains applies the Contains predicate on the "cue_definition" field.
|
||||
func CueDefinitionContains(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldContains(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionHasPrefix applies the HasPrefix predicate on the "cue_definition" field.
|
||||
func CueDefinitionHasPrefix(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldHasPrefix(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionHasSuffix applies the HasSuffix predicate on the "cue_definition" field.
|
||||
func CueDefinitionHasSuffix(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldHasSuffix(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionIsNil applies the IsNil predicate on the "cue_definition" field.
|
||||
func CueDefinitionIsNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldIsNull(FieldCueDefinition))
|
||||
}
|
||||
|
||||
// CueDefinitionNotNil applies the NotNil predicate on the "cue_definition" field.
|
||||
func CueDefinitionNotNil() predicate.Platform {
|
||||
return predicate.Platform(sql.FieldNotNull(FieldCueDefinition))
|
||||
}
|
||||
|
||||
// CueDefinitionEqualFold applies the EqualFold predicate on the "cue_definition" field.
|
||||
func CueDefinitionEqualFold(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldEqualFold(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// CueDefinitionContainsFold applies the ContainsFold predicate on the "cue_definition" field.
|
||||
func CueDefinitionContainsFold(v string) predicate.Platform {
|
||||
return predicate.Platform(sql.FieldContainsFold(FieldCueDefinition, v))
|
||||
}
|
||||
|
||||
// HasCreator applies the HasEdge predicate on the "creator" edge.
|
||||
func HasCreator() predicate.Platform {
|
||||
return predicate.Platform(func(s *sql.Selector) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/holos-run/holos/internal/ent/organization"
|
||||
"github.com/holos-run/holos/internal/ent/platform"
|
||||
"github.com/holos-run/holos/internal/ent/user"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
)
|
||||
|
||||
// PlatformCreate is the builder for creating a Platform entity.
|
||||
@@ -78,6 +79,38 @@ func (pc *PlatformCreate) SetCreatorID(u uuid.UUID) *PlatformCreate {
|
||||
return pc
|
||||
}
|
||||
|
||||
// SetForm sets the "form" field.
|
||||
func (pc *PlatformCreate) SetForm(h *holos.Form) *PlatformCreate {
|
||||
pc.mutation.SetForm(h)
|
||||
return pc
|
||||
}
|
||||
|
||||
// SetModel sets the "model" field.
|
||||
func (pc *PlatformCreate) SetModel(h *holos.Model) *PlatformCreate {
|
||||
pc.mutation.SetModel(h)
|
||||
return pc
|
||||
}
|
||||
|
||||
// SetCue sets the "cue" field.
|
||||
func (pc *PlatformCreate) SetCue(b []byte) *PlatformCreate {
|
||||
pc.mutation.SetCue(b)
|
||||
return pc
|
||||
}
|
||||
|
||||
// SetCueDefinition sets the "cue_definition" field.
|
||||
func (pc *PlatformCreate) SetCueDefinition(s string) *PlatformCreate {
|
||||
pc.mutation.SetCueDefinition(s)
|
||||
return pc
|
||||
}
|
||||
|
||||
// SetNillableCueDefinition sets the "cue_definition" field if the given value is not nil.
|
||||
func (pc *PlatformCreate) SetNillableCueDefinition(s *string) *PlatformCreate {
|
||||
if s != nil {
|
||||
pc.SetCueDefinition(*s)
|
||||
}
|
||||
return pc
|
||||
}
|
||||
|
||||
// SetID sets the "id" field.
|
||||
func (pc *PlatformCreate) SetID(u uuid.UUID) *PlatformCreate {
|
||||
pc.mutation.SetID(u)
|
||||
@@ -240,6 +273,22 @@ func (pc *PlatformCreate) createSpec() (*Platform, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(platform.FieldDisplayName, field.TypeString, value)
|
||||
_node.DisplayName = value
|
||||
}
|
||||
if value, ok := pc.mutation.Form(); ok {
|
||||
_spec.SetField(platform.FieldForm, field.TypeJSON, value)
|
||||
_node.Form = value
|
||||
}
|
||||
if value, ok := pc.mutation.Model(); ok {
|
||||
_spec.SetField(platform.FieldModel, field.TypeJSON, value)
|
||||
_node.Model = value
|
||||
}
|
||||
if value, ok := pc.mutation.Cue(); ok {
|
||||
_spec.SetField(platform.FieldCue, field.TypeBytes, value)
|
||||
_node.Cue = value
|
||||
}
|
||||
if value, ok := pc.mutation.CueDefinition(); ok {
|
||||
_spec.SetField(platform.FieldCueDefinition, field.TypeString, value)
|
||||
_node.CueDefinition = value
|
||||
}
|
||||
if nodes := pc.mutation.CreatorIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
@@ -386,6 +435,78 @@ func (u *PlatformUpsert) UpdateCreatorID() *PlatformUpsert {
|
||||
return u
|
||||
}
|
||||
|
||||
// SetForm sets the "form" field.
|
||||
func (u *PlatformUpsert) SetForm(v *holos.Form) *PlatformUpsert {
|
||||
u.Set(platform.FieldForm, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateForm sets the "form" field to the value that was provided on create.
|
||||
func (u *PlatformUpsert) UpdateForm() *PlatformUpsert {
|
||||
u.SetExcluded(platform.FieldForm)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearForm clears the value of the "form" field.
|
||||
func (u *PlatformUpsert) ClearForm() *PlatformUpsert {
|
||||
u.SetNull(platform.FieldForm)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetModel sets the "model" field.
|
||||
func (u *PlatformUpsert) SetModel(v *holos.Model) *PlatformUpsert {
|
||||
u.Set(platform.FieldModel, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateModel sets the "model" field to the value that was provided on create.
|
||||
func (u *PlatformUpsert) UpdateModel() *PlatformUpsert {
|
||||
u.SetExcluded(platform.FieldModel)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearModel clears the value of the "model" field.
|
||||
func (u *PlatformUpsert) ClearModel() *PlatformUpsert {
|
||||
u.SetNull(platform.FieldModel)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetCue sets the "cue" field.
|
||||
func (u *PlatformUpsert) SetCue(v []byte) *PlatformUpsert {
|
||||
u.Set(platform.FieldCue, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateCue sets the "cue" field to the value that was provided on create.
|
||||
func (u *PlatformUpsert) UpdateCue() *PlatformUpsert {
|
||||
u.SetExcluded(platform.FieldCue)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearCue clears the value of the "cue" field.
|
||||
func (u *PlatformUpsert) ClearCue() *PlatformUpsert {
|
||||
u.SetNull(platform.FieldCue)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetCueDefinition sets the "cue_definition" field.
|
||||
func (u *PlatformUpsert) SetCueDefinition(v string) *PlatformUpsert {
|
||||
u.Set(platform.FieldCueDefinition, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateCueDefinition sets the "cue_definition" field to the value that was provided on create.
|
||||
func (u *PlatformUpsert) UpdateCueDefinition() *PlatformUpsert {
|
||||
u.SetExcluded(platform.FieldCueDefinition)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearCueDefinition clears the value of the "cue_definition" field.
|
||||
func (u *PlatformUpsert) ClearCueDefinition() *PlatformUpsert {
|
||||
u.SetNull(platform.FieldCueDefinition)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
@@ -507,6 +628,90 @@ func (u *PlatformUpsertOne) UpdateCreatorID() *PlatformUpsertOne {
|
||||
})
|
||||
}
|
||||
|
||||
// SetForm sets the "form" field.
|
||||
func (u *PlatformUpsertOne) SetForm(v *holos.Form) *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetForm(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateForm sets the "form" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertOne) UpdateForm() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateForm()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearForm clears the value of the "form" field.
|
||||
func (u *PlatformUpsertOne) ClearForm() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearForm()
|
||||
})
|
||||
}
|
||||
|
||||
// SetModel sets the "model" field.
|
||||
func (u *PlatformUpsertOne) SetModel(v *holos.Model) *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetModel(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateModel sets the "model" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertOne) UpdateModel() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateModel()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearModel clears the value of the "model" field.
|
||||
func (u *PlatformUpsertOne) ClearModel() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearModel()
|
||||
})
|
||||
}
|
||||
|
||||
// SetCue sets the "cue" field.
|
||||
func (u *PlatformUpsertOne) SetCue(v []byte) *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetCue(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateCue sets the "cue" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertOne) UpdateCue() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateCue()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearCue clears the value of the "cue" field.
|
||||
func (u *PlatformUpsertOne) ClearCue() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearCue()
|
||||
})
|
||||
}
|
||||
|
||||
// SetCueDefinition sets the "cue_definition" field.
|
||||
func (u *PlatformUpsertOne) SetCueDefinition(v string) *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetCueDefinition(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateCueDefinition sets the "cue_definition" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertOne) UpdateCueDefinition() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateCueDefinition()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearCueDefinition clears the value of the "cue_definition" field.
|
||||
func (u *PlatformUpsertOne) ClearCueDefinition() *PlatformUpsertOne {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearCueDefinition()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *PlatformUpsertOne) Exec(ctx context.Context) error {
|
||||
if len(u.create.conflict) == 0 {
|
||||
@@ -795,6 +1000,90 @@ func (u *PlatformUpsertBulk) UpdateCreatorID() *PlatformUpsertBulk {
|
||||
})
|
||||
}
|
||||
|
||||
// SetForm sets the "form" field.
|
||||
func (u *PlatformUpsertBulk) SetForm(v *holos.Form) *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetForm(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateForm sets the "form" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertBulk) UpdateForm() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateForm()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearForm clears the value of the "form" field.
|
||||
func (u *PlatformUpsertBulk) ClearForm() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearForm()
|
||||
})
|
||||
}
|
||||
|
||||
// SetModel sets the "model" field.
|
||||
func (u *PlatformUpsertBulk) SetModel(v *holos.Model) *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetModel(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateModel sets the "model" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertBulk) UpdateModel() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateModel()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearModel clears the value of the "model" field.
|
||||
func (u *PlatformUpsertBulk) ClearModel() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearModel()
|
||||
})
|
||||
}
|
||||
|
||||
// SetCue sets the "cue" field.
|
||||
func (u *PlatformUpsertBulk) SetCue(v []byte) *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetCue(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateCue sets the "cue" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertBulk) UpdateCue() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateCue()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearCue clears the value of the "cue" field.
|
||||
func (u *PlatformUpsertBulk) ClearCue() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearCue()
|
||||
})
|
||||
}
|
||||
|
||||
// SetCueDefinition sets the "cue_definition" field.
|
||||
func (u *PlatformUpsertBulk) SetCueDefinition(v string) *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.SetCueDefinition(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateCueDefinition sets the "cue_definition" field to the value that was provided on create.
|
||||
func (u *PlatformUpsertBulk) UpdateCueDefinition() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.UpdateCueDefinition()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearCueDefinition clears the value of the "cue_definition" field.
|
||||
func (u *PlatformUpsertBulk) ClearCueDefinition() *PlatformUpsertBulk {
|
||||
return u.Update(func(s *PlatformUpsert) {
|
||||
s.ClearCueDefinition()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *PlatformUpsertBulk) Exec(ctx context.Context) error {
|
||||
if u.create.err != nil {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/holos-run/holos/internal/ent/platform"
|
||||
"github.com/holos-run/holos/internal/ent/predicate"
|
||||
"github.com/holos-run/holos/internal/ent/user"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
)
|
||||
|
||||
// PlatformUpdate is the builder for updating Platform entities.
|
||||
@@ -93,6 +94,62 @@ func (pu *PlatformUpdate) SetNillableCreatorID(u *uuid.UUID) *PlatformUpdate {
|
||||
return pu
|
||||
}
|
||||
|
||||
// SetForm sets the "form" field.
|
||||
func (pu *PlatformUpdate) SetForm(h *holos.Form) *PlatformUpdate {
|
||||
pu.mutation.SetForm(h)
|
||||
return pu
|
||||
}
|
||||
|
||||
// ClearForm clears the value of the "form" field.
|
||||
func (pu *PlatformUpdate) ClearForm() *PlatformUpdate {
|
||||
pu.mutation.ClearForm()
|
||||
return pu
|
||||
}
|
||||
|
||||
// SetModel sets the "model" field.
|
||||
func (pu *PlatformUpdate) SetModel(h *holos.Model) *PlatformUpdate {
|
||||
pu.mutation.SetModel(h)
|
||||
return pu
|
||||
}
|
||||
|
||||
// ClearModel clears the value of the "model" field.
|
||||
func (pu *PlatformUpdate) ClearModel() *PlatformUpdate {
|
||||
pu.mutation.ClearModel()
|
||||
return pu
|
||||
}
|
||||
|
||||
// SetCue sets the "cue" field.
|
||||
func (pu *PlatformUpdate) SetCue(b []byte) *PlatformUpdate {
|
||||
pu.mutation.SetCue(b)
|
||||
return pu
|
||||
}
|
||||
|
||||
// ClearCue clears the value of the "cue" field.
|
||||
func (pu *PlatformUpdate) ClearCue() *PlatformUpdate {
|
||||
pu.mutation.ClearCue()
|
||||
return pu
|
||||
}
|
||||
|
||||
// SetCueDefinition sets the "cue_definition" field.
|
||||
func (pu *PlatformUpdate) SetCueDefinition(s string) *PlatformUpdate {
|
||||
pu.mutation.SetCueDefinition(s)
|
||||
return pu
|
||||
}
|
||||
|
||||
// SetNillableCueDefinition sets the "cue_definition" field if the given value is not nil.
|
||||
func (pu *PlatformUpdate) SetNillableCueDefinition(s *string) *PlatformUpdate {
|
||||
if s != nil {
|
||||
pu.SetCueDefinition(*s)
|
||||
}
|
||||
return pu
|
||||
}
|
||||
|
||||
// ClearCueDefinition clears the value of the "cue_definition" field.
|
||||
func (pu *PlatformUpdate) ClearCueDefinition() *PlatformUpdate {
|
||||
pu.mutation.ClearCueDefinition()
|
||||
return pu
|
||||
}
|
||||
|
||||
// SetCreator sets the "creator" edge to the User entity.
|
||||
func (pu *PlatformUpdate) SetCreator(u *User) *PlatformUpdate {
|
||||
return pu.SetCreatorID(u.ID)
|
||||
@@ -199,6 +256,30 @@ func (pu *PlatformUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if value, ok := pu.mutation.DisplayName(); ok {
|
||||
_spec.SetField(platform.FieldDisplayName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := pu.mutation.Form(); ok {
|
||||
_spec.SetField(platform.FieldForm, field.TypeJSON, value)
|
||||
}
|
||||
if pu.mutation.FormCleared() {
|
||||
_spec.ClearField(platform.FieldForm, field.TypeJSON)
|
||||
}
|
||||
if value, ok := pu.mutation.Model(); ok {
|
||||
_spec.SetField(platform.FieldModel, field.TypeJSON, value)
|
||||
}
|
||||
if pu.mutation.ModelCleared() {
|
||||
_spec.ClearField(platform.FieldModel, field.TypeJSON)
|
||||
}
|
||||
if value, ok := pu.mutation.Cue(); ok {
|
||||
_spec.SetField(platform.FieldCue, field.TypeBytes, value)
|
||||
}
|
||||
if pu.mutation.CueCleared() {
|
||||
_spec.ClearField(platform.FieldCue, field.TypeBytes)
|
||||
}
|
||||
if value, ok := pu.mutation.CueDefinition(); ok {
|
||||
_spec.SetField(platform.FieldCueDefinition, field.TypeString, value)
|
||||
}
|
||||
if pu.mutation.CueDefinitionCleared() {
|
||||
_spec.ClearField(platform.FieldCueDefinition, field.TypeString)
|
||||
}
|
||||
if pu.mutation.CreatorCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
@@ -339,6 +420,62 @@ func (puo *PlatformUpdateOne) SetNillableCreatorID(u *uuid.UUID) *PlatformUpdate
|
||||
return puo
|
||||
}
|
||||
|
||||
// SetForm sets the "form" field.
|
||||
func (puo *PlatformUpdateOne) SetForm(h *holos.Form) *PlatformUpdateOne {
|
||||
puo.mutation.SetForm(h)
|
||||
return puo
|
||||
}
|
||||
|
||||
// ClearForm clears the value of the "form" field.
|
||||
func (puo *PlatformUpdateOne) ClearForm() *PlatformUpdateOne {
|
||||
puo.mutation.ClearForm()
|
||||
return puo
|
||||
}
|
||||
|
||||
// SetModel sets the "model" field.
|
||||
func (puo *PlatformUpdateOne) SetModel(h *holos.Model) *PlatformUpdateOne {
|
||||
puo.mutation.SetModel(h)
|
||||
return puo
|
||||
}
|
||||
|
||||
// ClearModel clears the value of the "model" field.
|
||||
func (puo *PlatformUpdateOne) ClearModel() *PlatformUpdateOne {
|
||||
puo.mutation.ClearModel()
|
||||
return puo
|
||||
}
|
||||
|
||||
// SetCue sets the "cue" field.
|
||||
func (puo *PlatformUpdateOne) SetCue(b []byte) *PlatformUpdateOne {
|
||||
puo.mutation.SetCue(b)
|
||||
return puo
|
||||
}
|
||||
|
||||
// ClearCue clears the value of the "cue" field.
|
||||
func (puo *PlatformUpdateOne) ClearCue() *PlatformUpdateOne {
|
||||
puo.mutation.ClearCue()
|
||||
return puo
|
||||
}
|
||||
|
||||
// SetCueDefinition sets the "cue_definition" field.
|
||||
func (puo *PlatformUpdateOne) SetCueDefinition(s string) *PlatformUpdateOne {
|
||||
puo.mutation.SetCueDefinition(s)
|
||||
return puo
|
||||
}
|
||||
|
||||
// SetNillableCueDefinition sets the "cue_definition" field if the given value is not nil.
|
||||
func (puo *PlatformUpdateOne) SetNillableCueDefinition(s *string) *PlatformUpdateOne {
|
||||
if s != nil {
|
||||
puo.SetCueDefinition(*s)
|
||||
}
|
||||
return puo
|
||||
}
|
||||
|
||||
// ClearCueDefinition clears the value of the "cue_definition" field.
|
||||
func (puo *PlatformUpdateOne) ClearCueDefinition() *PlatformUpdateOne {
|
||||
puo.mutation.ClearCueDefinition()
|
||||
return puo
|
||||
}
|
||||
|
||||
// SetCreator sets the "creator" edge to the User entity.
|
||||
func (puo *PlatformUpdateOne) SetCreator(u *User) *PlatformUpdateOne {
|
||||
return puo.SetCreatorID(u.ID)
|
||||
@@ -475,6 +612,30 @@ func (puo *PlatformUpdateOne) sqlSave(ctx context.Context) (_node *Platform, err
|
||||
if value, ok := puo.mutation.DisplayName(); ok {
|
||||
_spec.SetField(platform.FieldDisplayName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := puo.mutation.Form(); ok {
|
||||
_spec.SetField(platform.FieldForm, field.TypeJSON, value)
|
||||
}
|
||||
if puo.mutation.FormCleared() {
|
||||
_spec.ClearField(platform.FieldForm, field.TypeJSON)
|
||||
}
|
||||
if value, ok := puo.mutation.Model(); ok {
|
||||
_spec.SetField(platform.FieldModel, field.TypeJSON, value)
|
||||
}
|
||||
if puo.mutation.ModelCleared() {
|
||||
_spec.ClearField(platform.FieldModel, field.TypeJSON)
|
||||
}
|
||||
if value, ok := puo.mutation.Cue(); ok {
|
||||
_spec.SetField(platform.FieldCue, field.TypeBytes, value)
|
||||
}
|
||||
if puo.mutation.CueCleared() {
|
||||
_spec.ClearField(platform.FieldCue, field.TypeBytes)
|
||||
}
|
||||
if value, ok := puo.mutation.CueDefinition(); ok {
|
||||
_spec.SetField(platform.FieldCueDefinition, field.TypeString, value)
|
||||
}
|
||||
if puo.mutation.CueDefinitionCleared() {
|
||||
_spec.ClearField(platform.FieldCueDefinition, field.TypeString)
|
||||
}
|
||||
if puo.mutation.CreatorCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/schema/edge"
|
||||
"entgo.io/ent/schema/field"
|
||||
"entgo.io/ent/schema/index"
|
||||
"github.com/gofrs/uuid"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
)
|
||||
|
||||
type Platform struct {
|
||||
@@ -24,6 +26,18 @@ func (Platform) Fields() []ent.Field {
|
||||
field.String("name").NotEmpty(),
|
||||
field.String("display_name"),
|
||||
field.UUID("creator_id", uuid.UUID{}),
|
||||
field.JSON("form", &holos.Form{}).
|
||||
Optional().
|
||||
Comment("JSON representation of FormlyFormConfig[] refer to https://github.com/holos-run/holos/issues/161"),
|
||||
field.JSON("model", &holos.Model{}).
|
||||
Optional().
|
||||
Comment("JSON representation of the form model which holds user input values refer to https://github.com/holos-run/holos/issues/161"),
|
||||
field.Bytes("cue").
|
||||
Optional().
|
||||
Comment("CUE definition to vet the model against e.g. #PlatformConfig"),
|
||||
field.String("cue_definition").
|
||||
Optional().
|
||||
Comment("The definition name to vet config_values against config_cue e.g. '#PlatformSpec'"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,3 +53,10 @@ func (Platform) Edges() []ent.Edge {
|
||||
Required(),
|
||||
}
|
||||
}
|
||||
|
||||
func (Platform) Indexes() []ent.Index {
|
||||
return []ent.Index{
|
||||
// One org cannot have two platforms with the same name.
|
||||
index.Fields("org_id", "name").Unique(),
|
||||
}
|
||||
}
|
||||
|
||||
47
internal/frontend/holos/.eslintrc.json
Normal file
47
internal/frontend/holos/.eslintrc.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"projects/**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "app",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "app",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended",
|
||||
"plugin:@angular-eslint/template/accessibility"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
3
internal/frontend/holos/.gitignore
vendored
3
internal/frontend/holos/.gitignore
vendored
@@ -40,3 +40,6 @@ testem.log
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# NX?
|
||||
/.nx/
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "1mb"
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
@@ -100,8 +100,22 @@
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"schematicCollections": [
|
||||
"@angular-eslint/schematics"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
2137
internal/frontend/holos/package-lock.json
generated
2137
internal/frontend/holos/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,8 @@
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
"test": "ng test",
|
||||
"lint": "ng lint"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
@@ -32,6 +33,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.3.4",
|
||||
"@angular-eslint/builder": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin-template": "17.3.0",
|
||||
"@angular-eslint/schematics": "17.3.0",
|
||||
"@angular-eslint/template-parser": "17.3.0",
|
||||
"@angular/cli": "^17.3.4",
|
||||
"@angular/compiler-cli": "^17.3.0",
|
||||
"@bufbuild/buf": "^1.31.0",
|
||||
@@ -40,6 +46,9 @@
|
||||
"@connectrpc/protoc-gen-connect-query": "^1.3.1",
|
||||
"@ngx-formly/schematics": "^6.3.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "7.2.0",
|
||||
"@typescript-eslint/parser": "7.2.0",
|
||||
"eslint": "^8.57.0",
|
||||
"jasmine-core": "~5.1.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
@@ -48,4 +57,4 @@
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.4.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
||||
import { FormlyModule } from '@ngx-formly/core';
|
||||
// import { provideHttpClient, withFetch } from '@angular/common/http';
|
||||
import { routes } from './app.routes';
|
||||
@@ -8,19 +8,24 @@ import { ConnectModule } from '../connect/connect.module';
|
||||
import { provideClient } from "../connect/client.provider";
|
||||
import { UserService } from './gen/holos/v1alpha1/user_connect';
|
||||
import { OrganizationService } from './gen/holos/v1alpha1/organization_connect';
|
||||
import { PlatformService } from './gen/holos/v1alpha1/platform_connect';
|
||||
import { HolosPanelWrapperComponent } from '../wrappers/holos-panel-wrapper/holos-panel-wrapper.component';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideRouter(routes),
|
||||
provideRouter(routes, withComponentInputBinding()),
|
||||
provideAnimationsAsync(),
|
||||
// provideHttpClient(withFetch()),
|
||||
provideClient(UserService),
|
||||
provideClient(OrganizationService),
|
||||
provideClient(PlatformService),
|
||||
importProvidersFrom(
|
||||
ConnectModule.forRoot({
|
||||
baseUrl: window.location.origin
|
||||
}),
|
||||
FormlyModule.forRoot(),
|
||||
FormlyModule.forRoot({
|
||||
wrappers: [{ name: 'holos-panel', component: HolosPanelWrapperComponent }],
|
||||
}),
|
||||
),
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { ClusterListComponent } from './cluster-list/cluster-list.component';
|
||||
import { ErrorNotFoundComponent } from './error-not-found/error-not-found.component';
|
||||
import { PlatformConfigComponent } from './views/platform-config/platform-config.component';
|
||||
import { AddressFormComponent } from './examples/address-form/address-form.component';
|
||||
import { PlatformsComponent } from './views/platforms/platforms.component'
|
||||
import { PlatformDetailComponent } from './views/platform-detail/platform-detail.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: 'platform-config', component: PlatformConfigComponent },
|
||||
{ path: 'address-form', component: AddressFormComponent },
|
||||
{ path: 'platform/:id', component: PlatformDetailComponent },
|
||||
{ path: 'platforms', component: PlatformsComponent },
|
||||
{ path: 'home', component: HomeComponent },
|
||||
{ path: 'clusters', component: ClusterListComponent },
|
||||
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
||||
{ path: '', redirectTo: '/platforms', pathMatch: 'full' },
|
||||
{ path: '**', component: ErrorNotFoundComponent },
|
||||
];
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<div class="grid-container">
|
||||
<h1 class="mat-h1">Clusters</h1>
|
||||
<mat-grid-list cols="2" rowHeight="350px">
|
||||
@for (card of cards | async; track card) {
|
||||
<mat-grid-tile [colspan]="card.cols" [rowspan]="card.rows">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
{{card.title}}
|
||||
<button mat-icon-button class="more-button" [matMenuTriggerFor]="menu" aria-label="Toggle menu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu" xPosition="before">
|
||||
<button mat-menu-item>Expand</button>
|
||||
<button mat-menu-item>Remove</button>
|
||||
</mat-menu>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div>Card Content Here</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
}
|
||||
</mat-grid-list>
|
||||
</div>
|
||||
@@ -1,21 +0,0 @@
|
||||
.grid-container {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.dashboard-card {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.dashboard-card-content {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { ClusterListComponent } from './cluster-list.component';
|
||||
|
||||
describe('ClusterListComponent', () => {
|
||||
let component: ClusterListComponent;
|
||||
let fixture: ComponentFixture<ClusterListComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopAnimationsModule]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ClusterListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should compile', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cluster-list',
|
||||
templateUrl: './cluster-list.component.html',
|
||||
styleUrl: './cluster-list.component.scss',
|
||||
standalone: true,
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
MatGridListModule,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatCardModule
|
||||
]
|
||||
})
|
||||
export class ClusterListComponent {
|
||||
private breakpointObserver = inject(BreakpointObserver);
|
||||
|
||||
/** Based on the screen size, switch from standard to one column per row */
|
||||
cards = this.breakpointObserver.observe(Breakpoints.Handset).pipe(
|
||||
map(({ matches }) => {
|
||||
if (matches) {
|
||||
return [
|
||||
{ title: 'Card 1', cols: 1, rows: 1 },
|
||||
{ title: 'Card 2', cols: 1, rows: 1 },
|
||||
{ title: 'Card 3', cols: 1, rows: 1 },
|
||||
{ title: 'Card 4', cols: 1, rows: 1 }
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
{ title: 'Card 1', cols: 2, rows: 1 },
|
||||
{ title: 'Card 2', cols: 1, rows: 1 },
|
||||
{ title: 'Card 3', cols: 1, rows: 2 },
|
||||
{ title: 'Card 4', cols: 1, rows: 1 }
|
||||
];
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<form [formGroup]="addressForm" novalidate (ngSubmit)="onSubmit()">
|
||||
<mat-card class="shipping-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Shipping Information</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mat-form-field class="full-width">
|
||||
<input matInput placeholder="Company" formControlName="company">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mat-form-field class="full-width">
|
||||
<input matInput placeholder="First name" formControlName="firstName">
|
||||
@if (addressForm.controls['firstName'].hasError('required')) {
|
||||
<mat-error>First name is <strong>required</strong></mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col">
|
||||
<mat-form-field class="full-width">
|
||||
<input matInput placeholder="Last name" formControlName="lastName">
|
||||
@if (addressForm.controls['lastName'].hasError('required')) {
|
||||
<mat-error>Last name is <strong>required</strong></mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mat-form-field class="full-width">
|
||||
<textarea matInput placeholder="Address" formControlName="address"></textarea>
|
||||
@if (addressForm.controls['address'].hasError('required')) {
|
||||
<mat-error>Address is <strong>required</strong></mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@if (hasUnitNumber) {
|
||||
<mat-form-field class="full-width">
|
||||
<textarea matInput placeholder="Address 2" formControlName="address2"></textarea>
|
||||
</mat-form-field>
|
||||
} @else {
|
||||
<button mat-button type="button" (click)="hasUnitNumber = !hasUnitNumber">
|
||||
+ Add C/O, Apt, Suite, Unit
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mat-form-field class="full-width">
|
||||
<input matInput placeholder="City" formControlName="city">
|
||||
@if (addressForm.controls['city'].hasError('required')) {
|
||||
<mat-error>City is <strong>required</strong></mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col">
|
||||
<mat-form-field class="full-width">
|
||||
<mat-select placeholder="State" formControlName="state">
|
||||
@for (state of states; track state) {
|
||||
<mat-option [value]="state.abbreviation">{{ state.name }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
@if (addressForm.controls['state'].hasError('required')) {
|
||||
<mat-error>State is <strong>required</strong></mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mat-form-field class="full-width">
|
||||
<input matInput #postalCode maxlength="5" placeholder="Postal Code" type="number" formControlName="postalCode">
|
||||
<mat-hint align="end">{{postalCode.value.length}} / 5</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mat-radio-group formControlName="shipping">
|
||||
<mat-radio-button value="free">Free Shipping</mat-radio-button>
|
||||
<mat-radio-button value="priority">Priority Shipping</mat-radio-button>
|
||||
<mat-radio-button value="nextday">Next Day Shipping</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" type="submit">Submit</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
||||
@@ -1,27 +0,0 @@
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.shipping-card {
|
||||
min-width: 120px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.mat-radio-button {
|
||||
display: block;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.col {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.col:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { AddressFormComponent } from './address-form.component';
|
||||
|
||||
describe('AddressFormComponent', () => {
|
||||
let component: AddressFormComponent;
|
||||
let fixture: ComponentFixture<AddressFormComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopAnimationsModule]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AddressFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should compile', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,108 +0,0 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
|
||||
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-address-form',
|
||||
templateUrl: './address-form.component.html',
|
||||
styleUrl: './address-form.component.scss',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
MatSelectModule,
|
||||
MatRadioModule,
|
||||
MatCardModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
})
|
||||
export class AddressFormComponent {
|
||||
private fb = inject(FormBuilder);
|
||||
addressForm = this.fb.group({
|
||||
company: null,
|
||||
firstName: [null, Validators.required],
|
||||
lastName: [null, Validators.required],
|
||||
address: [null, Validators.required],
|
||||
address2: null,
|
||||
city: [null, Validators.required],
|
||||
state: [null, Validators.required],
|
||||
postalCode: [null, Validators.compose([
|
||||
Validators.required, Validators.minLength(5), Validators.maxLength(5)])
|
||||
],
|
||||
shipping: ['free', Validators.required]
|
||||
});
|
||||
|
||||
hasUnitNumber = false;
|
||||
|
||||
states = [
|
||||
{name: 'Alabama', abbreviation: 'AL'},
|
||||
{name: 'Alaska', abbreviation: 'AK'},
|
||||
{name: 'American Samoa', abbreviation: 'AS'},
|
||||
{name: 'Arizona', abbreviation: 'AZ'},
|
||||
{name: 'Arkansas', abbreviation: 'AR'},
|
||||
{name: 'California', abbreviation: 'CA'},
|
||||
{name: 'Colorado', abbreviation: 'CO'},
|
||||
{name: 'Connecticut', abbreviation: 'CT'},
|
||||
{name: 'Delaware', abbreviation: 'DE'},
|
||||
{name: 'District Of Columbia', abbreviation: 'DC'},
|
||||
{name: 'Federated States Of Micronesia', abbreviation: 'FM'},
|
||||
{name: 'Florida', abbreviation: 'FL'},
|
||||
{name: 'Georgia', abbreviation: 'GA'},
|
||||
{name: 'Guam', abbreviation: 'GU'},
|
||||
{name: 'Hawaii', abbreviation: 'HI'},
|
||||
{name: 'Idaho', abbreviation: 'ID'},
|
||||
{name: 'Illinois', abbreviation: 'IL'},
|
||||
{name: 'Indiana', abbreviation: 'IN'},
|
||||
{name: 'Iowa', abbreviation: 'IA'},
|
||||
{name: 'Kansas', abbreviation: 'KS'},
|
||||
{name: 'Kentucky', abbreviation: 'KY'},
|
||||
{name: 'Louisiana', abbreviation: 'LA'},
|
||||
{name: 'Maine', abbreviation: 'ME'},
|
||||
{name: 'Marshall Islands', abbreviation: 'MH'},
|
||||
{name: 'Maryland', abbreviation: 'MD'},
|
||||
{name: 'Massachusetts', abbreviation: 'MA'},
|
||||
{name: 'Michigan', abbreviation: 'MI'},
|
||||
{name: 'Minnesota', abbreviation: 'MN'},
|
||||
{name: 'Mississippi', abbreviation: 'MS'},
|
||||
{name: 'Missouri', abbreviation: 'MO'},
|
||||
{name: 'Montana', abbreviation: 'MT'},
|
||||
{name: 'Nebraska', abbreviation: 'NE'},
|
||||
{name: 'Nevada', abbreviation: 'NV'},
|
||||
{name: 'New Hampshire', abbreviation: 'NH'},
|
||||
{name: 'New Jersey', abbreviation: 'NJ'},
|
||||
{name: 'New Mexico', abbreviation: 'NM'},
|
||||
{name: 'New York', abbreviation: 'NY'},
|
||||
{name: 'North Carolina', abbreviation: 'NC'},
|
||||
{name: 'North Dakota', abbreviation: 'ND'},
|
||||
{name: 'Northern Mariana Islands', abbreviation: 'MP'},
|
||||
{name: 'Ohio', abbreviation: 'OH'},
|
||||
{name: 'Oklahoma', abbreviation: 'OK'},
|
||||
{name: 'Oregon', abbreviation: 'OR'},
|
||||
{name: 'Palau', abbreviation: 'PW'},
|
||||
{name: 'Pennsylvania', abbreviation: 'PA'},
|
||||
{name: 'Puerto Rico', abbreviation: 'PR'},
|
||||
{name: 'Rhode Island', abbreviation: 'RI'},
|
||||
{name: 'South Carolina', abbreviation: 'SC'},
|
||||
{name: 'South Dakota', abbreviation: 'SD'},
|
||||
{name: 'Tennessee', abbreviation: 'TN'},
|
||||
{name: 'Texas', abbreviation: 'TX'},
|
||||
{name: 'Utah', abbreviation: 'UT'},
|
||||
{name: 'Vermont', abbreviation: 'VT'},
|
||||
{name: 'Virgin Islands', abbreviation: 'VI'},
|
||||
{name: 'Virginia', abbreviation: 'VA'},
|
||||
{name: 'Washington', abbreviation: 'WA'},
|
||||
{name: 'West Virginia', abbreviation: 'WV'},
|
||||
{name: 'Wisconsin', abbreviation: 'WI'},
|
||||
{name: 'Wyoming', abbreviation: 'WY'}
|
||||
];
|
||||
|
||||
onSubmit(): void {
|
||||
alert('Thanks!');
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// @generated by protoc-gen-connect-query v1.3.1 with parameter "target=ts"
|
||||
// @generated from file holos/v1alpha1/organization.proto (package holos.v1alpha1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { MethodKind } from "@bufbuild/protobuf";
|
||||
import { CreateCallerOrganizationRequest, GetCallerOrganizationsRequest, GetCallerOrganizationsResponse } from "./organization_pb.js";
|
||||
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.OrganizationService.GetCallerOrganizations
|
||||
*/
|
||||
export const getCallerOrganizations = {
|
||||
localName: "getCallerOrganizations",
|
||||
name: "GetCallerOrganizations",
|
||||
kind: MethodKind.Unary,
|
||||
I: GetCallerOrganizationsRequest,
|
||||
O: GetCallerOrganizationsResponse,
|
||||
service: {
|
||||
typeName: "holos.v1alpha1.OrganizationService"
|
||||
}
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.OrganizationService.CreateCallerOrganization
|
||||
*/
|
||||
export const createCallerOrganization = {
|
||||
localName: "createCallerOrganization",
|
||||
name: "CreateCallerOrganization",
|
||||
kind: MethodKind.Unary,
|
||||
I: CreateCallerOrganizationRequest,
|
||||
O: GetCallerOrganizationsResponse,
|
||||
service: {
|
||||
typeName: "holos.v1alpha1.OrganizationService"
|
||||
}
|
||||
} as const;
|
||||
@@ -3,7 +3,7 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { CreateCallerOrganizationRequest, GetCallerOrganizationsRequest, GetCallerOrganizationsResponse } from "./organization_pb.js";
|
||||
import { CreateCallerOrganizationRequest, CreateCallerOrganizationResponse, ListCallerOrganizationsRequest, ListCallerOrganizationsResponse } from "./organization_pb.js";
|
||||
import { MethodKind } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
@@ -13,12 +13,12 @@ export const OrganizationService = {
|
||||
typeName: "holos.v1alpha1.OrganizationService",
|
||||
methods: {
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.OrganizationService.GetCallerOrganizations
|
||||
* @generated from rpc holos.v1alpha1.OrganizationService.ListCallerOrganizations
|
||||
*/
|
||||
getCallerOrganizations: {
|
||||
name: "GetCallerOrganizations",
|
||||
I: GetCallerOrganizationsRequest,
|
||||
O: GetCallerOrganizationsResponse,
|
||||
listCallerOrganizations: {
|
||||
name: "ListCallerOrganizations",
|
||||
I: ListCallerOrganizationsRequest,
|
||||
O: ListCallerOrganizationsResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
@@ -27,7 +27,7 @@ export const OrganizationService = {
|
||||
createCallerOrganization: {
|
||||
name: "CreateCallerOrganization",
|
||||
I: CreateCallerOrganizationRequest,
|
||||
O: GetCallerOrganizationsResponse,
|
||||
O: CreateCallerOrganizationResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -72,40 +72,40 @@ export class Organization extends Message<Organization> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetCallerOrganizationsRequest
|
||||
* @generated from message holos.v1alpha1.ListCallerOrganizationsRequest
|
||||
*/
|
||||
export class GetCallerOrganizationsRequest extends Message<GetCallerOrganizationsRequest> {
|
||||
constructor(data?: PartialMessage<GetCallerOrganizationsRequest>) {
|
||||
export class ListCallerOrganizationsRequest extends Message<ListCallerOrganizationsRequest> {
|
||||
constructor(data?: PartialMessage<ListCallerOrganizationsRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetCallerOrganizationsRequest";
|
||||
static readonly typeName = "holos.v1alpha1.ListCallerOrganizationsRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetCallerOrganizationsRequest {
|
||||
return new GetCallerOrganizationsRequest().fromBinary(bytes, options);
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListCallerOrganizationsRequest {
|
||||
return new ListCallerOrganizationsRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetCallerOrganizationsRequest {
|
||||
return new GetCallerOrganizationsRequest().fromJson(jsonValue, options);
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListCallerOrganizationsRequest {
|
||||
return new ListCallerOrganizationsRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetCallerOrganizationsRequest {
|
||||
return new GetCallerOrganizationsRequest().fromJsonString(jsonString, options);
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListCallerOrganizationsRequest {
|
||||
return new ListCallerOrganizationsRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetCallerOrganizationsRequest | PlainMessage<GetCallerOrganizationsRequest> | undefined, b: GetCallerOrganizationsRequest | PlainMessage<GetCallerOrganizationsRequest> | undefined): boolean {
|
||||
return proto3.util.equals(GetCallerOrganizationsRequest, a, b);
|
||||
static equals(a: ListCallerOrganizationsRequest | PlainMessage<ListCallerOrganizationsRequest> | undefined, b: ListCallerOrganizationsRequest | PlainMessage<ListCallerOrganizationsRequest> | undefined): boolean {
|
||||
return proto3.util.equals(ListCallerOrganizationsRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetCallerOrganizationsResponse
|
||||
* @generated from message holos.v1alpha1.ListCallerOrganizationsResponse
|
||||
*/
|
||||
export class GetCallerOrganizationsResponse extends Message<GetCallerOrganizationsResponse> {
|
||||
export class ListCallerOrganizationsResponse extends Message<ListCallerOrganizationsResponse> {
|
||||
/**
|
||||
* @generated from field: holos.v1alpha1.User user = 1;
|
||||
*/
|
||||
@@ -116,32 +116,32 @@ export class GetCallerOrganizationsResponse extends Message<GetCallerOrganizatio
|
||||
*/
|
||||
organizations: Organization[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<GetCallerOrganizationsResponse>) {
|
||||
constructor(data?: PartialMessage<ListCallerOrganizationsResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetCallerOrganizationsResponse";
|
||||
static readonly typeName = "holos.v1alpha1.ListCallerOrganizationsResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "user", kind: "message", T: User },
|
||||
{ no: 2, name: "organizations", kind: "message", T: Organization, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetCallerOrganizationsResponse {
|
||||
return new GetCallerOrganizationsResponse().fromBinary(bytes, options);
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListCallerOrganizationsResponse {
|
||||
return new ListCallerOrganizationsResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetCallerOrganizationsResponse {
|
||||
return new GetCallerOrganizationsResponse().fromJson(jsonValue, options);
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListCallerOrganizationsResponse {
|
||||
return new ListCallerOrganizationsResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetCallerOrganizationsResponse {
|
||||
return new GetCallerOrganizationsResponse().fromJsonString(jsonString, options);
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListCallerOrganizationsResponse {
|
||||
return new ListCallerOrganizationsResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetCallerOrganizationsResponse | PlainMessage<GetCallerOrganizationsResponse> | undefined, b: GetCallerOrganizationsResponse | PlainMessage<GetCallerOrganizationsResponse> | undefined): boolean {
|
||||
return proto3.util.equals(GetCallerOrganizationsResponse, a, b);
|
||||
static equals(a: ListCallerOrganizationsResponse | PlainMessage<ListCallerOrganizationsResponse> | undefined, b: ListCallerOrganizationsResponse | PlainMessage<ListCallerOrganizationsResponse> | undefined): boolean {
|
||||
return proto3.util.equals(ListCallerOrganizationsResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,3 +176,46 @@ export class CreateCallerOrganizationRequest extends Message<CreateCallerOrganiz
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.CreateCallerOrganizationResponse
|
||||
*/
|
||||
export class CreateCallerOrganizationResponse extends Message<CreateCallerOrganizationResponse> {
|
||||
/**
|
||||
* @generated from field: holos.v1alpha1.User user = 1;
|
||||
*/
|
||||
user?: User;
|
||||
|
||||
/**
|
||||
* @generated from field: repeated holos.v1alpha1.Organization organizations = 2;
|
||||
*/
|
||||
organizations: Organization[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<CreateCallerOrganizationResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.CreateCallerOrganizationResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "user", kind: "message", T: User },
|
||||
{ no: 2, name: "organizations", kind: "message", T: Organization, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateCallerOrganizationResponse {
|
||||
return new CreateCallerOrganizationResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateCallerOrganizationResponse {
|
||||
return new CreateCallerOrganizationResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateCallerOrganizationResponse {
|
||||
return new CreateCallerOrganizationResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: CreateCallerOrganizationResponse | PlainMessage<CreateCallerOrganizationResponse> | undefined, b: CreateCallerOrganizationResponse | PlainMessage<CreateCallerOrganizationResponse> | undefined): boolean {
|
||||
return proto3.util.equals(CreateCallerOrganizationResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// @generated by protoc-gen-connect-query v1.3.1 with parameter "target=ts"
|
||||
// @generated from file holos/v1alpha1/platform.proto (package holos.v1alpha1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { MethodKind } from "@bufbuild/protobuf";
|
||||
import { AddPlatformRequest, GetPlatformsRequest, GetPlatformsResponse } from "./platform_pb.js";
|
||||
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.GetPlatforms
|
||||
*/
|
||||
export const getPlatforms = {
|
||||
localName: "getPlatforms",
|
||||
name: "GetPlatforms",
|
||||
kind: MethodKind.Unary,
|
||||
I: GetPlatformsRequest,
|
||||
O: GetPlatformsResponse,
|
||||
service: {
|
||||
typeName: "holos.v1alpha1.PlatformService"
|
||||
}
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.AddPlatform
|
||||
*/
|
||||
export const addPlatform = {
|
||||
localName: "addPlatform",
|
||||
name: "AddPlatform",
|
||||
kind: MethodKind.Unary,
|
||||
I: AddPlatformRequest,
|
||||
O: GetPlatformsResponse,
|
||||
service: {
|
||||
typeName: "holos.v1alpha1.PlatformService"
|
||||
}
|
||||
} as const;
|
||||
@@ -3,7 +3,7 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { AddPlatformRequest, GetPlatformsRequest, GetPlatformsResponse } from "./platform_pb.js";
|
||||
import { AddPlatformRequest, AddPlatformResponse, GetFormRequest, GetFormResponse, GetModelRequest, GetModelResponse, GetPlatformRequest, GetPlatformResponse, ListPlatformsRequest, ListPlatformsResponse, PutFormRequest, PutFormResponse, PutModelRequest, PutModelResponse } from "./platform_pb.js";
|
||||
import { MethodKind } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
@@ -12,22 +12,67 @@ import { MethodKind } from "@bufbuild/protobuf";
|
||||
export const PlatformService = {
|
||||
typeName: "holos.v1alpha1.PlatformService",
|
||||
methods: {
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.GetPlatforms
|
||||
*/
|
||||
getPlatforms: {
|
||||
name: "GetPlatforms",
|
||||
I: GetPlatformsRequest,
|
||||
O: GetPlatformsResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.AddPlatform
|
||||
*/
|
||||
addPlatform: {
|
||||
name: "AddPlatform",
|
||||
I: AddPlatformRequest,
|
||||
O: GetPlatformsResponse,
|
||||
O: AddPlatformResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.GetPlatform
|
||||
*/
|
||||
getPlatform: {
|
||||
name: "GetPlatform",
|
||||
I: GetPlatformRequest,
|
||||
O: GetPlatformResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.ListPlatforms
|
||||
*/
|
||||
listPlatforms: {
|
||||
name: "ListPlatforms",
|
||||
I: ListPlatformsRequest,
|
||||
O: ListPlatformsResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.GetForm
|
||||
*/
|
||||
getForm: {
|
||||
name: "GetForm",
|
||||
I: GetFormRequest,
|
||||
O: GetFormResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.PutForm
|
||||
*/
|
||||
putForm: {
|
||||
name: "PutForm",
|
||||
I: PutFormRequest,
|
||||
O: PutFormResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.GetModel
|
||||
*/
|
||||
getModel: {
|
||||
name: "GetModel",
|
||||
I: GetModelRequest,
|
||||
O: GetModelResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.PlatformService.PutModel
|
||||
*/
|
||||
putModel: {
|
||||
name: "PutModel",
|
||||
I: PutModelRequest,
|
||||
O: PutModelResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
|
||||
import { Message, proto3 } from "@bufbuild/protobuf";
|
||||
import { Timestamps } from "./timestamps_pb.js";
|
||||
import { Creator } from "./user_pb.js";
|
||||
import { Message, proto3, Struct } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.Platform
|
||||
@@ -20,24 +18,28 @@ export class Platform extends Message<Platform> {
|
||||
id = "";
|
||||
|
||||
/**
|
||||
* @generated from field: string name = 2;
|
||||
* Organization ID resource owner.
|
||||
*
|
||||
* @generated from field: string org_id = 2;
|
||||
*/
|
||||
orgId = "";
|
||||
|
||||
/**
|
||||
* name is the platform short name as a dns label.
|
||||
*
|
||||
* @generated from field: string name = 3;
|
||||
*/
|
||||
name = "";
|
||||
|
||||
/**
|
||||
* @generated from field: string display_name = 3;
|
||||
* @generated from field: string display_name = 4;
|
||||
*/
|
||||
displayName = "";
|
||||
|
||||
/**
|
||||
* @generated from field: holos.v1alpha1.Timestamps timestamps = 4;
|
||||
* @generated from field: holos.v1alpha1.PlatformSpec spec = 5;
|
||||
*/
|
||||
timestamps?: Timestamps;
|
||||
|
||||
/**
|
||||
* @generated from field: holos.v1alpha1.Creator creator = 5;
|
||||
*/
|
||||
creator?: Creator;
|
||||
spec?: PlatformSpec;
|
||||
|
||||
constructor(data?: PartialMessage<Platform>) {
|
||||
super();
|
||||
@@ -48,10 +50,10 @@ export class Platform extends Message<Platform> {
|
||||
static readonly typeName = "holos.v1alpha1.Platform";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 3, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 4, name: "timestamps", kind: "message", T: Timestamps },
|
||||
{ no: 5, name: "creator", kind: "message", T: Creator },
|
||||
{ no: 2, name: "org_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 3, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 4, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 5, name: "spec", kind: "message", T: PlatformSpec },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Platform {
|
||||
@@ -72,82 +74,197 @@ export class Platform extends Message<Platform> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetPlatformsRequest
|
||||
* @generated from message holos.v1alpha1.PlatformSpec
|
||||
*/
|
||||
export class GetPlatformsRequest extends Message<GetPlatformsRequest> {
|
||||
export class PlatformSpec extends Message<PlatformSpec> {
|
||||
/**
|
||||
* @generated from field: string org_id = 1;
|
||||
* model represents the user-defined and user-supplied form field values.
|
||||
*
|
||||
* @generated from field: google.protobuf.Struct model = 1;
|
||||
*/
|
||||
orgId = "";
|
||||
model?: Struct;
|
||||
|
||||
constructor(data?: PartialMessage<GetPlatformsRequest>) {
|
||||
constructor(data?: PartialMessage<PlatformSpec>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetPlatformsRequest";
|
||||
static readonly typeName = "holos.v1alpha1.PlatformSpec";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "org_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 1, name: "model", kind: "message", T: Struct },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetPlatformsRequest {
|
||||
return new GetPlatformsRequest().fromBinary(bytes, options);
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PlatformSpec {
|
||||
return new PlatformSpec().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetPlatformsRequest {
|
||||
return new GetPlatformsRequest().fromJson(jsonValue, options);
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PlatformSpec {
|
||||
return new PlatformSpec().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetPlatformsRequest {
|
||||
return new GetPlatformsRequest().fromJsonString(jsonString, options);
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PlatformSpec {
|
||||
return new PlatformSpec().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetPlatformsRequest | PlainMessage<GetPlatformsRequest> | undefined, b: GetPlatformsRequest | PlainMessage<GetPlatformsRequest> | undefined): boolean {
|
||||
return proto3.util.equals(GetPlatformsRequest, a, b);
|
||||
static equals(a: PlatformSpec | PlainMessage<PlatformSpec> | undefined, b: PlatformSpec | PlainMessage<PlatformSpec> | undefined): boolean {
|
||||
return proto3.util.equals(PlatformSpec, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetPlatformsResponse
|
||||
* Form represents the Formly input form.
|
||||
*
|
||||
* @generated from message holos.v1alpha1.Form
|
||||
*/
|
||||
export class GetPlatformsResponse extends Message<GetPlatformsResponse> {
|
||||
export class Form extends Message<Form> {
|
||||
/**
|
||||
* @generated from field: string org_id = 1;
|
||||
* fields represents FormlyFieldConfig[] encoded as a JSON array.
|
||||
*
|
||||
* @generated from field: repeated google.protobuf.Struct fields = 1;
|
||||
*/
|
||||
orgId = "";
|
||||
fields: Struct[] = [];
|
||||
|
||||
/**
|
||||
* @generated from field: repeated holos.v1alpha1.Platform platforms = 2;
|
||||
*/
|
||||
platforms: Platform[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<GetPlatformsResponse>) {
|
||||
constructor(data?: PartialMessage<Form>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetPlatformsResponse";
|
||||
static readonly typeName = "holos.v1alpha1.Form";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "org_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "platforms", kind: "message", T: Platform, repeated: true },
|
||||
{ no: 1, name: "fields", kind: "message", T: Struct, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetPlatformsResponse {
|
||||
return new GetPlatformsResponse().fromBinary(bytes, options);
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Form {
|
||||
return new Form().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetPlatformsResponse {
|
||||
return new GetPlatformsResponse().fromJson(jsonValue, options);
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Form {
|
||||
return new Form().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetPlatformsResponse {
|
||||
return new GetPlatformsResponse().fromJsonString(jsonString, options);
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Form {
|
||||
return new Form().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetPlatformsResponse | PlainMessage<GetPlatformsResponse> | undefined, b: GetPlatformsResponse | PlainMessage<GetPlatformsResponse> | undefined): boolean {
|
||||
return proto3.util.equals(GetPlatformsResponse, a, b);
|
||||
static equals(a: Form | PlainMessage<Form> | undefined, b: Form | PlainMessage<Form> | undefined): boolean {
|
||||
return proto3.util.equals(Form, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Model represents the values entered into the form, stored in the form's model
|
||||
* in the web app, and persisted into the backend database. The model is
|
||||
* ultimately intended as the input to platform rendering.
|
||||
*
|
||||
* @generated from message holos.v1alpha1.Model
|
||||
*/
|
||||
export class Model extends Message<Model> {
|
||||
/**
|
||||
* @generated from field: google.protobuf.Struct model = 1;
|
||||
*/
|
||||
model?: Struct;
|
||||
|
||||
constructor(data?: PartialMessage<Model>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.Model";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "model", kind: "message", T: Struct },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Model {
|
||||
return new Model().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Model {
|
||||
return new Model().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Model {
|
||||
return new Model().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: Model | PlainMessage<Model> | undefined, b: Model | PlainMessage<Model> | undefined): boolean {
|
||||
return proto3.util.equals(Model, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.ListPlatformsRequest
|
||||
*/
|
||||
export class ListPlatformsRequest extends Message<ListPlatformsRequest> {
|
||||
/**
|
||||
* @generated from field: string org_id = 1;
|
||||
*/
|
||||
orgId = "";
|
||||
|
||||
constructor(data?: PartialMessage<ListPlatformsRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.ListPlatformsRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "org_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListPlatformsRequest {
|
||||
return new ListPlatformsRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListPlatformsRequest {
|
||||
return new ListPlatformsRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListPlatformsRequest {
|
||||
return new ListPlatformsRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: ListPlatformsRequest | PlainMessage<ListPlatformsRequest> | undefined, b: ListPlatformsRequest | PlainMessage<ListPlatformsRequest> | undefined): boolean {
|
||||
return proto3.util.equals(ListPlatformsRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.ListPlatformsResponse
|
||||
*/
|
||||
export class ListPlatformsResponse extends Message<ListPlatformsResponse> {
|
||||
/**
|
||||
* @generated from field: repeated holos.v1alpha1.Platform platforms = 1;
|
||||
*/
|
||||
platforms: Platform[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<ListPlatformsResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.ListPlatformsResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platforms", kind: "message", T: Platform, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListPlatformsResponse {
|
||||
return new ListPlatformsResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListPlatformsResponse {
|
||||
return new ListPlatformsResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListPlatformsResponse {
|
||||
return new ListPlatformsResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: ListPlatformsResponse | PlainMessage<ListPlatformsResponse> | undefined, b: ListPlatformsResponse | PlainMessage<ListPlatformsResponse> | undefined): boolean {
|
||||
return proto3.util.equals(ListPlatformsResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,19 +273,9 @@ export class GetPlatformsResponse extends Message<GetPlatformsResponse> {
|
||||
*/
|
||||
export class AddPlatformRequest extends Message<AddPlatformRequest> {
|
||||
/**
|
||||
* @generated from field: string org_id = 1;
|
||||
* @generated from field: holos.v1alpha1.Platform platform = 1;
|
||||
*/
|
||||
orgId = "";
|
||||
|
||||
/**
|
||||
* @generated from field: string name = 2;
|
||||
*/
|
||||
name = "";
|
||||
|
||||
/**
|
||||
* @generated from field: string display_name = 3;
|
||||
*/
|
||||
displayName = "";
|
||||
platform?: Platform;
|
||||
|
||||
constructor(data?: PartialMessage<AddPlatformRequest>) {
|
||||
super();
|
||||
@@ -178,9 +285,7 @@ export class AddPlatformRequest extends Message<AddPlatformRequest> {
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.AddPlatformRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "org_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 3, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 1, name: "platform", kind: "message", T: Platform },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): AddPlatformRequest {
|
||||
@@ -200,3 +305,428 @@ export class AddPlatformRequest extends Message<AddPlatformRequest> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.AddPlatformResponse
|
||||
*/
|
||||
export class AddPlatformResponse extends Message<AddPlatformResponse> {
|
||||
/**
|
||||
* @generated from field: repeated holos.v1alpha1.Platform platforms = 1;
|
||||
*/
|
||||
platforms: Platform[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<AddPlatformResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.AddPlatformResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platforms", kind: "message", T: Platform, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): AddPlatformResponse {
|
||||
return new AddPlatformResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): AddPlatformResponse {
|
||||
return new AddPlatformResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): AddPlatformResponse {
|
||||
return new AddPlatformResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: AddPlatformResponse | PlainMessage<AddPlatformResponse> | undefined, b: AddPlatformResponse | PlainMessage<AddPlatformResponse> | undefined): boolean {
|
||||
return proto3.util.equals(AddPlatformResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetPlatformRequest
|
||||
*/
|
||||
export class GetPlatformRequest extends Message<GetPlatformRequest> {
|
||||
/**
|
||||
* @generated from field: string platform_id = 1;
|
||||
*/
|
||||
platformId = "";
|
||||
|
||||
constructor(data?: PartialMessage<GetPlatformRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetPlatformRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetPlatformRequest {
|
||||
return new GetPlatformRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetPlatformRequest {
|
||||
return new GetPlatformRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetPlatformRequest {
|
||||
return new GetPlatformRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetPlatformRequest | PlainMessage<GetPlatformRequest> | undefined, b: GetPlatformRequest | PlainMessage<GetPlatformRequest> | undefined): boolean {
|
||||
return proto3.util.equals(GetPlatformRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetPlatformResponse
|
||||
*/
|
||||
export class GetPlatformResponse extends Message<GetPlatformResponse> {
|
||||
/**
|
||||
* @generated from field: holos.v1alpha1.Platform platform = 1;
|
||||
*/
|
||||
platform?: Platform;
|
||||
|
||||
constructor(data?: PartialMessage<GetPlatformResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetPlatformResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platform", kind: "message", T: Platform },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetPlatformResponse {
|
||||
return new GetPlatformResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetPlatformResponse {
|
||||
return new GetPlatformResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetPlatformResponse {
|
||||
return new GetPlatformResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetPlatformResponse | PlainMessage<GetPlatformResponse> | undefined, b: GetPlatformResponse | PlainMessage<GetPlatformResponse> | undefined): boolean {
|
||||
return proto3.util.equals(GetPlatformResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetFormRequest
|
||||
*/
|
||||
export class GetFormRequest extends Message<GetFormRequest> {
|
||||
/**
|
||||
* @generated from field: string platform_id = 1;
|
||||
*/
|
||||
platformId = "";
|
||||
|
||||
constructor(data?: PartialMessage<GetFormRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetFormRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetFormRequest {
|
||||
return new GetFormRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetFormRequest {
|
||||
return new GetFormRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetFormRequest {
|
||||
return new GetFormRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetFormRequest | PlainMessage<GetFormRequest> | undefined, b: GetFormRequest | PlainMessage<GetFormRequest> | undefined): boolean {
|
||||
return proto3.util.equals(GetFormRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetFormResponse
|
||||
*/
|
||||
export class GetFormResponse extends Message<GetFormResponse> {
|
||||
/**
|
||||
* @generated from field: repeated google.protobuf.Struct fields = 1;
|
||||
*/
|
||||
fields: Struct[] = [];
|
||||
|
||||
/**
|
||||
* @generated from field: google.protobuf.Struct model = 2;
|
||||
*/
|
||||
model?: Struct;
|
||||
|
||||
constructor(data?: PartialMessage<GetFormResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetFormResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "fields", kind: "message", T: Struct, repeated: true },
|
||||
{ no: 2, name: "model", kind: "message", T: Struct },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetFormResponse {
|
||||
return new GetFormResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetFormResponse {
|
||||
return new GetFormResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetFormResponse {
|
||||
return new GetFormResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetFormResponse | PlainMessage<GetFormResponse> | undefined, b: GetFormResponse | PlainMessage<GetFormResponse> | undefined): boolean {
|
||||
return proto3.util.equals(GetFormResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetModelRequest
|
||||
*/
|
||||
export class GetModelRequest extends Message<GetModelRequest> {
|
||||
/**
|
||||
* @generated from field: string platform_id = 1;
|
||||
*/
|
||||
platformId = "";
|
||||
|
||||
constructor(data?: PartialMessage<GetModelRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetModelRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetModelRequest {
|
||||
return new GetModelRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetModelRequest {
|
||||
return new GetModelRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetModelRequest {
|
||||
return new GetModelRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetModelRequest | PlainMessage<GetModelRequest> | undefined, b: GetModelRequest | PlainMessage<GetModelRequest> | undefined): boolean {
|
||||
return proto3.util.equals(GetModelRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.GetModelResponse
|
||||
*/
|
||||
export class GetModelResponse extends Message<GetModelResponse> {
|
||||
/**
|
||||
* @generated from field: google.protobuf.Struct model = 1;
|
||||
*/
|
||||
model?: Struct;
|
||||
|
||||
constructor(data?: PartialMessage<GetModelResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.GetModelResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "model", kind: "message", T: Struct },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetModelResponse {
|
||||
return new GetModelResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetModelResponse {
|
||||
return new GetModelResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetModelResponse {
|
||||
return new GetModelResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetModelResponse | PlainMessage<GetModelResponse> | undefined, b: GetModelResponse | PlainMessage<GetModelResponse> | undefined): boolean {
|
||||
return proto3.util.equals(GetModelResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.PutModelRequest
|
||||
*/
|
||||
export class PutModelRequest extends Message<PutModelRequest> {
|
||||
/**
|
||||
* @generated from field: string platform_id = 1;
|
||||
*/
|
||||
platformId = "";
|
||||
|
||||
/**
|
||||
* @generated from field: google.protobuf.Struct model = 2;
|
||||
*/
|
||||
model?: Struct;
|
||||
|
||||
constructor(data?: PartialMessage<PutModelRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.PutModelRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "model", kind: "message", T: Struct },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutModelRequest {
|
||||
return new PutModelRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutModelRequest {
|
||||
return new PutModelRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutModelRequest {
|
||||
return new PutModelRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: PutModelRequest | PlainMessage<PutModelRequest> | undefined, b: PutModelRequest | PlainMessage<PutModelRequest> | undefined): boolean {
|
||||
return proto3.util.equals(PutModelRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.PutModelResponse
|
||||
*/
|
||||
export class PutModelResponse extends Message<PutModelResponse> {
|
||||
/**
|
||||
* @generated from field: google.protobuf.Struct model = 1;
|
||||
*/
|
||||
model?: Struct;
|
||||
|
||||
constructor(data?: PartialMessage<PutModelResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.PutModelResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "model", kind: "message", T: Struct },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutModelResponse {
|
||||
return new PutModelResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutModelResponse {
|
||||
return new PutModelResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutModelResponse {
|
||||
return new PutModelResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: PutModelResponse | PlainMessage<PutModelResponse> | undefined, b: PutModelResponse | PlainMessage<PutModelResponse> | undefined): boolean {
|
||||
return proto3.util.equals(PutModelResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.PutFormRequest
|
||||
*/
|
||||
export class PutFormRequest extends Message<PutFormRequest> {
|
||||
/**
|
||||
* @generated from field: string platform_id = 1;
|
||||
*/
|
||||
platformId = "";
|
||||
|
||||
/**
|
||||
* @generated from field: repeated google.protobuf.Struct fields = 2;
|
||||
*/
|
||||
fields: Struct[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<PutFormRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.PutFormRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "platform_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "fields", kind: "message", T: Struct, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutFormRequest {
|
||||
return new PutFormRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutFormRequest {
|
||||
return new PutFormRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutFormRequest {
|
||||
return new PutFormRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: PutFormRequest | PlainMessage<PutFormRequest> | undefined, b: PutFormRequest | PlainMessage<PutFormRequest> | undefined): boolean {
|
||||
return proto3.util.equals(PutFormRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.PutFormResponse
|
||||
*/
|
||||
export class PutFormResponse extends Message<PutFormResponse> {
|
||||
/**
|
||||
* @generated from field: repeated google.protobuf.Struct fields = 1;
|
||||
*/
|
||||
fields: Struct[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<PutFormResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.PutFormResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "fields", kind: "message", T: Struct, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PutFormResponse {
|
||||
return new PutFormResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PutFormResponse {
|
||||
return new PutFormResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PutFormResponse {
|
||||
return new PutFormResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: PutFormResponse | PlainMessage<PutFormResponse> | undefined, b: PutFormResponse | PlainMessage<PutFormResponse> | undefined): boolean {
|
||||
return proto3.util.equals(PutFormResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// @generated by protoc-gen-connect-es v1.4.0 with parameter "target=ts"
|
||||
// @generated from file holos/v1alpha1/system.proto (package holos.v1alpha1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { DropTablesRequest, DropTablesResponse, SeedDatabaseRequest, SeedDatabaseResponse } from "./system_pb.js";
|
||||
import { MethodKind } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
* @generated from service holos.v1alpha1.SystemService
|
||||
*/
|
||||
export const SystemService = {
|
||||
typeName: "holos.v1alpha1.SystemService",
|
||||
methods: {
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.SystemService.SeedDatabase
|
||||
*/
|
||||
seedDatabase: {
|
||||
name: "SeedDatabase",
|
||||
I: SeedDatabaseRequest,
|
||||
O: SeedDatabaseResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.SystemService.DropTables
|
||||
*/
|
||||
dropTables: {
|
||||
name: "DropTables",
|
||||
I: DropTablesRequest,
|
||||
O: DropTablesResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
}
|
||||
} as const;
|
||||
|
||||
132
internal/frontend/holos/src/app/gen/holos/v1alpha1/system_pb.ts
Normal file
132
internal/frontend/holos/src/app/gen/holos/v1alpha1/system_pb.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
// @generated by protoc-gen-es v1.9.0 with parameter "target=ts"
|
||||
// @generated from file holos/v1alpha1/system.proto (package holos.v1alpha1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
|
||||
import { Message, proto3 } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.SeedDatabaseRequest
|
||||
*/
|
||||
export class SeedDatabaseRequest extends Message<SeedDatabaseRequest> {
|
||||
constructor(data?: PartialMessage<SeedDatabaseRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.SeedDatabaseRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SeedDatabaseRequest {
|
||||
return new SeedDatabaseRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): SeedDatabaseRequest {
|
||||
return new SeedDatabaseRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): SeedDatabaseRequest {
|
||||
return new SeedDatabaseRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: SeedDatabaseRequest | PlainMessage<SeedDatabaseRequest> | undefined, b: SeedDatabaseRequest | PlainMessage<SeedDatabaseRequest> | undefined): boolean {
|
||||
return proto3.util.equals(SeedDatabaseRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.SeedDatabaseResponse
|
||||
*/
|
||||
export class SeedDatabaseResponse extends Message<SeedDatabaseResponse> {
|
||||
constructor(data?: PartialMessage<SeedDatabaseResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.SeedDatabaseResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SeedDatabaseResponse {
|
||||
return new SeedDatabaseResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): SeedDatabaseResponse {
|
||||
return new SeedDatabaseResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): SeedDatabaseResponse {
|
||||
return new SeedDatabaseResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: SeedDatabaseResponse | PlainMessage<SeedDatabaseResponse> | undefined, b: SeedDatabaseResponse | PlainMessage<SeedDatabaseResponse> | undefined): boolean {
|
||||
return proto3.util.equals(SeedDatabaseResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.DropTablesRequest
|
||||
*/
|
||||
export class DropTablesRequest extends Message<DropTablesRequest> {
|
||||
constructor(data?: PartialMessage<DropTablesRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.DropTablesRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DropTablesRequest {
|
||||
return new DropTablesRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DropTablesRequest {
|
||||
return new DropTablesRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DropTablesRequest {
|
||||
return new DropTablesRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: DropTablesRequest | PlainMessage<DropTablesRequest> | undefined, b: DropTablesRequest | PlainMessage<DropTablesRequest> | undefined): boolean {
|
||||
return proto3.util.equals(DropTablesRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message holos.v1alpha1.DropTablesResponse
|
||||
*/
|
||||
export class DropTablesResponse extends Message<DropTablesResponse> {
|
||||
constructor(data?: PartialMessage<DropTablesResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "holos.v1alpha1.DropTablesResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DropTablesResponse {
|
||||
return new DropTablesResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DropTablesResponse {
|
||||
return new DropTablesResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DropTablesResponse {
|
||||
return new DropTablesResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: DropTablesResponse | PlainMessage<DropTablesResponse> | undefined, b: DropTablesResponse | PlainMessage<DropTablesResponse> | undefined): boolean {
|
||||
return proto3.util.equals(DropTablesResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
// @generated by protoc-gen-connect-query v1.3.1 with parameter "target=ts"
|
||||
// @generated from file holos/v1alpha1/user.proto (package holos.v1alpha1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { MethodKind } from "@bufbuild/protobuf";
|
||||
import { CreateCallerUserRequest, CreateCallerUserResponse, GetCallerClaimsRequest, GetCallerClaimsResponse, GetCallerUserRequest, GetCallerUserResponse } from "./user_pb.js";
|
||||
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.UserService.GetCallerClaims
|
||||
*/
|
||||
export const getCallerClaims = {
|
||||
localName: "getCallerClaims",
|
||||
name: "GetCallerClaims",
|
||||
kind: MethodKind.Unary,
|
||||
I: GetCallerClaimsRequest,
|
||||
O: GetCallerClaimsResponse,
|
||||
service: {
|
||||
typeName: "holos.v1alpha1.UserService"
|
||||
}
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.UserService.GetCallerUser
|
||||
*/
|
||||
export const getCallerUser = {
|
||||
localName: "getCallerUser",
|
||||
name: "GetCallerUser",
|
||||
kind: MethodKind.Unary,
|
||||
I: GetCallerUserRequest,
|
||||
O: GetCallerUserResponse,
|
||||
service: {
|
||||
typeName: "holos.v1alpha1.UserService"
|
||||
}
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* @generated from rpc holos.v1alpha1.UserService.CreateCallerUser
|
||||
*/
|
||||
export const createCallerUser = {
|
||||
localName: "createCallerUser",
|
||||
name: "CreateCallerUser",
|
||||
kind: MethodKind.Unary,
|
||||
I: CreateCallerUserRequest,
|
||||
O: CreateCallerUserResponse,
|
||||
service: {
|
||||
typeName: "holos.v1alpha1.UserService"
|
||||
}
|
||||
} as const;
|
||||
@@ -7,10 +7,8 @@
|
||||
<span>Menu</span>
|
||||
</mat-toolbar>
|
||||
<mat-nav-list>
|
||||
<a mat-list-item routerLink="/platform-config" routerLinkActive="active-link">Platform Config</a>
|
||||
<a mat-list-item routerLink="/home" routerLinkActive="active-link">Home</a>
|
||||
<a mat-list-item routerLink="/clusters" routerLinkActive="active-link">Clusters</a>
|
||||
<a mat-list-item routerLink="/address-form" routerLinkActive="active-link">Address Form</a>
|
||||
<a mat-list-item routerLink="/platforms" routerLinkActive="active-link">Platforms</a>
|
||||
</mat-nav-list>
|
||||
</mat-sidenav>
|
||||
<mat-sidenav-content>
|
||||
@@ -35,7 +33,8 @@
|
||||
</span>
|
||||
<app-profile-button [claims$]="claims$"></app-profile-button>
|
||||
</mat-toolbar>
|
||||
<!-- Add Content Here -->
|
||||
<router-outlet></router-outlet>
|
||||
<main class="main-content">
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
.mat-toolbar.mat-primary {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.toolbar-spacer {
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { OrganizationService as ConnectOrganizationService } from '../gen/holos/v1alpha1/organization_connect';
|
||||
import { ObservableClient } from '../../connect/observable-client';
|
||||
import { Observable, switchMap, of, shareReplay, catchError, BehaviorSubject } from 'rxjs';
|
||||
import { GetCallerOrganizationsResponse, Organization } from '../gen/holos/v1alpha1/organization_pb';
|
||||
import { UserService } from './user.service';
|
||||
import { Code, ConnectError } from '@connectrpc/connect';
|
||||
import { BehaviorSubject, Observable, catchError, of, shareReplay, switchMap } from 'rxjs';
|
||||
import { ObservableClient } from '../../connect/observable-client';
|
||||
import { OrganizationService as ConnectOrganizationService } from '../gen/holos/v1alpha1/organization_connect';
|
||||
import { ListCallerOrganizationsResponse, Organization } from '../gen/holos/v1alpha1/organization_pb';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OrganizationService {
|
||||
private callerOrganizationsTrigger$ = new BehaviorSubject<void>(undefined);
|
||||
private callerOrganizations$: Observable<GetCallerOrganizationsResponse>;
|
||||
private callerOrganizations$: Observable<ListCallerOrganizationsResponse>;
|
||||
|
||||
private fetchCallerOrganizations(): Observable<GetCallerOrganizationsResponse> {
|
||||
return this.client.getCallerOrganizations({ request: {} }).pipe(
|
||||
private fetchCallerOrganizations(): Observable<ListCallerOrganizationsResponse> {
|
||||
return this.client.listCallerOrganizations({ request: {} }).pipe(
|
||||
switchMap(resp => {
|
||||
if (resp && resp.organizations.length > 0) {
|
||||
return of(resp)
|
||||
@@ -25,7 +25,7 @@ export class OrganizationService {
|
||||
if (err instanceof ConnectError) {
|
||||
if (err.code == Code.NotFound) {
|
||||
return this.userService.createUser().pipe(
|
||||
switchMap(user => this.client.createCallerOrganization({ request: {} }))
|
||||
switchMap(() => this.client.createCallerOrganization({ request: {} }))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PlatformService } from './platform.service';
|
||||
|
||||
describe('PlatformService', () => {
|
||||
let service: PlatformService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(PlatformService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
40
internal/frontend/holos/src/app/services/platform.service.ts
Normal file
40
internal/frontend/holos/src/app/services/platform.service.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { JsonValue, Struct, } from '@bufbuild/protobuf';
|
||||
import { Observable, of, switchMap } from 'rxjs';
|
||||
import { ObservableClient } from '../../connect/observable-client';
|
||||
import { Organization } from '../gen/holos/v1alpha1/organization_pb';
|
||||
import { PlatformService as ConnectPlatformService } from '../gen/holos/v1alpha1/platform_connect';
|
||||
import { GetFormResponse, ListPlatformsRequest, Platform, PutModelRequest, PutModelResponse } from '../gen/holos/v1alpha1/platform_pb';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PlatformService {
|
||||
listPlatforms(org: Observable<Organization>): Observable<Platform[]> {
|
||||
return org.pipe(
|
||||
switchMap(org => {
|
||||
const req = new ListPlatformsRequest({ orgId: org.id })
|
||||
return this.client.listPlatforms(req).pipe(
|
||||
switchMap(resp => { return of(resp.platforms) })
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
getForm(id: string): Observable<GetFormResponse> {
|
||||
return this.client.getForm({ platformId: id })
|
||||
}
|
||||
|
||||
putModel(id: string, model: JsonValue): Observable<PutModelResponse> {
|
||||
const req = new PutModelRequest({
|
||||
platformId: id,
|
||||
// "We recommend to use fromJson() to construct Struct literals" refer to
|
||||
// https://github.com/bufbuild/protobuf-es/blob/main/docs/runtime_api.md#struct
|
||||
model: Struct.fromJson(model),
|
||||
})
|
||||
return this.client.putModel(req)
|
||||
}
|
||||
|
||||
|
||||
constructor(@Inject(ConnectPlatformService) private client: ObservableClient<typeof ConnectPlatformService>) { }
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Organization">
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit(model)">
|
||||
<mat-card class="config-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Organization</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>Organization config values are used to derive more specific configuration values throughout the platform.</p>
|
||||
<formly-form [form]="form" [fields]="fields" [model]="model">
|
||||
</formly-form>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" type="submit">Submit</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
||||
|
||||
</mat-tab>
|
||||
<mat-tab label="Integrations">
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit(model)">
|
||||
<mat-card class="config-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Integrations</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>Configure integrations with your DNS and version control service providers.</p>
|
||||
<formly-form [form]="form" [fields]="integrationFields" [model]="model">
|
||||
</formly-form>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" type="submit">Submit</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
||||
|
||||
</mat-tab>
|
||||
<mat-tab label="Provisioner">
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit(model)">
|
||||
<mat-card class="config-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Provisioner Cluster</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>Provide the connection details used to sync secrets among platform clusters.</p>
|
||||
<formly-form [form]="form" [fields]="provisionerFields" [model]="model">
|
||||
</formly-form>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" type="submit">Submit</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
||||
</mat-tab>
|
||||
<mat-tab label="OAuth Clients"></mat-tab>
|
||||
</mat-tab-group>
|
||||
@@ -1,27 +0,0 @@
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.config-card {
|
||||
min-width: 120px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.mat-radio-button {
|
||||
display: block;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.col {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.col:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardActions, MatCardContent, MatCardHeader, MatCardTitle } from '@angular/material/card';
|
||||
import { FormlyModule, FormlyFieldConfig } from '@ngx-formly/core';
|
||||
import { FormlyMaterialModule } from '@ngx-formly/material';
|
||||
|
||||
@Component({
|
||||
selector: 'app-platform-config',
|
||||
standalone: true,
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
FormlyMaterialModule,
|
||||
FormlyModule,
|
||||
MatTabsModule,
|
||||
MatCard,
|
||||
MatCardHeader,
|
||||
MatCardTitle,
|
||||
MatCardContent,
|
||||
MatCardActions,
|
||||
MatButton,
|
||||
],
|
||||
templateUrl: './platform-config.component.html',
|
||||
styleUrl: './platform-config.component.scss'
|
||||
})
|
||||
export class PlatformConfigComponent {
|
||||
form = new FormGroup({});
|
||||
model: any = {};
|
||||
fields: FormlyFieldConfig[] = [
|
||||
{
|
||||
key: 'name',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Name',
|
||||
placeholder: 'example',
|
||||
required: true,
|
||||
description: "DNS label, e.g. 'example'"
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'domain',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Domain',
|
||||
placeholder: 'example.com',
|
||||
required: true,
|
||||
description: "DNS domain, e.g. 'example.com'"
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'displayName',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Display Name',
|
||||
placeholder: 'Example Organization',
|
||||
required: true,
|
||||
description: "Display name, e.g. 'My Organization'"
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'contactEmail',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Contact Email',
|
||||
placeholder: '',
|
||||
required: true,
|
||||
description: "Organization technical contact."
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
integrationFields: FormlyFieldConfig[] = [
|
||||
{
|
||||
key: 'cloudflareEmail',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Cloudflare Account',
|
||||
placeholder: 'example@example.com',
|
||||
required: true,
|
||||
description: "Cloudflare account email address."
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'githubPrimaryOrg',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Github Organization',
|
||||
placeholder: 'ExampleOrg',
|
||||
required: true,
|
||||
description: "Github organization, e.g. 'ExampleOrg'"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
provisionerFields: FormlyFieldConfig[] = [
|
||||
{
|
||||
key: 'provisionerCABundle',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Provisioner API CA Bundle',
|
||||
placeholder: 'LS0tLS1CRUdJTiBDRVJUSUZJQXXXXXXXXXXXXXXXXXXXXXXX',
|
||||
required: true,
|
||||
description: "kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.certificate-authority-data}'"
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'provisionerURL',
|
||||
type: 'input',
|
||||
props: {
|
||||
label: 'Provisioner API URL',
|
||||
placeholder: 'https://1.2.3.4',
|
||||
required: true,
|
||||
description: "kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.server}'"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
onSubmit(model: any) {
|
||||
console.log(model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<div class="content-container">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Detail">
|
||||
<div class="grid-container">
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit(model)">
|
||||
<formly-form [model]="model" [fields]="fields" [options]="options" [form]="form"></formly-form>
|
||||
<button type="submit" mat-flat-button color="primary" [disabled]="!form.valid">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Model">
|
||||
<div class="grid-container">
|
||||
<pre>{{ model | json }}</pre>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Form State">
|
||||
<div class="grid-container">
|
||||
<pre>{{ options.formState | json }}</pre>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Fields">
|
||||
<div class="grid-container">
|
||||
<pre>{{ fields | json }}</pre>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
.grid-container {
|
||||
margin: 20px;
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PlatformConfigComponent } from './platform-config.component';
|
||||
import { PlatformDetailComponent } from './platform-detail.component';
|
||||
|
||||
describe('PlatformConfigComponent', () => {
|
||||
let component: PlatformConfigComponent;
|
||||
let fixture: ComponentFixture<PlatformConfigComponent>;
|
||||
describe('PlatformDetailComponent', () => {
|
||||
let component: PlatformDetailComponent;
|
||||
let fixture: ComponentFixture<PlatformDetailComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [PlatformConfigComponent]
|
||||
imports: [PlatformDetailComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(PlatformConfigComponent);
|
||||
fixture = TestBed.createComponent(PlatformDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import { AsyncPipe, CommonModule } from '@angular/common';
|
||||
import { Component, Input, OnDestroy, inject } from '@angular/core';
|
||||
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatDivider } from '@angular/material/divider';
|
||||
import { MatTab, MatTabGroup } from '@angular/material/tabs';
|
||||
import { JsonValue } from '@bufbuild/protobuf';
|
||||
import { FormlyFieldConfig, FormlyFormOptions, FormlyModule } from '@ngx-formly/core';
|
||||
import { FormlyMaterialModule } from '@ngx-formly/material';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
import { PlatformService } from '../../services/platform.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-platform-detail',
|
||||
standalone: true,
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
CommonModule,
|
||||
FormlyMaterialModule,
|
||||
FormlyModule,
|
||||
MatButton,
|
||||
MatDivider,
|
||||
MatTab,
|
||||
MatTabGroup,
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
templateUrl: './platform-detail.component.html',
|
||||
styleUrl: './platform-detail.component.scss'
|
||||
})
|
||||
export class PlatformDetailComponent implements OnDestroy {
|
||||
private platformService = inject(PlatformService);
|
||||
private platformId: string = "";
|
||||
|
||||
private destroy$: Subject<boolean> = new Subject<boolean>();
|
||||
form = new FormGroup({});
|
||||
fields: FormlyFieldConfig[] = [];
|
||||
model: JsonValue = {};
|
||||
// Use form state to store the model for nested forms
|
||||
// Refer to https://formly.dev/docs/examples/form-options/form-state/
|
||||
options: FormlyFormOptions = {
|
||||
formState: {
|
||||
model: this.model,
|
||||
},
|
||||
};
|
||||
|
||||
private setModel(model: JsonValue) {
|
||||
if (model) {
|
||||
this.model = model
|
||||
this.options.formState.model = model
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit(model: JsonValue) {
|
||||
if (this.form.valid) {
|
||||
console.log(model)
|
||||
this.platformService
|
||||
.putModel(this.platformId, model)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(resp => {
|
||||
if (resp.model !== undefined) {
|
||||
this.setModel(resp.model.toJson())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Input()
|
||||
set id(platformId: string) {
|
||||
this.platformId = platformId;
|
||||
this.platformService
|
||||
.getForm(platformId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(resp => {
|
||||
if (resp.model !== undefined) {
|
||||
this.setModel(resp.model.toJson())
|
||||
}
|
||||
if (resp.fields !== undefined) {
|
||||
// NOTE: We could mix functions into the json data via mapped fields,
|
||||
// but consider carefully before doing so. Refer to
|
||||
// https://formly.dev/docs/examples/other/json-powered
|
||||
this.fields = resp.fields.map(field => field.toJson() as FormlyFieldConfig)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.destroy$.next(true);
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="grid-container">
|
||||
<mat-nav-list>
|
||||
<h3 mat-subheader>Platforms</h3>
|
||||
<p>Select a platform to manage.</p>
|
||||
@for (platform of (platforms$ | async); track platform.id) {
|
||||
<a mat-list-item [routerLink]="['/platform', platform.id]">
|
||||
{{ platform.displayName ? platform.displayName : platform.name }}
|
||||
</a>
|
||||
}
|
||||
</mat-nav-list>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
.grid-container {
|
||||
margin: 20px;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PlatformsComponent } from './platforms.component';
|
||||
|
||||
describe('PlatformsComponent', () => {
|
||||
let component: PlatformsComponent;
|
||||
let fixture: ComponentFixture<PlatformsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [PlatformsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(PlatformsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Platform } from '../../gen/holos/v1alpha1/platform_pb';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { MatListItem, MatNavList } from '@angular/material/list';
|
||||
import { Observable, filter } from 'rxjs';
|
||||
import { Organization } from '../../gen/holos/v1alpha1/organization_pb';
|
||||
import { OrganizationService } from '../../services/organization.service';
|
||||
import { PlatformService } from '../../services/platform.service';
|
||||
import { AsyncPipe, CommonModule } from '@angular/common';
|
||||
import { RouterLink } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-platforms',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatNavList,
|
||||
MatListItem,
|
||||
AsyncPipe,
|
||||
CommonModule,
|
||||
RouterLink,
|
||||
],
|
||||
templateUrl: './platforms.component.html',
|
||||
styleUrl: './platforms.component.scss'
|
||||
})
|
||||
export class PlatformsComponent implements OnInit {
|
||||
private orgSvc = inject(OrganizationService);
|
||||
private platformSvc = inject(PlatformService);
|
||||
|
||||
org$!: Observable<Organization | undefined>;
|
||||
platforms$!: Observable<Platform[]>;
|
||||
|
||||
ngOnInit() {
|
||||
this.org$ = this.orgSvc.activeOrg();
|
||||
this.platforms$ = this.platformSvc.listPlatforms(this.org$.pipe(
|
||||
filter((org): org is Organization => org !== undefined)
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="card">
|
||||
<h2 class="card-header">{{ props.label }}</h2>
|
||||
<div class="card-body">
|
||||
<p>{{ props.description }}</p>
|
||||
<ng-container #fieldComponent></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
.card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HolosPanelWrapperComponent } from './holos-panel-wrapper.component';
|
||||
|
||||
describe('HolosPanelWrapperComponent', () => {
|
||||
let component: HolosPanelWrapperComponent;
|
||||
let fixture: ComponentFixture<HolosPanelWrapperComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HolosPanelWrapperComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HolosPanelWrapperComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FieldWrapper } from '@ngx-formly/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-holos-panel-wrapper',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './holos-panel-wrapper.component.html',
|
||||
styleUrl: './holos-panel-wrapper.component.scss'
|
||||
})
|
||||
export class HolosPanelWrapperComponent extends FieldWrapper { }
|
||||
@@ -11,29 +11,335 @@ let Platform = formsv1.#Platform & {
|
||||
description: "Organization config values are used to derive more specific configuration values throughout the platform."
|
||||
|
||||
fieldConfigs: {
|
||||
// platform.org.name
|
||||
name: props: {
|
||||
label: "Name"
|
||||
placeholder: "example"
|
||||
description: "DNS label, e.g. 'example'"
|
||||
// platform.spec.config.user.sections.org.fields.name
|
||||
name: {
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Name"
|
||||
// placeholder: "example" placeholder cannot be used with validation?
|
||||
description: "DNS label, e.g. 'example'"
|
||||
pattern: "^[a-z]([0-9a-z]|-){1,28}[0-9a-z]$"
|
||||
minLength: 3
|
||||
maxLength: 30
|
||||
required: true
|
||||
}
|
||||
validation: messages: {
|
||||
pattern: "It must be 3 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited."
|
||||
}
|
||||
}
|
||||
// platform.org.domain
|
||||
domain: props: {
|
||||
label: "Domain"
|
||||
placeholder: "example.com"
|
||||
description: "DNS domain, e.g. 'example.com'"
|
||||
|
||||
// platform.spec.config.user.sections.org.fields.domain
|
||||
domain: {
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Domain"
|
||||
placeholder: "example.com"
|
||||
minLength: 3
|
||||
maxLength: 100
|
||||
description: "DNS domain, e.g. 'example.com'"
|
||||
required: true
|
||||
}
|
||||
}
|
||||
// platform.org.displayName
|
||||
displayName: props: {
|
||||
label: "Display Name"
|
||||
placeholder: "Example Organization"
|
||||
description: "Display name, e.g. 'Example Organization'"
|
||||
// platform.spec.config.user.sections.org.fields.displayName
|
||||
displayName: {
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Display Name"
|
||||
placeholder: "Example Organization"
|
||||
description: "Display name, e.g. 'Example Organization'"
|
||||
maxLength: 100
|
||||
required: true
|
||||
}
|
||||
}
|
||||
// platform.org.contactEmail
|
||||
contactEmail: props: {
|
||||
label: "Contact Email"
|
||||
placeholder: "platform-team@example.com"
|
||||
description: "Technical contact email address"
|
||||
// platform.spec.config.user.sections.org.fields.contactEmail
|
||||
contactEmail: {
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Contact Email"
|
||||
placeholder: "platform-team@example.com"
|
||||
description: "Technical contact email address"
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sections: cloud: {
|
||||
displayName: "Cloud Providers"
|
||||
description: "Select the services that provide resources for the platform."
|
||||
|
||||
fieldConfigs: {
|
||||
providers: {
|
||||
// https://formly.dev/docs/api/ui/material/select/
|
||||
type: "select"
|
||||
props: {
|
||||
label: "Select Providers"
|
||||
description: "Select the cloud providers the platform builds upon."
|
||||
multiple: true
|
||||
selectAllOption: "Select All"
|
||||
options: [
|
||||
{value: "aws", label: "Amazon Web Services"},
|
||||
{value: "gcp", label: "Google Cloud Platform"},
|
||||
{value: "azure", label: "Microsoft Azure"},
|
||||
{value: "cloudflare", label: "Cloudflare"},
|
||||
{value: "github", label: "GitHub"},
|
||||
{value: "ois", label: "Open Infrastructure Services"},
|
||||
{value: "onprem", label: "On Premises", disabled: true},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sections: aws: {
|
||||
displayName: "Amazon Web Services"
|
||||
description: "Provide the information necessary for Holos to manage AWS resources to provide the platform."
|
||||
|
||||
expressions: hide: "!\(AWSSelected)"
|
||||
|
||||
fieldConfigs: {
|
||||
primaryRoleARN: {
|
||||
// https://formly.dev/docs/api/ui/material/input
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Holos Admin Role ARN"
|
||||
description: "Enter the AWS Role ARN Holos will use to bootstrap resources. For example, arn:aws:iam::123456789012:role/HolosAdminAccess"
|
||||
pattern: "^arn:.*"
|
||||
minLength: 4
|
||||
required: true
|
||||
}
|
||||
validation: messages: {
|
||||
pattern: "Must be a valid ARN. Refer to https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html"
|
||||
}
|
||||
}
|
||||
|
||||
regions: {
|
||||
// https://formly.dev/docs/api/ui/material/select/
|
||||
type: "select"
|
||||
props: {
|
||||
label: "Select Regions"
|
||||
description: "Select the AWS regions this platform operates in."
|
||||
multiple: true
|
||||
required: true
|
||||
selectAllOption: "Select All"
|
||||
options: AWSRegions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sections: gcp: {
|
||||
displayName: "Google Cloud Platform"
|
||||
description: "Use this form to configure platform level GCP settings."
|
||||
|
||||
expressions: hide: "!\(GCPSelected)"
|
||||
|
||||
fieldConfigs: {
|
||||
regions: {
|
||||
// https://formly.dev/docs/api/ui/material/select/
|
||||
type: "select"
|
||||
props: {
|
||||
label: "Select Regions"
|
||||
description: "Select the GCP regions this platform operates in."
|
||||
multiple: true
|
||||
selectAllOption: "Select All"
|
||||
// gcloud compute regions list --format=json | jq '.[] | {value: .name, label: .description}' regions.json | jq -s | cue export --out cue
|
||||
options: GCPRegions
|
||||
}
|
||||
}
|
||||
|
||||
gcpProjectID: {
|
||||
// https://formly.dev/docs/api/ui/material/input
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Project ID"
|
||||
description: "Enter the project id where the provisioner cluster resides."
|
||||
pattern: "^[a-z]([0-9a-z]|-){1,28}[0-9a-z]$"
|
||||
minLength: 6
|
||||
maxLength: 30
|
||||
required: true
|
||||
}
|
||||
validation: messages: {
|
||||
pattern: "It must be 3 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited."
|
||||
}
|
||||
}
|
||||
|
||||
gcpProjectNumber: {
|
||||
// https://formly.dev/docs/api/ui/material/input
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Project Number"
|
||||
// note type number here
|
||||
type: "number"
|
||||
description: "Enter the project number where the provisioner cluster resides."
|
||||
pattern: "^[0-9]+$"
|
||||
required: true
|
||||
}
|
||||
validation: messages: {
|
||||
pattern: "Must be a valid project number."
|
||||
}
|
||||
}
|
||||
|
||||
provisionerCABundle: {
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Provisioner CA Bundle"
|
||||
description: "Enter the provisioner cluster ca bundle. kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.certificate-authority-data}'"
|
||||
pattern: "^[0-9a-zA-Z]+=*$"
|
||||
required: true
|
||||
}
|
||||
validation: messages: {
|
||||
pattern: "Must be a base64 encoded pem encoded certificate bundle."
|
||||
}
|
||||
}
|
||||
|
||||
provisionerURL: {
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Provisioner URL"
|
||||
description: "Enter the URL of the provisioner cluster API endpoint. kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.server}'"
|
||||
pattern: "^https://.*$"
|
||||
required: true
|
||||
}
|
||||
validation: messages: {
|
||||
pattern: "Must be a https:// URL."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sections: cloudflare: {
|
||||
displayName: "Cloudflare"
|
||||
description: "Cloudflare is primarily used for DNS automation."
|
||||
|
||||
expressions: hide: "!" + CloudflareSelected
|
||||
|
||||
fieldConfigs: {
|
||||
email: {
|
||||
// https://formly.dev/docs/api/ui/material/input
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Account Email"
|
||||
description: "Enter the Cloudflare email address to manage DNS"
|
||||
minLength: 3
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sections: github: {
|
||||
displayName: "GitHub"
|
||||
description: "GitHub is primarily used to host Git repositories and execute Actions workflows."
|
||||
|
||||
expressions: hide: "!\(GitHubSelected)"
|
||||
|
||||
fieldConfigs: {
|
||||
primaryOrg: {
|
||||
// https://formly.dev/docs/api/ui/material/input
|
||||
type: "input"
|
||||
props: {
|
||||
label: "Organization"
|
||||
description: "Enter the primary GitHub organization associed with the platform."
|
||||
pattern: "^(?!-)(?!.*--)([a-zA-Z0-9]|-){1,39}$"
|
||||
minLength: 1
|
||||
maxLength: 39
|
||||
required: true
|
||||
}
|
||||
validation: messages: {
|
||||
pattern: "All characters must be either a hyphen or alphanumeric. Cannot start with a hyphen. Cannot include consecutive hyphens."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sections: backups: {
|
||||
displayName: "Backups"
|
||||
description: "Configure platform level data backup settings. Requires AWS."
|
||||
|
||||
fieldConfigs: {
|
||||
s3bucket: {
|
||||
// https://formly.dev/docs/api/ui/material/input
|
||||
type: "select"
|
||||
props: {
|
||||
label: "S3 Bucket Region"
|
||||
description: "Select the S3 Bucket Region."
|
||||
multiple: true
|
||||
options: AWSRegions
|
||||
}
|
||||
expressions: {
|
||||
// Disable the control if AWS is not selected.
|
||||
"props.disabled": "!" + AWSSelected
|
||||
// Required if AWS is selected.
|
||||
"props.required": AWSSelected
|
||||
// Change the label depending on AWS
|
||||
"props.description": AWSSelected + " ? '\(props.description)' : 'Enable AWS in the Cloud Provider section to configure backups.'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sections: privacy: {
|
||||
displayName: "Data Privacy"
|
||||
description: "Configure data privacy aspects of the platform."
|
||||
|
||||
fieldConfigs: {
|
||||
country: {
|
||||
// https://formly.dev/docs/api/ui/material/select/
|
||||
type: "select"
|
||||
props: {
|
||||
label: "Select Planet"
|
||||
description: "Juridiction of applicable data privacy laws."
|
||||
options: [
|
||||
{value: "mercury", label: "Mercury"},
|
||||
{value: "venus", label: "Venus"},
|
||||
{value: "earth", label: "Earth"},
|
||||
{value: "mars", label: "Mars"},
|
||||
{value: "jupiter", label: "Jupiter"},
|
||||
{value: "saturn", label: "Saturn"},
|
||||
{value: "uranus", label: "Uranus"},
|
||||
{value: "neptune", label: "Neptune"},
|
||||
]
|
||||
}
|
||||
}
|
||||
regions: {
|
||||
// https://formly.dev/docs/api/ui/material/select/
|
||||
type: "select"
|
||||
props: {
|
||||
label: "Select Regions"
|
||||
description: "Select the regions this platform operates in."
|
||||
multiple: true
|
||||
selectAllOption: "Select All"
|
||||
options: [
|
||||
{value: "us-east-2", label: "Ohio"},
|
||||
{value: "us-west-2", label: "Oregon"},
|
||||
{value: "eu-west-1", label: "Ireland"},
|
||||
{value: "eu-west-2", label: "London", disabled: true},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sections: terms: {
|
||||
displayName: "Terms and Conditions"
|
||||
description: "Example of a boolean checkbox."
|
||||
|
||||
fieldConfigs: {
|
||||
// platform.spec.config.user.sections.terms.fields.didAgree
|
||||
didAgree: {
|
||||
type: "checkbox"
|
||||
props: {
|
||||
label: "Accept terms"
|
||||
description: "In order to proceed, please accept terms"
|
||||
pattern: "true"
|
||||
required: true
|
||||
}
|
||||
validation: {
|
||||
messages: {
|
||||
pattern: "Please accept the terms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,3 +347,80 @@ let Platform = formsv1.#Platform & {
|
||||
|
||||
// Provide the output form fields
|
||||
Platform.Form
|
||||
|
||||
let GCPRegions = [
|
||||
{value: "africa-south1", label: "africa-south1"},
|
||||
{value: "asia-east1", label: "asia-east1"},
|
||||
{value: "asia-east2", label: "asia-east2"},
|
||||
{value: "asia-northeast1", label: "asia-northeast1"},
|
||||
{value: "asia-northeast2", label: "asia-northeast2"},
|
||||
{value: "asia-northeast3", label: "asia-northeast3"},
|
||||
{value: "asia-south1", label: "asia-south1"},
|
||||
{value: "asia-south2", label: "asia-south2"},
|
||||
{value: "asia-southeast1", label: "asia-southeast1"},
|
||||
{value: "asia-southeast2", label: "asia-southeast2"},
|
||||
{value: "australia-southeast1", label: "australia-southeast1"},
|
||||
{value: "australia-southeast2", label: "australia-southeast2"},
|
||||
{value: "europe-central2", label: "europe-central2"},
|
||||
{value: "europe-north1", label: "europe-north1"},
|
||||
{value: "europe-southwest1", label: "europe-southwest1"},
|
||||
{value: "europe-west1", label: "europe-west1"},
|
||||
{value: "europe-west10", label: "europe-west10"},
|
||||
{value: "europe-west12", label: "europe-west12"},
|
||||
{value: "europe-west2", label: "europe-west2"},
|
||||
{value: "europe-west3", label: "europe-west3"},
|
||||
{value: "europe-west4", label: "europe-west4"},
|
||||
{value: "europe-west6", label: "europe-west6"},
|
||||
{value: "europe-west8", label: "europe-west8"},
|
||||
{value: "europe-west9", label: "europe-west9"},
|
||||
{value: "me-central1", label: "me-central1"},
|
||||
{value: "me-central2", label: "me-central2"},
|
||||
{value: "me-west1", label: "me-west1"},
|
||||
{value: "northamerica-northeast1", label: "northamerica-northeast1"},
|
||||
{value: "northamerica-northeast2", label: "northamerica-northeast2"},
|
||||
{value: "southamerica-east1", label: "southamerica-east1"},
|
||||
{value: "southamerica-west1", label: "southamerica-west1"},
|
||||
{value: "us-central1", label: "us-central1"},
|
||||
{value: "us-east1", label: "us-east1"},
|
||||
{value: "us-east4", label: "us-east4"},
|
||||
{value: "us-east5", label: "us-east5"},
|
||||
{value: "us-south1", label: "us-south1"},
|
||||
{value: "us-west1", label: "us-west1"},
|
||||
{value: "us-west2", label: "us-west2"},
|
||||
{value: "us-west3", label: "us-west3"},
|
||||
{value: "us-west4", label: "us-west4"},
|
||||
]
|
||||
|
||||
let AWSRegions = [
|
||||
{value: "us-east-1", label: "N. Virginia (us-east-1)"},
|
||||
{value: "us-east-2", label: "Ohio (us-east-2)"},
|
||||
{value: "us-west-1", label: "N. California (us-west-1)"},
|
||||
{value: "us-west-2", label: "Oregon (us-west-2)"},
|
||||
{value: "us-gov-west1", label: "US GovCloud West (us-gov-west1)"},
|
||||
{value: "us-gov-east1", label: "US GovCloud East (us-gov-east1)"},
|
||||
{value: "ca-central-1", label: "Canada (ca-central-1)"},
|
||||
{value: "eu-north-1", label: "Stockholm (eu-north-1)"},
|
||||
{value: "eu-west-1", label: "Ireland (eu-west-1)"},
|
||||
{value: "eu-west-2", label: "London (eu-west-2)"},
|
||||
{value: "eu-west-3", label: "Paris (eu-west-3)"},
|
||||
{value: "eu-central-1", label: "Frankfurt (eu-central-1)"},
|
||||
{value: "eu-south-1", label: "Milan (eu-south-1)"},
|
||||
{value: "af-south-1", label: "Cape Town (af-south-1)"},
|
||||
{value: "ap-northeast-1", label: "Tokyo (ap-northeast-1)"},
|
||||
{value: "ap-northeast-2", label: "Seoul (ap-northeast-2)"},
|
||||
{value: "ap-northeast-3", label: "Osaka (ap-northeast-3)"},
|
||||
{value: "ap-southeast-1", label: "Singapore (ap-southeast-1)"},
|
||||
{value: "ap-southeast-2", label: "Sydney (ap-southeast-2)"},
|
||||
{value: "ap-east-1", label: "Hong Kong (ap-east-1)"},
|
||||
{value: "ap-south-1", label: "Mumbai (ap-south-1)"},
|
||||
{value: "me-south-1", label: "Bahrain (me-south-1)"},
|
||||
{value: "sa-east-1", label: "São Paulo (sa-east-1)"},
|
||||
{value: "cn-north-1", label: "Bejing (cn-north-1)"},
|
||||
{value: "cn-northwest-1", label: "Ningxia (cn-northwest-1)"},
|
||||
{value: "ap-southeast-3", label: "Jakarta (ap-southeast-3)"},
|
||||
]
|
||||
|
||||
let AWSSelected = "formState.model.cloud?.providers?.includes(\"aws\")"
|
||||
let GCPSelected = "formState.model.cloud?.providers?.includes(\"gcp\")"
|
||||
let GitHubSelected = "formState.model.cloud?.providers?.includes(\"github\")"
|
||||
let CloudflareSelected = "formState.model.cloud?.providers?.includes(\"cloudflare\")"
|
||||
|
||||
@@ -22,4 +22,18 @@ package holos
|
||||
// #PlatformSpec represents configuration values defined by the platform
|
||||
// designer. Config values are organized by section, then simple strings for
|
||||
// each section.
|
||||
#PlatformSpec: {[string]: {[string]: string | bool | [...string]}}
|
||||
#PlatformSpec: {
|
||||
config: [string]: _
|
||||
config: user: #UserDefinedConfig
|
||||
}
|
||||
|
||||
// #PlatformUserConfig represents configuration fields and values defined by the
|
||||
// user.
|
||||
#UserDefinedConfig: {
|
||||
sections: [string]: fields: [string]: _
|
||||
}
|
||||
|
||||
// #PlatformConfig represents the platform config data returned from the Holos API. Useful for cue vet.
|
||||
#PlatformConfig: {
|
||||
platform: spec: #PlatformSpec
|
||||
}
|
||||
|
||||
@@ -1 +1,20 @@
|
||||
{"platform":{"spec":{"org":{"name":"ois"}}}}
|
||||
{
|
||||
"platform": {
|
||||
"spec": {
|
||||
"config": {
|
||||
"user": {
|
||||
"sections": {
|
||||
"org": {
|
||||
"fields": {
|
||||
"contactEmail": "jeff@openinfrastructure.co",
|
||||
"displayName": "Open Infrastructure Services LLC",
|
||||
"domain": "ois.run",
|
||||
"name": "ois"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,35 +16,49 @@ package v1alpha1
|
||||
}
|
||||
|
||||
let Sections = sections
|
||||
Form: spec: sections: [for s in Sections {s.output}]
|
||||
|
||||
// Collapse all sections into one fields list.
|
||||
// Refer to https://formly.dev/docs/examples/other/nested-formly-forms
|
||||
Form: spec: fields: [for s in Sections {s.wrapper}]
|
||||
}
|
||||
|
||||
#PlatformFormSpec: {
|
||||
sections: [...#ConfigSectionOutput]
|
||||
fields: [...#FieldConfig]
|
||||
}
|
||||
|
||||
// #ConfigSection represents a configuration section of the front end UI. For
|
||||
// #ConfigSection represents a configuration section of the front end UI. For
|
||||
// example, Organization config values. The fields of the section map to form
|
||||
// input fields.
|
||||
#ConfigSection: {
|
||||
name: string // e.g. "org"
|
||||
displayName: string // e.g. "Organization"
|
||||
description: string
|
||||
|
||||
expressions: {[string]: string}
|
||||
|
||||
fieldConfigs: {[NAME=string]: #FieldConfig & {key: NAME}}
|
||||
|
||||
let Name = name
|
||||
let DisplayName = displayName
|
||||
let Description = description
|
||||
let FieldConfigs = fieldConfigs
|
||||
let Expressions = expressions
|
||||
|
||||
output: #ConfigSectionOutput & {
|
||||
name: Name
|
||||
displayName: DisplayName
|
||||
description: Description
|
||||
fieldConfigs: [for fc in FieldConfigs {fc}]
|
||||
// Wrap the fields of the section into one FormlyFieldConfig
|
||||
wrapper: #FieldConfig & {
|
||||
key: name
|
||||
// See our custom wrappers registered in app.config.ts
|
||||
wrappers: ["holos-panel"]
|
||||
props: label: displayName
|
||||
props: description: Description
|
||||
for k, v in Expressions {
|
||||
expressions: "\(k)": v
|
||||
}
|
||||
|
||||
// Might need to initialize the default value for a fieldGroup
|
||||
// https://github.com/ngx-formly/ngx-formly/issues/3667
|
||||
fieldGroup: [for fc in fieldConfigs {fc}]
|
||||
}
|
||||
}
|
||||
|
||||
// REMOVE
|
||||
#ConfigSectionOutput: {
|
||||
name: string
|
||||
displayName: string
|
||||
@@ -53,13 +67,68 @@ package v1alpha1
|
||||
}
|
||||
|
||||
// Refer to https://formly.dev/docs/api/core#formlyfieldconfig
|
||||
// Refer to https://formly.dev/docs/api/ui/material/select
|
||||
#FieldConfig: {
|
||||
key: string
|
||||
type: "input"
|
||||
key: string
|
||||
// type is optional, may be a nested form which has no type field
|
||||
type?: string | "input" | "select" | "checkbox"
|
||||
// For nested forms, refer: to https://formly.dev/docs/examples/other/nested-formly-forms
|
||||
wrappers?: [...string]
|
||||
// Refer to: https://formly.dev/docs/api/ui/material/select#formlyselectprops
|
||||
// and other input field select props.
|
||||
props: {
|
||||
label: string
|
||||
placeholder: string
|
||||
description: string
|
||||
required: *true | false
|
||||
#FormlySelectProps
|
||||
|
||||
label: string
|
||||
type?: string
|
||||
placeholder?: string
|
||||
description: string
|
||||
required?: *true | false
|
||||
pattern?: string
|
||||
minLength?: number
|
||||
maxLength?: number
|
||||
}
|
||||
// Refer to: https://github.com/ngx-formly/ngx-formly/blob/v6.3.0/src/core/src/lib/models/fieldconfig.ts#L49-L64
|
||||
// We support only the string form.
|
||||
validation?: {
|
||||
// Note, you can set messages for pattern, minLength, maxLength here.
|
||||
messages?: [string]: string
|
||||
}
|
||||
|
||||
// Refer to: https://github.com/ngx-formly/ngx-formly/blob/v6.3.0/src/core/src/lib/models/fieldconfig.ts#L66-L71
|
||||
// We do not support validators because they must be javascript functions, not data.
|
||||
validators?: "not supported"
|
||||
|
||||
// Refer to: https://github.com/ngx-formly/ngx-formly/blob/v6.3.0/src/core/src/lib/models/fieldconfig.ts#L115-L120
|
||||
expressions?: [string]: string
|
||||
hide?: true | false
|
||||
// Required to populate protobuf value.
|
||||
resetOnHide: *true | false
|
||||
defaultValue?: _
|
||||
className?: string
|
||||
fieldGroup?: [...#FieldConfig]
|
||||
focus?: true | *false
|
||||
modelOptions?: {
|
||||
debounce?: {
|
||||
default: number
|
||||
}
|
||||
updateOn?: "change" | "blur" | "submit"
|
||||
}
|
||||
}
|
||||
|
||||
// Refer to https://formly.dev/docs/api/ui/material/select#formlyselectprops
|
||||
#FormlySelectProps: {
|
||||
disableOptionCentering?: true | false
|
||||
multiple?: true | false
|
||||
panelClass?: string
|
||||
selectAllOption?: string
|
||||
typeaheadDebounceInterval?: number
|
||||
|
||||
options?: [...{value: string | number | bool, label: string, disabled?: true | *false}]
|
||||
|
||||
// These could be used to set different keys for value and label in the
|
||||
// options list, but we don't support that level of customization.
|
||||
// They're here for documentation purposes only.
|
||||
labelProp?: "label"
|
||||
valueProp?: "value"
|
||||
}
|
||||
|
||||
@@ -9,32 +9,37 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/holos-run/holos/internal/ent"
|
||||
"github.com/holos-run/holos/internal/server/middleware/logger"
|
||||
)
|
||||
|
||||
// WithTx runs callbacks in a transaction as described in https://entgo.io/docs/transactions/#best-practices
|
||||
func WithTx(ctx context.Context, client *ent.Client, fn func(tx *ent.Tx) error) error {
|
||||
log := logger.FromContext(ctx)
|
||||
tx, err := client.Tx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if v := recover(); v != nil {
|
||||
slog.ErrorContext(ctx, "panic", "v", v)
|
||||
log.ErrorContext(ctx, "panic", "v", v)
|
||||
_ = tx.Rollback()
|
||||
panic(v)
|
||||
}
|
||||
}()
|
||||
if err := fn(tx); err != nil {
|
||||
if rerr := tx.Rollback(); rerr != nil {
|
||||
err = fmt.Errorf("%w: rolling back transaction: %v", err, rerr)
|
||||
log.ErrorContext(ctx, "could not roll back tx", "err", rerr)
|
||||
err = fmt.Errorf("coult not roll back tx: %w: %w", rerr, err)
|
||||
} else {
|
||||
log.WarnContext(ctx, "rolled back failed tx", "err", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("committing transaction: %w", err)
|
||||
log.ErrorContext(ctx, "could not commit transaction", "err", err)
|
||||
return fmt.Errorf("could not commit: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/holos-run/holos/internal/ent"
|
||||
"github.com/holos-run/holos/internal/ent/user"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/logger"
|
||||
"github.com/holos-run/holos/internal/server/middleware/authn"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -26,10 +27,10 @@ type OrganizationHandler struct {
|
||||
db *ent.Client
|
||||
}
|
||||
|
||||
func (h *OrganizationHandler) GetCallerOrganizations(
|
||||
func (h *OrganizationHandler) ListCallerOrganizations(
|
||||
ctx context.Context,
|
||||
req *connect.Request[holos.GetCallerOrganizationsRequest],
|
||||
) (*connect.Response[holos.GetCallerOrganizationsResponse], error) {
|
||||
req *connect.Request[holos.ListCallerOrganizationsRequest],
|
||||
) (*connect.Response[holos.ListCallerOrganizationsResponse], error) {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
@@ -55,7 +56,7 @@ func (h *OrganizationHandler) GetCallerOrganizations(
|
||||
rpcOrgs = append(rpcOrgs, OrganizationToRPC(dbOrg))
|
||||
}
|
||||
|
||||
res := connect.NewResponse(&holos.GetCallerOrganizationsResponse{
|
||||
res := connect.NewResponse(&holos.ListCallerOrganizationsResponse{
|
||||
User: UserToRPC(dbUser),
|
||||
Organizations: rpcOrgs,
|
||||
})
|
||||
@@ -65,13 +66,13 @@ func (h *OrganizationHandler) GetCallerOrganizations(
|
||||
func (h *OrganizationHandler) CreateCallerOrganization(
|
||||
ctx context.Context,
|
||||
req *connect.Request[holos.CreateCallerOrganizationRequest],
|
||||
) (*connect.Response[holos.GetCallerOrganizationsResponse], error) {
|
||||
) (*connect.Response[holos.CreateCallerOrganizationResponse], error) {
|
||||
log := logger.FromContext(ctx)
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
// todo get user by iss, sub
|
||||
dbUser, err := getUser(ctx, h.db, authnID.Email())
|
||||
dbUser, err := getUser(ctx, h.db, authnID.Issuer(), authnID.Subject())
|
||||
if err != nil {
|
||||
if ent.MaskNotFound(err) == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, errors.Wrap(err))
|
||||
@@ -90,14 +91,14 @@ func (h *OrganizationHandler) CreateCallerOrganization(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbUser, err = dbUser.Update().
|
||||
AddOrganizations(org).
|
||||
Save(ctx)
|
||||
return err
|
||||
return tx.Organization.UpdateOne(org).AddUsers(dbUser).Exec(ctx)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeInternal, errors.Wrap(err))
|
||||
}
|
||||
log = log.With("organization", org)
|
||||
|
||||
log.InfoContext(ctx, "created organization")
|
||||
|
||||
// TODO: prefetch organizations
|
||||
dbOrgs, err := dbUser.QueryOrganizations().All(ctx)
|
||||
@@ -109,7 +110,7 @@ func (h *OrganizationHandler) CreateCallerOrganization(
|
||||
rpcOrgs = append(rpcOrgs, OrganizationToRPC(dbOrg))
|
||||
}
|
||||
|
||||
res := connect.NewResponse(&holos.GetCallerOrganizationsResponse{
|
||||
res := connect.NewResponse(&holos.CreateCallerOrganizationResponse{
|
||||
User: UserToRPC(dbUser),
|
||||
Organizations: rpcOrgs,
|
||||
})
|
||||
|
||||
@@ -3,15 +3,17 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/holos-run/holos/internal/ent"
|
||||
"github.com/holos-run/holos/internal/ent/organization"
|
||||
entplatform "github.com/holos-run/holos/internal/ent/platform"
|
||||
"github.com/holos-run/holos/internal/ent/user"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/server/middleware/authn"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// NewPlatformHandler returns a new PlatformService implementation.
|
||||
@@ -24,23 +26,24 @@ type PlatformHandler struct {
|
||||
db *ent.Client
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) GetPlatforms(
|
||||
func (h *PlatformHandler) ListPlatforms(
|
||||
ctx context.Context,
|
||||
req *connect.Request[holos.GetPlatformsRequest],
|
||||
) (*connect.Response[holos.GetPlatformsResponse], error) {
|
||||
req *connect.Request[holos.ListPlatformsRequest],
|
||||
) (*connect.Response[holos.ListPlatformsResponse], error) {
|
||||
_, reqDBOrg, err := getAuthnUsersOrg(ctx, req.Msg.OrgId, h.db)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
|
||||
return getPlatformsResponse(reqDBOrg), nil
|
||||
resp := &holos.ListPlatformsResponse{Platforms: rpcPlatforms(reqDBOrg)}
|
||||
return connect.NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) AddPlatform(
|
||||
ctx context.Context,
|
||||
req *connect.Request[holos.AddPlatformRequest],
|
||||
) (*connect.Response[holos.GetPlatformsResponse], error) {
|
||||
dbUser, dbOrg, err := getAuthnUsersOrg(ctx, req.Msg.OrgId, h.db)
|
||||
) (*connect.Response[holos.AddPlatformResponse], error) {
|
||||
dbUser, dbOrg, err := getAuthnUsersOrg(ctx, req.Msg.Platform.OrgId, h.db)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
@@ -48,17 +51,129 @@ func (h *PlatformHandler) AddPlatform(
|
||||
platform, err := h.db.Platform.Create().
|
||||
SetOrgID(dbOrg.ID).
|
||||
SetCreatorID(dbUser.ID).
|
||||
SetName(req.Msg.Name).
|
||||
SetDisplayName(req.Msg.DisplayName).
|
||||
SetName(req.Msg.Platform.Name).
|
||||
SetDisplayName(req.Msg.Platform.DisplayName).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
|
||||
}
|
||||
|
||||
resp := getPlatformsResponse(dbOrg)
|
||||
resp.Msg.Platforms = append(resp.Msg.Platforms, PlatformToRPC(platform))
|
||||
resp := &holos.AddPlatformResponse{Platforms: rpcPlatforms(dbOrg)}
|
||||
resp.Platforms = append(resp.Platforms, PlatformToRPC(platform))
|
||||
|
||||
return resp, nil
|
||||
return connect.NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) getPlatform(ctx context.Context, id string, uid authn.Identity) (*ent.Platform, error) {
|
||||
platformID, err := uuid.FromString(id)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeInvalidArgument, errors.Wrap(err))
|
||||
}
|
||||
|
||||
p, err := h.db.Platform.Query().
|
||||
Where(entplatform.ID(platformID)).
|
||||
Where(entplatform.HasOrganizationWith(
|
||||
organization.HasUsersWith(
|
||||
user.Iss(uid.Issuer()),
|
||||
user.Sub(uid.Subject()),
|
||||
))).
|
||||
Only(ctx)
|
||||
if err != nil {
|
||||
if ent.MaskNotFound(err) == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
|
||||
}
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) GetPlatform(ctx context.Context, req *connect.Request[holos.GetPlatformRequest]) (*connect.Response[holos.GetPlatformResponse], error) {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
|
||||
p, err := h.getPlatform(ctx, req.Msg.PlatformId, authnID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
|
||||
return connect.NewResponse(&holos.GetPlatformResponse{Platform: PlatformToRPC(p)}), nil
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) PutModel(ctx context.Context, req *connect.Request[holos.PutModelRequest]) (*connect.Response[holos.PutModelResponse], error) {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
|
||||
p, err := h.getPlatform(ctx, req.Msg.GetPlatformId(), authnID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
|
||||
slog.WarnContext(ctx, "todo: validate the platform config against cue definitions", "action", "todo", "cue", len(p.Cue))
|
||||
|
||||
_, err = p.Update().
|
||||
SetModel(&holos.Model{Model: req.Msg.GetModel()}).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
|
||||
}
|
||||
|
||||
return connect.NewResponse(&holos.PutModelResponse{Model: req.Msg.Model}), nil
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) GetModel(ctx context.Context, req *connect.Request[holos.GetModelRequest]) (*connect.Response[holos.GetModelResponse], error) {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
|
||||
p, err := h.getPlatform(ctx, req.Msg.PlatformId, authnID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
|
||||
return connect.NewResponse(&holos.GetModelResponse{Model: p.Model.Model}), nil
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) GetForm(ctx context.Context, req *connect.Request[holos.GetFormRequest]) (*connect.Response[holos.GetFormResponse], error) {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
|
||||
p, err := h.getPlatform(ctx, req.Msg.GetPlatformId(), authnID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
|
||||
return connect.NewResponse(&holos.GetFormResponse{Fields: p.Form.GetFields(), Model: p.Model.GetModel()}), nil
|
||||
}
|
||||
|
||||
func (h *PlatformHandler) PutForm(ctx context.Context, req *connect.Request[holos.PutFormRequest]) (*connect.Response[holos.PutFormResponse], error) {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
|
||||
p, err := h.getPlatform(ctx, req.Msg.GetPlatformId(), authnID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
|
||||
_, err = p.Update().
|
||||
SetForm(&holos.Form{Fields: req.Msg.GetFields()}).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
|
||||
}
|
||||
|
||||
resp := &holos.PutFormResponse{Fields: req.Msg.GetFields()}
|
||||
return connect.NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func PlatformToRPC(platform *ent.Platform) *holos.Platform {
|
||||
@@ -66,13 +181,8 @@ func PlatformToRPC(platform *ent.Platform) *holos.Platform {
|
||||
Id: platform.ID.String(),
|
||||
Name: platform.Name,
|
||||
DisplayName: platform.DisplayName,
|
||||
Timestamps: &holos.Timestamps{
|
||||
CreatedAt: timestamppb.New(platform.CreatedAt),
|
||||
UpdatedAt: timestamppb.New(platform.UpdatedAt),
|
||||
},
|
||||
Creator: &holos.Creator{
|
||||
Id: platform.CreatorID.String(),
|
||||
},
|
||||
OrgId: platform.OrgID.String(),
|
||||
Spec: &holos.PlatformSpec{Model: platform.Model.GetModel()},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +211,7 @@ func getAuthnUsersOrg(ctx context.Context, orgID string, db *ent.Client) (*ent.U
|
||||
return nil, nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
|
||||
// Check the user is a member of the organization.
|
||||
var reqDBOrg *ent.Organization
|
||||
wantOrgIDs := make([]uuid.UUID, 0, len(dbUser.Edges.Organizations))
|
||||
for _, org := range dbUser.Edges.Organizations {
|
||||
@@ -123,15 +234,14 @@ func getAuthnUsersOrg(ctx context.Context, orgID string, db *ent.Client) (*ent.U
|
||||
return dbUser, reqDBOrg, nil
|
||||
}
|
||||
|
||||
func getPlatformsResponse(reqDBOrg *ent.Organization) *connect.Response[holos.GetPlatformsResponse] {
|
||||
// one extra in case a new platform is appended.
|
||||
rpcPlatforms := make([]*holos.Platform, 0, 1+len(reqDBOrg.Edges.Platforms))
|
||||
for _, platform := range reqDBOrg.Edges.Platforms {
|
||||
rpcPlatforms = append(rpcPlatforms, PlatformToRPC(platform))
|
||||
func rpcPlatforms(reqDBOrg *ent.Organization) []*holos.Platform {
|
||||
if reqDBOrg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return connect.NewResponse(&holos.GetPlatformsResponse{
|
||||
OrgId: reqDBOrg.ID.String(),
|
||||
Platforms: rpcPlatforms,
|
||||
})
|
||||
// one extra in case a new platform is appended.
|
||||
platforms := make([]*holos.Platform, 0, 1+len(reqDBOrg.Edges.Platforms))
|
||||
for _, platform := range reqDBOrg.Edges.Platforms {
|
||||
platforms = append(platforms, PlatformToRPC(platform))
|
||||
}
|
||||
return platforms
|
||||
}
|
||||
|
||||
900
internal/server/handler/system.go
Normal file
900
internal/server/handler/system.go
Normal file
@@ -0,0 +1,900 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/holos-run/holos/internal/ent"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/server/middleware/authn"
|
||||
"github.com/holos-run/holos/internal/server/middleware/logger"
|
||||
holos "github.com/holos-run/holos/service/gen/holos/v1alpha1"
|
||||
)
|
||||
|
||||
const AdminEmail = "jeff@openinfrastructure.co"
|
||||
|
||||
// NewSystemHandler returns a new SystemService implementation.
|
||||
func NewSystemHandler(db *ent.Client) *SystemHandler {
|
||||
return &SystemHandler{db: db}
|
||||
}
|
||||
|
||||
// SystemHandler implements the PlatformService interface.
|
||||
type SystemHandler struct {
|
||||
db *ent.Client
|
||||
}
|
||||
|
||||
func (h *SystemHandler) checkAdmin(ctx context.Context) error {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
if authnID.Email() != AdminEmail {
|
||||
err := fmt.Errorf("not an admin:\n\thave (%+v)\n\twant (%+v)", authnID.Email(), AdminEmail)
|
||||
return connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SystemHandler) DropTables(ctx context.Context, req *connect.Request[holos.DropTablesRequest]) (*connect.Response[holos.DropTablesResponse], error) {
|
||||
if err := h.checkAdmin(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log := logger.FromContext(ctx)
|
||||
|
||||
if err := WithTx(ctx, h.db, func(tx *ent.Tx) (err error) {
|
||||
var n int
|
||||
if n, err = tx.Platform.Delete().Exec(ctx); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
log.WarnContext(ctx, "deleted platforms", "count", n)
|
||||
if n, err = tx.Organization.Delete().Exec(ctx); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
log.WarnContext(ctx, "deleted organizations", "count", n)
|
||||
if n, err = tx.User.Delete().Exec(ctx); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
log.WarnContext(ctx, "deleted users", "count", n)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
|
||||
}
|
||||
|
||||
return connect.NewResponse(&holos.DropTablesResponse{}), nil
|
||||
}
|
||||
|
||||
func (h *SystemHandler) SeedDatabase(ctx context.Context, req *connect.Request[holos.SeedDatabaseRequest]) (*connect.Response[holos.SeedDatabaseResponse], error) {
|
||||
if err := h.checkAdmin(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := WithTx(ctx, h.db, func(tx *ent.Tx) (err error) {
|
||||
jeff, err := tx.User.Create().
|
||||
SetID(uuid.FromStringOrNil("018f36fb-e3f2-7f7f-a72f-ce48eb16c82d")).
|
||||
SetEmail("jeff@openinfrastructure.co").
|
||||
SetIss("https://login.ois.run").
|
||||
SetSub("261773693724656988").
|
||||
SetName("Jeff McCune").
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
nate, err := tx.User.Create().
|
||||
SetEmail("nate@openinfrastructure.co").
|
||||
SetIss("https://login.ois.run").
|
||||
SetSub("261775487611699776").
|
||||
SetName("Nate McCurdy").
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
gary, err := tx.User.Create().
|
||||
SetEmail("gary@openinfrastructure.co").
|
||||
SetIss("https://login.ois.run").
|
||||
SetSub("261775531836441152").
|
||||
SetName("Gary Larizza").
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
// Create the org
|
||||
org, err := tx.Organization.Create().
|
||||
SetID(uuid.FromStringOrNil("018f36fb-e3f7-7f7f-a1c5-c85fb735d215")).
|
||||
SetName("ois").
|
||||
SetDisplayName("Open Infrastructure Services").
|
||||
SetCreator(jeff).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
// Add org memebers
|
||||
org, err = org.Update().AddUsers(jeff, gary, nate).Save(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
var form holos.Form
|
||||
if err := json.Unmarshal([]byte(BareForm), &form); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
var model holos.Model
|
||||
if err := json.Unmarshal([]byte(Model), &model); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
// Add a platform
|
||||
err = tx.Platform.Create().
|
||||
SetID(uuid.FromStringOrNil("018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94")).
|
||||
SetName("bare").
|
||||
SetDisplayName("Bare Platform").
|
||||
SetForm(&form).
|
||||
SetModel(&model).
|
||||
SetCreator(jeff).
|
||||
SetOrgID(org.ID).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
stuff := []string{"Jeff", "Gary", "Nate"}
|
||||
for _, name := range stuff {
|
||||
err := tx.Platform.Create().
|
||||
SetName(strings.ToLower(name)).
|
||||
SetDisplayName(name + "'s Platform").
|
||||
SetForm(&form).
|
||||
SetModel(&model).
|
||||
SetCreator(jeff).
|
||||
SetOrgID(org.ID).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
|
||||
}
|
||||
|
||||
return connect.NewResponse(&holos.SeedDatabaseResponse{}), nil
|
||||
}
|
||||
|
||||
const Model = `{"model":{}}`
|
||||
|
||||
const BareForm = `
|
||||
{
|
||||
"fields": [
|
||||
{
|
||||
"key": "org",
|
||||
"wrappers": [
|
||||
"holos-panel"
|
||||
],
|
||||
"props": {
|
||||
"label": "Organization",
|
||||
"description": "Organization config values are used to derive more specific configuration values throughout the platform."
|
||||
},
|
||||
"resetOnHide": true,
|
||||
"fieldGroup": [
|
||||
{
|
||||
"key": "name",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Name",
|
||||
"description": "DNS label, e.g. 'example'",
|
||||
"pattern": "^[a-z]([0-9a-z]|-){1,28}[0-9a-z]$",
|
||||
"minLength": 3,
|
||||
"maxLength": 30,
|
||||
"required": true
|
||||
},
|
||||
"validation": {
|
||||
"messages": {
|
||||
"pattern": "It must be 3 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited."
|
||||
}
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "domain",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Domain",
|
||||
"placeholder": "example.com",
|
||||
"minLength": 3,
|
||||
"maxLength": 100,
|
||||
"description": "DNS domain, e.g. 'example.com'",
|
||||
"required": true
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "displayName",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Display Name",
|
||||
"placeholder": "Example Organization",
|
||||
"description": "Display name, e.g. 'Example Organization'",
|
||||
"maxLength": 100,
|
||||
"required": true
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "contactEmail",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Contact Email",
|
||||
"placeholder": "platform-team@example.com",
|
||||
"description": "Technical contact email address",
|
||||
"required": true
|
||||
},
|
||||
"resetOnHide": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "cloud",
|
||||
"wrappers": [
|
||||
"holos-panel"
|
||||
],
|
||||
"props": {
|
||||
"label": "Cloud Providers",
|
||||
"description": "Select the services that provide resources for the platform."
|
||||
},
|
||||
"resetOnHide": true,
|
||||
"fieldGroup": [
|
||||
{
|
||||
"key": "providers",
|
||||
"type": "select",
|
||||
"props": {
|
||||
"label": "Select Providers",
|
||||
"description": "Select the cloud providers the platform builds upon.",
|
||||
"multiple": true,
|
||||
"selectAllOption": "Select All",
|
||||
"options": [
|
||||
{
|
||||
"value": "aws",
|
||||
"label": "Amazon Web Services"
|
||||
},
|
||||
{
|
||||
"value": "gcp",
|
||||
"label": "Google Cloud Platform"
|
||||
},
|
||||
{
|
||||
"value": "azure",
|
||||
"label": "Microsoft Azure"
|
||||
},
|
||||
{
|
||||
"value": "cloudflare",
|
||||
"label": "Cloudflare"
|
||||
},
|
||||
{
|
||||
"value": "github",
|
||||
"label": "GitHub"
|
||||
},
|
||||
{
|
||||
"value": "ois",
|
||||
"label": "Open Infrastructure Services"
|
||||
},
|
||||
{
|
||||
"value": "onprem",
|
||||
"label": "On Premises",
|
||||
"disabled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"resetOnHide": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "aws",
|
||||
"wrappers": [
|
||||
"holos-panel"
|
||||
],
|
||||
"props": {
|
||||
"label": "Amazon Web Services",
|
||||
"description": "Provide the information necessary for Holos to manage AWS resources to provide the platform."
|
||||
},
|
||||
"expressions": {
|
||||
"hide": "!formState.model.cloud?.providers?.includes(\"aws\")"
|
||||
},
|
||||
"resetOnHide": true,
|
||||
"fieldGroup": [
|
||||
{
|
||||
"key": "primaryRoleARN",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Holos Admin Role ARN",
|
||||
"description": "Enter the AWS Role ARN Holos will use to bootstrap resources. For example, arn:aws:iam::123456789012:role/HolosAdminAccess",
|
||||
"pattern": "^arn:.*",
|
||||
"minLength": 4,
|
||||
"required": true
|
||||
},
|
||||
"validation": {
|
||||
"messages": {
|
||||
"pattern": "Must be a valid ARN. Refer to https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html"
|
||||
}
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "regions",
|
||||
"type": "select",
|
||||
"props": {
|
||||
"label": "Select Regions",
|
||||
"description": "Select the AWS regions this platform operates in.",
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"selectAllOption": "Select All",
|
||||
"options": [
|
||||
{
|
||||
"value": "us-east-1",
|
||||
"label": "N. Virginia (us-east-1)"
|
||||
},
|
||||
{
|
||||
"value": "us-east-2",
|
||||
"label": "Ohio (us-east-2)"
|
||||
},
|
||||
{
|
||||
"value": "us-west-1",
|
||||
"label": "N. California (us-west-1)"
|
||||
},
|
||||
{
|
||||
"value": "us-west-2",
|
||||
"label": "Oregon (us-west-2)"
|
||||
},
|
||||
{
|
||||
"value": "us-gov-west1",
|
||||
"label": "US GovCloud West (us-gov-west1)"
|
||||
},
|
||||
{
|
||||
"value": "us-gov-east1",
|
||||
"label": "US GovCloud East (us-gov-east1)"
|
||||
},
|
||||
{
|
||||
"value": "ca-central-1",
|
||||
"label": "Canada (ca-central-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-north-1",
|
||||
"label": "Stockholm (eu-north-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-west-1",
|
||||
"label": "Ireland (eu-west-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-west-2",
|
||||
"label": "London (eu-west-2)"
|
||||
},
|
||||
{
|
||||
"value": "eu-west-3",
|
||||
"label": "Paris (eu-west-3)"
|
||||
},
|
||||
{
|
||||
"value": "eu-central-1",
|
||||
"label": "Frankfurt (eu-central-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-south-1",
|
||||
"label": "Milan (eu-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "af-south-1",
|
||||
"label": "Cape Town (af-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-northeast-1",
|
||||
"label": "Tokyo (ap-northeast-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-northeast-2",
|
||||
"label": "Seoul (ap-northeast-2)"
|
||||
},
|
||||
{
|
||||
"value": "ap-northeast-3",
|
||||
"label": "Osaka (ap-northeast-3)"
|
||||
},
|
||||
{
|
||||
"value": "ap-southeast-1",
|
||||
"label": "Singapore (ap-southeast-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-southeast-2",
|
||||
"label": "Sydney (ap-southeast-2)"
|
||||
},
|
||||
{
|
||||
"value": "ap-east-1",
|
||||
"label": "Hong Kong (ap-east-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-south-1",
|
||||
"label": "Mumbai (ap-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "me-south-1",
|
||||
"label": "Bahrain (me-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "sa-east-1",
|
||||
"label": "São Paulo (sa-east-1)"
|
||||
},
|
||||
{
|
||||
"value": "cn-north-1",
|
||||
"label": "Bejing (cn-north-1)"
|
||||
},
|
||||
{
|
||||
"value": "cn-northwest-1",
|
||||
"label": "Ningxia (cn-northwest-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-southeast-3",
|
||||
"label": "Jakarta (ap-southeast-3)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resetOnHide": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "gcp",
|
||||
"wrappers": [
|
||||
"holos-panel"
|
||||
],
|
||||
"props": {
|
||||
"label": "Google Cloud Platform",
|
||||
"description": "Use this form to configure platform level GCP settings."
|
||||
},
|
||||
"expressions": {
|
||||
"hide": "!formState.model.cloud?.providers?.includes(\"gcp\")"
|
||||
},
|
||||
"resetOnHide": true,
|
||||
"fieldGroup": [
|
||||
{
|
||||
"key": "regions",
|
||||
"type": "select",
|
||||
"props": {
|
||||
"label": "Select Regions",
|
||||
"description": "Select the GCP regions this platform operates in.",
|
||||
"multiple": true,
|
||||
"selectAllOption": "Select All",
|
||||
"options": [
|
||||
{
|
||||
"value": "africa-south1",
|
||||
"label": "africa-south1"
|
||||
},
|
||||
{
|
||||
"value": "asia-east1",
|
||||
"label": "asia-east1"
|
||||
},
|
||||
{
|
||||
"value": "asia-east2",
|
||||
"label": "asia-east2"
|
||||
},
|
||||
{
|
||||
"value": "asia-northeast1",
|
||||
"label": "asia-northeast1"
|
||||
},
|
||||
{
|
||||
"value": "asia-northeast2",
|
||||
"label": "asia-northeast2"
|
||||
},
|
||||
{
|
||||
"value": "asia-northeast3",
|
||||
"label": "asia-northeast3"
|
||||
},
|
||||
{
|
||||
"value": "asia-south1",
|
||||
"label": "asia-south1"
|
||||
},
|
||||
{
|
||||
"value": "asia-south2",
|
||||
"label": "asia-south2"
|
||||
},
|
||||
{
|
||||
"value": "asia-southeast1",
|
||||
"label": "asia-southeast1"
|
||||
},
|
||||
{
|
||||
"value": "asia-southeast2",
|
||||
"label": "asia-southeast2"
|
||||
},
|
||||
{
|
||||
"value": "australia-southeast1",
|
||||
"label": "australia-southeast1"
|
||||
},
|
||||
{
|
||||
"value": "australia-southeast2",
|
||||
"label": "australia-southeast2"
|
||||
},
|
||||
{
|
||||
"value": "europe-central2",
|
||||
"label": "europe-central2"
|
||||
},
|
||||
{
|
||||
"value": "europe-north1",
|
||||
"label": "europe-north1"
|
||||
},
|
||||
{
|
||||
"value": "europe-southwest1",
|
||||
"label": "europe-southwest1"
|
||||
},
|
||||
{
|
||||
"value": "europe-west1",
|
||||
"label": "europe-west1"
|
||||
},
|
||||
{
|
||||
"value": "europe-west10",
|
||||
"label": "europe-west10"
|
||||
},
|
||||
{
|
||||
"value": "europe-west12",
|
||||
"label": "europe-west12"
|
||||
},
|
||||
{
|
||||
"value": "europe-west2",
|
||||
"label": "europe-west2"
|
||||
},
|
||||
{
|
||||
"value": "europe-west3",
|
||||
"label": "europe-west3"
|
||||
},
|
||||
{
|
||||
"value": "europe-west4",
|
||||
"label": "europe-west4"
|
||||
},
|
||||
{
|
||||
"value": "europe-west6",
|
||||
"label": "europe-west6"
|
||||
},
|
||||
{
|
||||
"value": "europe-west8",
|
||||
"label": "europe-west8"
|
||||
},
|
||||
{
|
||||
"value": "europe-west9",
|
||||
"label": "europe-west9"
|
||||
},
|
||||
{
|
||||
"value": "me-central1",
|
||||
"label": "me-central1"
|
||||
},
|
||||
{
|
||||
"value": "me-central2",
|
||||
"label": "me-central2"
|
||||
},
|
||||
{
|
||||
"value": "me-west1",
|
||||
"label": "me-west1"
|
||||
},
|
||||
{
|
||||
"value": "northamerica-northeast1",
|
||||
"label": "northamerica-northeast1"
|
||||
},
|
||||
{
|
||||
"value": "northamerica-northeast2",
|
||||
"label": "northamerica-northeast2"
|
||||
},
|
||||
{
|
||||
"value": "southamerica-east1",
|
||||
"label": "southamerica-east1"
|
||||
},
|
||||
{
|
||||
"value": "southamerica-west1",
|
||||
"label": "southamerica-west1"
|
||||
},
|
||||
{
|
||||
"value": "us-central1",
|
||||
"label": "us-central1"
|
||||
},
|
||||
{
|
||||
"value": "us-east1",
|
||||
"label": "us-east1"
|
||||
},
|
||||
{
|
||||
"value": "us-east4",
|
||||
"label": "us-east4"
|
||||
},
|
||||
{
|
||||
"value": "us-east5",
|
||||
"label": "us-east5"
|
||||
},
|
||||
{
|
||||
"value": "us-south1",
|
||||
"label": "us-south1"
|
||||
},
|
||||
{
|
||||
"value": "us-west1",
|
||||
"label": "us-west1"
|
||||
},
|
||||
{
|
||||
"value": "us-west2",
|
||||
"label": "us-west2"
|
||||
},
|
||||
{
|
||||
"value": "us-west3",
|
||||
"label": "us-west3"
|
||||
},
|
||||
{
|
||||
"value": "us-west4",
|
||||
"label": "us-west4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "gcpProjectID",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Project ID",
|
||||
"description": "Enter the project id where the provisioner cluster resides.",
|
||||
"pattern": "^[a-z]([0-9a-z]|-){1,28}[0-9a-z]$",
|
||||
"minLength": 6,
|
||||
"maxLength": 30,
|
||||
"required": true
|
||||
},
|
||||
"validation": {
|
||||
"messages": {
|
||||
"pattern": "It must be 3 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited."
|
||||
}
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "gcpProjectNumber",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Project Number",
|
||||
"type": "number",
|
||||
"description": "Enter the project number where the provisioner cluster resides.",
|
||||
"pattern": "^[0-9]+$",
|
||||
"required": true
|
||||
},
|
||||
"validation": {
|
||||
"messages": {
|
||||
"pattern": "Must be a valid project number."
|
||||
}
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "provisionerCABundle",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Provisioner CA Bundle",
|
||||
"description": "Enter the provisioner cluster ca bundle. kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.certificate-authority-data}'",
|
||||
"pattern": "^[0-9a-zA-Z]+=*$",
|
||||
"required": true
|
||||
},
|
||||
"validation": {
|
||||
"messages": {
|
||||
"pattern": "Must be a base64 encoded pem encoded certificate bundle."
|
||||
}
|
||||
},
|
||||
"resetOnHide": true
|
||||
},
|
||||
{
|
||||
"key": "provisionerURL",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Provisioner URL",
|
||||
"description": "Enter the URL of the provisioner cluster API endpoint. kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.server}'",
|
||||
"pattern": "^https://.*$",
|
||||
"required": true
|
||||
},
|
||||
"validation": {
|
||||
"messages": {
|
||||
"pattern": "Must be a https:// URL."
|
||||
}
|
||||
},
|
||||
"resetOnHide": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "cloudflare",
|
||||
"wrappers": [
|
||||
"holos-panel"
|
||||
],
|
||||
"props": {
|
||||
"label": "Cloudflare",
|
||||
"description": "Cloudflare is primarily used for DNS automation."
|
||||
},
|
||||
"expressions": {
|
||||
"hide": "!formState.model.cloud?.providers?.includes(\"cloudflare\")"
|
||||
},
|
||||
"resetOnHide": true,
|
||||
"fieldGroup": [
|
||||
{
|
||||
"key": "email",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Account Email",
|
||||
"description": "Enter the Cloudflare email address to manage DNS",
|
||||
"minLength": 3,
|
||||
"required": true
|
||||
},
|
||||
"resetOnHide": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "github",
|
||||
"wrappers": [
|
||||
"holos-panel"
|
||||
],
|
||||
"props": {
|
||||
"label": "GitHub",
|
||||
"description": "GitHub is primarily used to host Git repositories and execute Actions workflows."
|
||||
},
|
||||
"expressions": {
|
||||
"hide": "!formState.model.cloud?.providers?.includes(\"github\")"
|
||||
},
|
||||
"resetOnHide": true,
|
||||
"fieldGroup": [
|
||||
{
|
||||
"key": "primaryOrg",
|
||||
"type": "input",
|
||||
"props": {
|
||||
"label": "Organization",
|
||||
"description": "Enter the primary GitHub organization associed with the platform.",
|
||||
"pattern": "^(?!-)(?!.*--)([a-zA-Z0-9]|-){1,39}$",
|
||||
"minLength": 1,
|
||||
"maxLength": 39,
|
||||
"required": true
|
||||
},
|
||||
"validation": {
|
||||
"messages": {
|
||||
"pattern": "All characters must be either a hyphen or alphanumeric. Cannot start with a hyphen. Cannot include consecutive hyphens."
|
||||
}
|
||||
},
|
||||
"resetOnHide": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "backups",
|
||||
"wrappers": [
|
||||
"holos-panel"
|
||||
],
|
||||
"props": {
|
||||
"label": "Backups",
|
||||
"description": "Configure platform level data backup settings. Requires AWS."
|
||||
},
|
||||
"resetOnHide": true,
|
||||
"fieldGroup": [
|
||||
{
|
||||
"key": "s3bucket",
|
||||
"type": "select",
|
||||
"props": {
|
||||
"label": "S3 Bucket Region",
|
||||
"description": "Select the S3 Bucket Region.",
|
||||
"multiple": true,
|
||||
"options": [
|
||||
{
|
||||
"value": "us-east-1",
|
||||
"label": "N. Virginia (us-east-1)"
|
||||
},
|
||||
{
|
||||
"value": "us-east-2",
|
||||
"label": "Ohio (us-east-2)"
|
||||
},
|
||||
{
|
||||
"value": "us-west-1",
|
||||
"label": "N. California (us-west-1)"
|
||||
},
|
||||
{
|
||||
"value": "us-west-2",
|
||||
"label": "Oregon (us-west-2)"
|
||||
},
|
||||
{
|
||||
"value": "us-gov-west1",
|
||||
"label": "US GovCloud West (us-gov-west1)"
|
||||
},
|
||||
{
|
||||
"value": "us-gov-east1",
|
||||
"label": "US GovCloud East (us-gov-east1)"
|
||||
},
|
||||
{
|
||||
"value": "ca-central-1",
|
||||
"label": "Canada (ca-central-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-north-1",
|
||||
"label": "Stockholm (eu-north-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-west-1",
|
||||
"label": "Ireland (eu-west-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-west-2",
|
||||
"label": "London (eu-west-2)"
|
||||
},
|
||||
{
|
||||
"value": "eu-west-3",
|
||||
"label": "Paris (eu-west-3)"
|
||||
},
|
||||
{
|
||||
"value": "eu-central-1",
|
||||
"label": "Frankfurt (eu-central-1)"
|
||||
},
|
||||
{
|
||||
"value": "eu-south-1",
|
||||
"label": "Milan (eu-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "af-south-1",
|
||||
"label": "Cape Town (af-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-northeast-1",
|
||||
"label": "Tokyo (ap-northeast-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-northeast-2",
|
||||
"label": "Seoul (ap-northeast-2)"
|
||||
},
|
||||
{
|
||||
"value": "ap-northeast-3",
|
||||
"label": "Osaka (ap-northeast-3)"
|
||||
},
|
||||
{
|
||||
"value": "ap-southeast-1",
|
||||
"label": "Singapore (ap-southeast-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-southeast-2",
|
||||
"label": "Sydney (ap-southeast-2)"
|
||||
},
|
||||
{
|
||||
"value": "ap-east-1",
|
||||
"label": "Hong Kong (ap-east-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-south-1",
|
||||
"label": "Mumbai (ap-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "me-south-1",
|
||||
"label": "Bahrain (me-south-1)"
|
||||
},
|
||||
{
|
||||
"value": "sa-east-1",
|
||||
"label": "São Paulo (sa-east-1)"
|
||||
},
|
||||
{
|
||||
"value": "cn-north-1",
|
||||
"label": "Bejing (cn-north-1)"
|
||||
},
|
||||
{
|
||||
"value": "cn-northwest-1",
|
||||
"label": "Ningxia (cn-northwest-1)"
|
||||
},
|
||||
{
|
||||
"value": "ap-southeast-3",
|
||||
"label": "Jakarta (ap-southeast-3)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"expressions": {
|
||||
"props.disabled": "!formState.model.cloud?.providers?.includes(\"aws\")",
|
||||
"props.required": "formState.model.cloud?.providers?.includes(\"aws\")",
|
||||
"props.description": "formState.model.cloud?.providers?.includes(\"aws\") ? 'Select the S3 Bucket Region.' : 'Enable AWS in the Cloud Provider section to configure backups.'"
|
||||
},
|
||||
"resetOnHide": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
@@ -56,7 +56,7 @@ func (h *UserHandler) GetCallerUser(
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
}
|
||||
dbUser, err := getUser(ctx, h.db, authnID.Email())
|
||||
dbUser, err := getUser(ctx, h.db, authnID.Issuer(), authnID.Subject())
|
||||
if err != nil {
|
||||
if ent.MaskNotFound(err) == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, errors.Wrap(err))
|
||||
@@ -68,10 +68,7 @@ func (h *UserHandler) GetCallerUser(
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (h *UserHandler) CreateCallerUser(
|
||||
ctx context.Context,
|
||||
req *connect.Request[holos.CreateCallerUserRequest],
|
||||
) (*connect.Response[holos.CreateCallerUserResponse], error) {
|
||||
func (h *UserHandler) createCallerUser(ctx context.Context) (*ent.User, error) {
|
||||
authnID, err := authn.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
|
||||
@@ -87,6 +84,18 @@ func (h *UserHandler) CreateCallerUser(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return createdUser, nil
|
||||
}
|
||||
|
||||
func (h *UserHandler) CreateCallerUser(
|
||||
ctx context.Context,
|
||||
req *connect.Request[holos.CreateCallerUserRequest],
|
||||
) (*connect.Response[holos.CreateCallerUserResponse], error) {
|
||||
createdUser, err := h.createCallerUser(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := connect.NewResponse(&holos.CreateCallerUserResponse{
|
||||
User: UserToRPC(createdUser),
|
||||
})
|
||||
@@ -107,11 +116,16 @@ func UserToRPC(u *ent.User) *holos.User {
|
||||
return &iamUser
|
||||
}
|
||||
|
||||
func getUser(ctx context.Context, client *ent.Client, email string) (*ent.User, error) {
|
||||
func getUser(ctx context.Context, client *ent.Client, iss string, sub string) (*ent.User, error) {
|
||||
log := logger.FromContext(ctx)
|
||||
user, err := client.User.Query().Where(user.Email(email)).Only(ctx)
|
||||
user, err := client.User.Query().
|
||||
Where(
|
||||
user.Iss(iss),
|
||||
user.Sub(sub),
|
||||
).
|
||||
Only(ctx)
|
||||
if err != nil {
|
||||
log.DebugContext(ctx, "could not get user", "err", err, "email", email)
|
||||
log.DebugContext(ctx, "could not get user", "err", err, "iss", iss, "sub", sub)
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
return user, nil
|
||||
|
||||
@@ -115,11 +115,13 @@ func (s *Server) registerConnectRpc() error {
|
||||
s.handle(holosconnect.NewUserServiceHandler(handler.NewUserHandler(s.db), opts))
|
||||
s.handle(holosconnect.NewOrganizationServiceHandler(handler.NewOrganizationHandler(s.db), opts))
|
||||
s.handle(holosconnect.NewPlatformServiceHandler(handler.NewPlatformHandler(s.db), opts))
|
||||
s.handle(holosconnect.NewSystemServiceHandler(handler.NewSystemHandler(s.db), opts))
|
||||
|
||||
reflector := grpcreflect.NewStaticReflector(
|
||||
holosconnect.UserServiceName,
|
||||
holosconnect.OrganizationServiceName,
|
||||
holosconnect.PlatformServiceName,
|
||||
holosconnect.SystemServiceName,
|
||||
)
|
||||
|
||||
s.mux.Handle(grpcreflect.NewHandlerV1(reflector))
|
||||
|
||||
@@ -20,16 +20,21 @@ message Organization {
|
||||
Creator creator = 5;
|
||||
}
|
||||
|
||||
message GetCallerOrganizationsRequest {}
|
||||
message ListCallerOrganizationsRequest {}
|
||||
|
||||
message GetCallerOrganizationsResponse {
|
||||
message ListCallerOrganizationsResponse {
|
||||
User user = 1;
|
||||
repeated Organization organizations = 2;
|
||||
}
|
||||
|
||||
message CreateCallerOrganizationRequest {}
|
||||
|
||||
service OrganizationService {
|
||||
rpc GetCallerOrganizations(GetCallerOrganizationsRequest) returns (GetCallerOrganizationsResponse) {}
|
||||
rpc CreateCallerOrganization(CreateCallerOrganizationRequest) returns (GetCallerOrganizationsResponse) {}
|
||||
message CreateCallerOrganizationResponse {
|
||||
User user = 1;
|
||||
repeated Organization organizations = 2;
|
||||
}
|
||||
|
||||
service OrganizationService {
|
||||
rpc ListCallerOrganizations(ListCallerOrganizationsRequest) returns (ListCallerOrganizationsResponse) {}
|
||||
rpc CreateCallerOrganization(CreateCallerOrganizationRequest) returns (CreateCallerOrganizationResponse) {}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,111 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package holos.v1alpha1;
|
||||
|
||||
option go_package = "github.com/holos-run/holos/service/gen/holos/v1alpha1;holos";
|
||||
|
||||
// git clone https://github.com/bufbuild/protovalidate then add <parent>/protovalidate/proto/protovalidate to your editor proto search path
|
||||
import "buf/validate/validate.proto";
|
||||
import "holos/v1alpha1/timestamps.proto";
|
||||
import "holos/v1alpha1/organization.proto";
|
||||
import "holos/v1alpha1/user.proto";
|
||||
import "google/protobuf/struct.proto";
|
||||
|
||||
// For validation, see the [Standard constraints](https://github.com/bufbuild/protovalidate/blob/main/docs/standard-constraints.md)
|
||||
|
||||
message Platform {
|
||||
// Unique id assigned by the server.
|
||||
string id = 1 [(buf.validate.field).string.uuid = true];
|
||||
string name = 2 [(buf.validate.field).string.max_len = 100];
|
||||
string display_name = 3 [(buf.validate.field).string.max_len = 100];
|
||||
|
||||
// platform spec here?
|
||||
// platform spec form config here?
|
||||
|
||||
Timestamps timestamps = 4;
|
||||
Creator creator = 5;
|
||||
string id = 1;
|
||||
// Organization ID resource owner.
|
||||
string org_id = 2 [(buf.validate.field).string.uuid = true];
|
||||
// name is the platform short name as a dns label.
|
||||
string name = 3 [(buf.validate.field).string.max_len = 100];
|
||||
string display_name = 4 [(buf.validate.field).string.max_len = 100];
|
||||
PlatformSpec spec = 5;
|
||||
}
|
||||
|
||||
message GetPlatformsRequest {
|
||||
message PlatformSpec {
|
||||
// model represents the user-defined and user-supplied form field values.
|
||||
google.protobuf.Struct model = 1;
|
||||
}
|
||||
|
||||
// Form represents the Formly input form.
|
||||
message Form {
|
||||
// fields represents FormlyFieldConfig[] encoded as a JSON array.
|
||||
repeated google.protobuf.Struct fields = 1;
|
||||
}
|
||||
|
||||
// Model represents the values entered into the form, stored in the form's model
|
||||
// in the web app, and persisted into the backend database. The model is
|
||||
// ultimately intended as the input to platform rendering.
|
||||
message Model {
|
||||
google.protobuf.Struct model = 1;
|
||||
}
|
||||
|
||||
|
||||
message ListPlatformsRequest {
|
||||
string org_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
}
|
||||
|
||||
message GetPlatformsResponse {
|
||||
string org_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
repeated Platform platforms = 2;
|
||||
message ListPlatformsResponse {
|
||||
repeated Platform platforms = 1;
|
||||
}
|
||||
|
||||
message AddPlatformRequest {
|
||||
string org_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
string name = 2 [(buf.validate.field).string.max_len = 100];
|
||||
string display_name = 3 [(buf.validate.field).string.max_len = 100];
|
||||
Platform platform = 1;
|
||||
}
|
||||
|
||||
message AddPlatformResponse {
|
||||
repeated Platform platforms = 1;
|
||||
}
|
||||
|
||||
message GetPlatformRequest {
|
||||
string platform_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
}
|
||||
|
||||
message GetPlatformResponse {
|
||||
Platform platform = 1;
|
||||
}
|
||||
|
||||
message GetFormRequest {
|
||||
string platform_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
}
|
||||
|
||||
message GetFormResponse {
|
||||
repeated google.protobuf.Struct fields = 1;
|
||||
google.protobuf.Struct model = 2;
|
||||
}
|
||||
|
||||
message GetModelRequest {
|
||||
string platform_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
}
|
||||
|
||||
message GetModelResponse {
|
||||
google.protobuf.Struct model = 1;
|
||||
}
|
||||
|
||||
message PutModelRequest {
|
||||
string platform_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
google.protobuf.Struct model = 2;
|
||||
}
|
||||
|
||||
message PutModelResponse {
|
||||
google.protobuf.Struct model = 1;
|
||||
}
|
||||
|
||||
message PutFormRequest {
|
||||
string platform_id = 1 [(buf.validate.field).string.uuid = true];
|
||||
repeated google.protobuf.Struct fields = 2;
|
||||
}
|
||||
|
||||
message PutFormResponse {
|
||||
repeated google.protobuf.Struct fields = 1;
|
||||
}
|
||||
|
||||
service PlatformService {
|
||||
rpc GetPlatforms(GetPlatformsRequest) returns (GetPlatformsResponse) {}
|
||||
rpc AddPlatform(AddPlatformRequest) returns (GetPlatformsResponse) {}
|
||||
rpc AddPlatform(AddPlatformRequest) returns (AddPlatformResponse) {}
|
||||
rpc GetPlatform(GetPlatformRequest) returns (GetPlatformResponse) {}
|
||||
rpc ListPlatforms(ListPlatformsRequest) returns (ListPlatformsResponse) {}
|
||||
|
||||
rpc GetForm(GetFormRequest) returns (GetFormResponse) {}
|
||||
rpc PutForm(PutFormRequest) returns (PutFormResponse) {}
|
||||
|
||||
rpc GetModel(GetModelRequest) returns (GetModelResponse) {}
|
||||
rpc PutModel(PutModelRequest) returns (PutModelResponse) {}
|
||||
}
|
||||
|
||||
20
service/holos/v1alpha1/system.proto
Normal file
20
service/holos/v1alpha1/system.proto
Normal file
@@ -0,0 +1,20 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package holos.v1alpha1;
|
||||
|
||||
option go_package = "github.com/holos-run/holos/service/gen/holos/v1alpha1;holos";
|
||||
|
||||
// git clone https://github.com/bufbuild/protovalidate then add <parent>/protovalidate/proto/protovalidate to your editor proto search path
|
||||
|
||||
// For validation, see the [Standard constraints](https://github.com/bufbuild/protovalidate/blob/main/docs/standard-constraints.md)
|
||||
|
||||
message SeedDatabaseRequest {}
|
||||
message SeedDatabaseResponse {}
|
||||
|
||||
message DropTablesRequest {}
|
||||
message DropTablesResponse {}
|
||||
|
||||
service SystemService {
|
||||
rpc SeedDatabase(SeedDatabaseRequest) returns (SeedDatabaseResponse) {}
|
||||
rpc DropTables(DropTablesRequest) returns (DropTablesResponse) {}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ package holos.v1alpha1;
|
||||
|
||||
option go_package = "github.com/holos-run/holos/service/gen/holos/v1alpha1;holos";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
// git clone https://github.com/bufbuild/protovalidate then add <parent>/protovalidate/proto/protovalidate to your editor proto search path
|
||||
import "buf/validate/validate.proto";
|
||||
import "holos/v1alpha1/timestamps.proto";
|
||||
|
||||
@@ -1 +1 @@
|
||||
70
|
||||
73
|
||||
|
||||
@@ -1 +1 @@
|
||||
2
|
||||
3
|
||||
|
||||
Reference in New Issue
Block a user