Add rest endpoints for chart translations
It allows saving/updating yAxis label and metric label translations
This commit is contained in:
@@ -154,7 +154,6 @@ func (svc resourceTranslationsManager) {{ .expIdent }}(ctx context.Context, {{ r
|
||||
err error
|
||||
out locale.ResourceTranslationSet
|
||||
res *types.{{ .expIdent }}
|
||||
k types.LocaleKey
|
||||
)
|
||||
|
||||
res, err = svc.load{{ .expIdent }}(ctx, svc.store, {{ range .references }}{{ .param }}, {{ end }})
|
||||
@@ -162,19 +161,29 @@ func (svc resourceTranslationsManager) {{ .expIdent }}(ctx context.Context, {{ r
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
{{- range .keys}}
|
||||
{{- if not .customHandler }}
|
||||
k = types.{{ .struct }}
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: res.ResourceTranslation(),
|
||||
Lang: tag.String(),
|
||||
Key: k.Path,
|
||||
Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), k.Path),
|
||||
})
|
||||
{{ end }}
|
||||
{{- end}}
|
||||
}
|
||||
{{ $customHandlerExist := false }}
|
||||
{{range .keys}}
|
||||
{{if not .customHandler}}
|
||||
{{ $customHandlerExist = true }}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{ if $customHandlerExist }}
|
||||
var k types.LocaleKey
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
{{- range .keys}}
|
||||
{{- if not .customHandler }}
|
||||
k = types.{{ .struct }}
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: res.ResourceTranslation(),
|
||||
Lang: tag.String(),
|
||||
Key: k.Path,
|
||||
Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), k.Path),
|
||||
})
|
||||
{{ end }}
|
||||
{{- end}}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{ if .extended }}
|
||||
tmp, err := svc.{{ .ident }}Extended(ctx, res)
|
||||
|
||||
@@ -73,7 +73,16 @@ func {{ .expIdent }}ResourceTranslationTpl() string {
|
||||
}
|
||||
|
||||
func (r *{{ .expIdent }}) DecodeTranslations(tt locale.ResourceTranslationIndex) {
|
||||
var aux *locale.ResourceTranslation
|
||||
{{- $decodeFuncExist := false }}
|
||||
{{- range .keys }}
|
||||
{{- if not .decodeFunc }}
|
||||
{{- $decodeFuncExist = true }}
|
||||
{{- end }}
|
||||
{{- end}}
|
||||
|
||||
{{- if $decodeFuncExist }}
|
||||
var aux *locale.ResourceTranslation
|
||||
{{- end }}
|
||||
|
||||
{{- range .keys }}
|
||||
{{ if .decodeFunc }}
|
||||
|
||||
@@ -43,6 +43,21 @@ chart: schema.#Resource & {
|
||||
}
|
||||
}
|
||||
|
||||
locale: {
|
||||
extended: true
|
||||
|
||||
keys: {
|
||||
reportsYaxisLabel: {
|
||||
path: ["yAxis", "label"]
|
||||
customHandler: true
|
||||
}
|
||||
reportsMetricLabel: {
|
||||
path: ["metrics", {part: "metricID", var: true}, "label"]
|
||||
customHandler: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store: {
|
||||
ident: "composeChart"
|
||||
|
||||
|
||||
@@ -1089,6 +1089,32 @@ endpoints:
|
||||
name: chartID
|
||||
required: true
|
||||
title: Chart ID
|
||||
- name: listTranslations
|
||||
method: GET
|
||||
title: List chart translation
|
||||
path: "/{chartID}/translation"
|
||||
parameters:
|
||||
path:
|
||||
- type: uint64
|
||||
name: chartID
|
||||
required: true
|
||||
title: ID
|
||||
- name: updateTranslations
|
||||
method: PATCH
|
||||
title: Update chart translation
|
||||
path: "/{chartID}/translation"
|
||||
parameters:
|
||||
path:
|
||||
- type: uint64
|
||||
name: chartID
|
||||
required: true
|
||||
title: ID
|
||||
post:
|
||||
- name: translations
|
||||
type: locale.ResourceTranslationSet
|
||||
title: Resource translation to upsert
|
||||
required: true
|
||||
|
||||
- title: Notifications
|
||||
description: Compose Notifications
|
||||
entrypoint: notification
|
||||
|
||||
@@ -37,7 +37,8 @@ type (
|
||||
Update(ctx context.Context, chart *types.Chart) (*types.Chart, error)
|
||||
DeleteByID(ctx context.Context, namespaceID, chartID uint64) error
|
||||
}
|
||||
ac chartAccessController
|
||||
locale service.ResourceTranslationsManagerService
|
||||
ac chartAccessController
|
||||
}
|
||||
|
||||
chartAccessController interface {
|
||||
@@ -50,8 +51,9 @@ type (
|
||||
|
||||
func (Chart) New() *Chart {
|
||||
return &Chart{
|
||||
chart: service.DefaultChart,
|
||||
ac: service.DefaultAccessControl,
|
||||
chart: service.DefaultChart,
|
||||
locale: service.DefaultResourceTranslation,
|
||||
ac: service.DefaultAccessControl,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +136,14 @@ func (ctrl Chart) Delete(ctx context.Context, r *request.ChartDelete) (interface
|
||||
return api.OK(), ctrl.chart.DeleteByID(ctx, r.NamespaceID, r.ChartID)
|
||||
}
|
||||
|
||||
func (ctrl Chart) ListTranslations(ctx context.Context, r *request.ChartListTranslations) (interface{}, error) {
|
||||
return ctrl.locale.Chart(ctx, r.NamespaceID, r.ChartID)
|
||||
}
|
||||
|
||||
func (ctrl Chart) UpdateTranslations(ctx context.Context, r *request.ChartUpdateTranslations) (interface{}, error) {
|
||||
return api.OK(), ctrl.locale.Upsert(ctx, r.Translations)
|
||||
}
|
||||
|
||||
func (ctrl Chart) makePayload(ctx context.Context, c *types.Chart, err error) (*chartPayload, error) {
|
||||
if err != nil || c == nil {
|
||||
return nil, err
|
||||
|
||||
@@ -24,15 +24,19 @@ type (
|
||||
Read(context.Context, *request.ChartRead) (interface{}, error)
|
||||
Update(context.Context, *request.ChartUpdate) (interface{}, error)
|
||||
Delete(context.Context, *request.ChartDelete) (interface{}, error)
|
||||
ListTranslations(context.Context, *request.ChartListTranslations) (interface{}, error)
|
||||
UpdateTranslations(context.Context, *request.ChartUpdateTranslations) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
Chart struct {
|
||||
List func(http.ResponseWriter, *http.Request)
|
||||
Create func(http.ResponseWriter, *http.Request)
|
||||
Read func(http.ResponseWriter, *http.Request)
|
||||
Update func(http.ResponseWriter, *http.Request)
|
||||
Delete func(http.ResponseWriter, *http.Request)
|
||||
List func(http.ResponseWriter, *http.Request)
|
||||
Create func(http.ResponseWriter, *http.Request)
|
||||
Read func(http.ResponseWriter, *http.Request)
|
||||
Update func(http.ResponseWriter, *http.Request)
|
||||
Delete func(http.ResponseWriter, *http.Request)
|
||||
ListTranslations func(http.ResponseWriter, *http.Request)
|
||||
UpdateTranslations func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -116,6 +120,38 @@ func NewChart(h ChartAPI) *Chart {
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
ListTranslations: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewChartListTranslations()
|
||||
if err := params.Fill(r); err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.ListTranslations(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
UpdateTranslations: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewChartUpdateTranslations()
|
||||
if err := params.Fill(r); err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.UpdateTranslations(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
}
|
||||
@@ -129,5 +165,7 @@ func (h Chart) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.
|
||||
r.Get("/namespace/{namespaceID}/chart/{chartID}", h.Read)
|
||||
r.Post("/namespace/{namespaceID}/chart/{chartID}", h.Update)
|
||||
r.Delete("/namespace/{namespaceID}/chart/{chartID}", h.Delete)
|
||||
r.Get("/namespace/{namespaceID}/chart/{chartID}/translation", h.ListTranslations)
|
||||
r.Patch("/namespace/{namespaceID}/chart/{chartID}/translation", h.UpdateTranslations)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/label"
|
||||
"github.com/cortezaproject/corteza-server/pkg/locale"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi/v5"
|
||||
sqlxTypes "github.com/jmoiron/sqlx/types"
|
||||
@@ -160,6 +161,35 @@ type (
|
||||
// Chart ID
|
||||
ChartID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
ChartListTranslations struct {
|
||||
// NamespaceID PATH parameter
|
||||
//
|
||||
// Namespace ID
|
||||
NamespaceID uint64 `json:",string"`
|
||||
|
||||
// ChartID PATH parameter
|
||||
//
|
||||
// ID
|
||||
ChartID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
ChartUpdateTranslations struct {
|
||||
// NamespaceID PATH parameter
|
||||
//
|
||||
// Namespace ID
|
||||
NamespaceID uint64 `json:",string"`
|
||||
|
||||
// ChartID PATH parameter
|
||||
//
|
||||
// ID
|
||||
ChartID uint64 `json:",string"`
|
||||
|
||||
// Translations POST parameter
|
||||
//
|
||||
// Resource translation to upsert
|
||||
Translations locale.ResourceTranslationSet
|
||||
}
|
||||
)
|
||||
|
||||
// NewChartList request
|
||||
@@ -711,3 +741,139 @@ func (r *ChartDelete) Fill(req *http.Request) (err error) {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewChartListTranslations request
|
||||
func NewChartListTranslations() *ChartListTranslations {
|
||||
return &ChartListTranslations{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ChartListTranslations) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"namespaceID": r.NamespaceID,
|
||||
"chartID": r.ChartID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ChartListTranslations) GetNamespaceID() uint64 {
|
||||
return r.NamespaceID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ChartListTranslations) GetChartID() uint64 {
|
||||
return r.ChartID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *ChartListTranslations) Fill(req *http.Request) (err error) {
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "namespaceID")
|
||||
r.NamespaceID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "chartID")
|
||||
r.ChartID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewChartUpdateTranslations request
|
||||
func NewChartUpdateTranslations() *ChartUpdateTranslations {
|
||||
return &ChartUpdateTranslations{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ChartUpdateTranslations) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"namespaceID": r.NamespaceID,
|
||||
"chartID": r.ChartID,
|
||||
"translations": r.Translations,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ChartUpdateTranslations) GetNamespaceID() uint64 {
|
||||
return r.NamespaceID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ChartUpdateTranslations) GetChartID() uint64 {
|
||||
return r.ChartID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ChartUpdateTranslations) GetTranslations() locale.ResourceTranslationSet {
|
||||
return r.Translations
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *ChartUpdateTranslations) Fill(req *http.Request) (err error) {
|
||||
|
||||
if strings.HasPrefix(strings.ToLower(req.Header.Get("content-type")), "application/json") {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Caching 32MB to memory, the rest to disk
|
||||
if err = req.ParseMultipartForm(32 << 20); err != nil && err != http.ErrNotMultipart {
|
||||
return err
|
||||
} else if err == nil {
|
||||
// Multipart params
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
//if val, ok := req.Form["translations[]"]; ok && len(val) > 0 {
|
||||
// r.Translations, err = locale.ResourceTranslationSet(val), nil
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "namespaceID")
|
||||
r.NamespaceID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "chartID")
|
||||
r.ChartID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/cortezaproject/corteza-server/pkg/locale"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
@@ -17,9 +19,11 @@ type (
|
||||
actionlog actionlog.Recorder
|
||||
ac chartAccessController
|
||||
store store.Storer
|
||||
locale ResourceTranslationsManagerService
|
||||
}
|
||||
|
||||
chartAccessController interface {
|
||||
CanManageResourceTranslations(ctx context.Context) bool
|
||||
CanSearchChartsOnNamespace(context.Context, *types.Namespace) bool
|
||||
CanReadNamespace(context.Context, *types.Namespace) bool
|
||||
CanCreateChartOnNamespace(context.Context, *types.Namespace) bool
|
||||
@@ -44,12 +48,14 @@ func Chart() *chart {
|
||||
ac: DefaultAccessControl,
|
||||
actionlog: DefaultActionlog,
|
||||
store: DefaultStore,
|
||||
locale: DefaultResourceTranslation,
|
||||
}
|
||||
}
|
||||
|
||||
func (svc chart) Find(ctx context.Context, filter types.ChartFilter) (set types.ChartSet, f types.ChartFilter, err error) {
|
||||
var (
|
||||
aProps = &chartActionProps{filter: &filter}
|
||||
ns *types.Namespace
|
||||
)
|
||||
|
||||
// For each fetched item, store backend will check if it is valid or not
|
||||
@@ -62,7 +68,7 @@ func (svc chart) Find(ctx context.Context, filter types.ChartFilter) (set types.
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
ns, err := loadNamespace(ctx, svc.store, filter.NamespaceID)
|
||||
ns, err = loadNamespace(ctx, svc.store, filter.NamespaceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -99,6 +105,13 @@ func (svc chart) Find(ctx context.Context, filter types.ChartFilter) (set types.
|
||||
return err
|
||||
}
|
||||
|
||||
// i18n
|
||||
tag := locale.GetAcceptLanguageFromContext(ctx)
|
||||
set.Walk(func(p *types.Chart) error {
|
||||
p.DecodeTranslations(svc.locale.Locale().ResourceTranslations(tag, p.ResourceTranslation()))
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
@@ -158,10 +171,23 @@ func (svc chart) Create(ctx context.Context, new *types.Chart) (*types.Chart, er
|
||||
new.UpdatedAt = nil
|
||||
new.DeletedAt = nil
|
||||
|
||||
// Ensure chart report IDs
|
||||
for i, report := range new.Config.Reports {
|
||||
new.Config.Reports[i].ReportID = nextID()
|
||||
// Ensure chart report metric IDs
|
||||
for j := range report.Metrics {
|
||||
new.Config.Reports[i].Metrics[j]["metricID"] = strconv.FormatUint(nextID(), 10)
|
||||
}
|
||||
}
|
||||
|
||||
if err = store.CreateComposeChart(ctx, s, new); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = updateTranslations(ctx, svc.ac, svc.locale, new.EncodeTranslations()...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = label.Create(ctx, s, new); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -249,6 +275,10 @@ func (svc chart) updater(ctx context.Context, namespaceID, chartID uint64, actio
|
||||
}
|
||||
}
|
||||
|
||||
if err = updateTranslations(ctx, svc.ac, svc.locale, c.EncodeTranslations()...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if changes&chartLabelsChanged > 0 {
|
||||
if err = label.Update(ctx, s, c); err != nil {
|
||||
return
|
||||
@@ -304,6 +334,25 @@ func (svc chart) handleUpdate(ctx context.Context, upd *types.Chart) chartUpdate
|
||||
res.Config = upd.Config
|
||||
}
|
||||
|
||||
// Assure ReportIDs
|
||||
for i, r := range res.Config.Reports {
|
||||
if r.ReportID == 0 {
|
||||
r.ReportID = nextID()
|
||||
res.Config.Reports[i] = r
|
||||
|
||||
changes |= chartChanged
|
||||
}
|
||||
|
||||
// Ensure chart report metric IDs
|
||||
for j, m := range r.Metrics {
|
||||
if val, ok := m["metricID"]; !ok || val == 0 {
|
||||
m["metricID"] = strconv.FormatUint(nextID(), 10)
|
||||
res.Config.Reports[i].Metrics[j] = m
|
||||
|
||||
changes |= chartChanged
|
||||
}
|
||||
}
|
||||
}
|
||||
if changes&chartChanged > 0 {
|
||||
res.UpdatedAt = now()
|
||||
}
|
||||
|
||||
23
compose/service/locale.gen.go
generated
23
compose/service/locale.gen.go
generated
@@ -37,6 +37,7 @@ type (
|
||||
}
|
||||
|
||||
ResourceTranslationsManagerService interface {
|
||||
Chart(ctx context.Context, namespaceID uint64, id uint64) (locale.ResourceTranslationSet, error)
|
||||
Module(ctx context.Context, namespaceID uint64, id uint64) (locale.ResourceTranslationSet, error)
|
||||
Namespace(ctx context.Context, id uint64) (locale.ResourceTranslationSet, error)
|
||||
Page(ctx context.Context, namespaceID uint64, id uint64) (locale.ResourceTranslationSet, error)
|
||||
@@ -148,12 +149,27 @@ func (svc resourceTranslationsManager) Locale() locale.Resource {
|
||||
return svc.locale
|
||||
}
|
||||
|
||||
func (svc resourceTranslationsManager) Chart(ctx context.Context, namespaceID uint64, id uint64) (locale.ResourceTranslationSet, error) {
|
||||
var (
|
||||
err error
|
||||
out locale.ResourceTranslationSet
|
||||
res *types.Chart
|
||||
)
|
||||
|
||||
res, err = svc.loadChart(ctx, svc.store, namespaceID, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp, err := svc.chartExtended(ctx, res)
|
||||
return append(out, tmp...), err
|
||||
}
|
||||
|
||||
func (svc resourceTranslationsManager) Module(ctx context.Context, namespaceID uint64, id uint64) (locale.ResourceTranslationSet, error) {
|
||||
var (
|
||||
err error
|
||||
out locale.ResourceTranslationSet
|
||||
res *types.Module
|
||||
k types.LocaleKey
|
||||
)
|
||||
|
||||
res, err = svc.loadModule(ctx, svc.store, namespaceID, id)
|
||||
@@ -161,6 +177,7 @@ func (svc resourceTranslationsManager) Module(ctx context.Context, namespaceID u
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var k types.LocaleKey
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
k = types.LocaleKeyModuleName
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
@@ -181,7 +198,6 @@ func (svc resourceTranslationsManager) Namespace(ctx context.Context, id uint64)
|
||||
err error
|
||||
out locale.ResourceTranslationSet
|
||||
res *types.Namespace
|
||||
k types.LocaleKey
|
||||
)
|
||||
|
||||
res, err = svc.loadNamespace(ctx, svc.store, id)
|
||||
@@ -189,6 +205,7 @@ func (svc resourceTranslationsManager) Namespace(ctx context.Context, id uint64)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var k types.LocaleKey
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
k = types.LocaleKeyNamespaceName
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
@@ -224,7 +241,6 @@ func (svc resourceTranslationsManager) Page(ctx context.Context, namespaceID uin
|
||||
err error
|
||||
out locale.ResourceTranslationSet
|
||||
res *types.Page
|
||||
k types.LocaleKey
|
||||
)
|
||||
|
||||
res, err = svc.loadPage(ctx, svc.store, namespaceID, id)
|
||||
@@ -232,6 +248,7 @@ func (svc resourceTranslationsManager) Page(ctx context.Context, namespaceID uin
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var k types.LocaleKey
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
k = types.LocaleKeyPageTitle
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
|
||||
@@ -272,6 +272,45 @@ func (svc resourceTranslationsManager) pageExtended(ctx context.Context, res *ty
|
||||
return
|
||||
}
|
||||
|
||||
func (svc resourceTranslationsManager) chartExtended(_ context.Context, res *types.Chart) (out locale.ResourceTranslationSet, err error) {
|
||||
var (
|
||||
yAxisLabelK = types.LocaleKeyChartYAxisLabel
|
||||
metricLabelK = types.LocaleKeyChartMetricsMetricIDLabel
|
||||
)
|
||||
|
||||
for _, report := range res.Config.Reports {
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: res.ResourceTranslation(),
|
||||
Lang: tag.String(),
|
||||
Key: yAxisLabelK.Path,
|
||||
Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), yAxisLabelK.Path),
|
||||
})
|
||||
}
|
||||
|
||||
for _, metric := range report.Metrics {
|
||||
if _, ok := metric["metricID"]; ok {
|
||||
mID, is := metric["metricID"].(string)
|
||||
if !is {
|
||||
continue
|
||||
}
|
||||
mpl := strings.NewReplacer("{{metricID}}", mID)
|
||||
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: res.ResourceTranslation(),
|
||||
Lang: tag.String(),
|
||||
Key: mpl.Replace(metricLabelK.Path),
|
||||
Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), mpl.Replace(metricLabelK.Path)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (svc resourceTranslationsManager) pageExtendedAutomationBlock(tag language.Tag, res *types.Page, block types.PageBlock, blockID uint64) (locale.ResourceTranslationSet, error) {
|
||||
var (
|
||||
k = types.LocaleKeyPagePageBlockBlockIDButtonButtonIDLabel
|
||||
|
||||
@@ -3,6 +3,8 @@ package types
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"github.com/cortezaproject/corteza-server/pkg/locale"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
@@ -31,6 +33,7 @@ type (
|
||||
}
|
||||
|
||||
ChartConfigReport struct {
|
||||
ReportID uint64 `json:"reportID,string,omitempty"`
|
||||
Filter string `json:"filter"`
|
||||
ModuleID uint64 `json:"moduleID,string,omitempty"`
|
||||
Metrics []map[string]interface{} `json:"metrics,omitempty"`
|
||||
@@ -65,6 +68,76 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func (c Chart) decodeTranslations(tt locale.ResourceTranslationIndex) {
|
||||
var aux *locale.ResourceTranslation
|
||||
|
||||
for i, report := range c.Config.Reports {
|
||||
if aux = tt.FindByKey(LocaleKeyChartYAxisLabel.Path); aux != nil {
|
||||
c.Config.Reports[i].YAxis["label"] = aux.Msg
|
||||
}
|
||||
|
||||
for j, metric := range report.Metrics {
|
||||
if metricID, ok := metric["metricID"]; ok {
|
||||
mID, is := metricID.(string)
|
||||
if !is {
|
||||
continue
|
||||
}
|
||||
mpl := strings.NewReplacer(
|
||||
"{{metricID}}", mID,
|
||||
)
|
||||
|
||||
if aux = tt.FindByKey(mpl.Replace(LocaleKeyChartMetricsMetricIDLabel.Path)); aux != nil {
|
||||
c.Config.Reports[i].Metrics[j]["label"] = aux.Msg
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c Chart) encodeTranslations() (out locale.ResourceTranslationSet) {
|
||||
out = make(locale.ResourceTranslationSet, 0, 12)
|
||||
|
||||
for _, report := range c.Config.Reports {
|
||||
if mLabel, ok := report.YAxis["label"]; ok {
|
||||
ml, is := mLabel.(string)
|
||||
if !is {
|
||||
continue
|
||||
}
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: c.ResourceTranslation(),
|
||||
Key: LocaleKeyChartYAxisLabel.Path,
|
||||
Msg: ml,
|
||||
})
|
||||
}
|
||||
|
||||
for _, metric := range report.Metrics {
|
||||
if metricID, ok := metric["metricID"]; ok {
|
||||
mID, is := metricID.(string)
|
||||
if !is {
|
||||
continue
|
||||
}
|
||||
mpl := strings.NewReplacer(
|
||||
"{{metricID}}", mID,
|
||||
)
|
||||
|
||||
if mLabel, ok := metric["label"]; ok {
|
||||
ml, is := mLabel.(string)
|
||||
if !is {
|
||||
continue
|
||||
}
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: c.ResourceTranslation(),
|
||||
Key: mpl.Replace(LocaleKeyChartMetricsMetricIDLabel.Path),
|
||||
Msg: ml,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindByHandle finds chart by it's handle
|
||||
func (set ChartSet) FindByHandle(handle string) *Chart {
|
||||
for i := range set {
|
||||
|
||||
44
compose/types/locale.gen.go
generated
44
compose/types/locale.gen.go
generated
@@ -23,6 +23,7 @@ type (
|
||||
|
||||
// Types and stuff
|
||||
const (
|
||||
ChartResourceTranslationType = "compose:chart"
|
||||
ModuleResourceTranslationType = "compose:module"
|
||||
ModuleFieldResourceTranslationType = "compose:module-field"
|
||||
NamespaceResourceTranslationType = "compose:namespace"
|
||||
@@ -31,6 +32,8 @@ const (
|
||||
|
||||
var (
|
||||
// @todo can we remove LocaleKey struct for string constant?
|
||||
LocaleKeyChartYAxisLabel = LocaleKey{Path: "yAxis.label"}
|
||||
LocaleKeyChartMetricsMetricIDLabel = LocaleKey{Path: "metrics.{{metricID}}.label"}
|
||||
LocaleKeyModuleName = LocaleKey{Path: "name"}
|
||||
LocaleKeyModuleFieldLabel = LocaleKey{Path: "label"}
|
||||
LocaleKeyModuleFieldMetaDescriptionView = LocaleKey{Path: "meta.description.view"}
|
||||
@@ -57,6 +60,47 @@ var (
|
||||
LocaleKeyPagePageBlockBlockIDContentBody = LocaleKey{Path: "pageBlock.{{blockID}}.content.body"}
|
||||
)
|
||||
|
||||
// ResourceTranslation returns string representation of Locale resource for Chart by calling ChartResourceTranslation fn
|
||||
//
|
||||
// Locale resource is in "compose:chart/..." format
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (r Chart) ResourceTranslation() string {
|
||||
return ChartResourceTranslation(r.NamespaceID, r.ID)
|
||||
}
|
||||
|
||||
// ChartResourceTranslation returns string representation of Locale resource for Chart
|
||||
//
|
||||
// Locale resource is in the compose:chart/... format
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ChartResourceTranslation(NamespaceID uint64, ID uint64) string {
|
||||
cpts := []interface{}{
|
||||
ChartResourceTranslationType,
|
||||
strconv.FormatUint(NamespaceID, 10),
|
||||
strconv.FormatUint(ID, 10),
|
||||
}
|
||||
|
||||
return fmt.Sprintf(ChartResourceTranslationTpl(), cpts...)
|
||||
}
|
||||
|
||||
func ChartResourceTranslationTpl() string {
|
||||
return "%s/%s/%s"
|
||||
}
|
||||
|
||||
func (r *Chart) DecodeTranslations(tt locale.ResourceTranslationIndex) {
|
||||
|
||||
r.decodeTranslations(tt)
|
||||
}
|
||||
|
||||
func (r *Chart) EncodeTranslations() (out locale.ResourceTranslationSet) {
|
||||
out = locale.ResourceTranslationSet{}
|
||||
|
||||
out = append(out, r.encodeTranslations()...)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// ResourceTranslation returns string representation of Locale resource for Module by calling ModuleResourceTranslation fn
|
||||
//
|
||||
// Locale resource is in "compose:module/..." format
|
||||
|
||||
@@ -65,21 +65,25 @@ func (r *ComposeChart) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *ComposeChart) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
func (r *ComposeChart) resourceParts(tpl string) (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref().Constraint(r.RefNs)
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(types.ChartRbacResourceTpl(), types.ChartResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// func (r *ComposeChart) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
// ref = r.Ref()
|
||||
// path = []*Ref{r.RefNs}
|
||||
// resource = fmt.Sprintf(types.ChartResourceTranslationTpl(), types.ChartResourceTranslationType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
func (r *ComposeChart) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ChartRbacResourceTpl())
|
||||
}
|
||||
|
||||
// return
|
||||
// }
|
||||
func (r *ComposeChart) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ChartResourceTranslationTpl())
|
||||
}
|
||||
|
||||
func (r *ComposeChart) encodeTranslations() ([]*ResourceTranslation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// FindComposeChart looks for the chart in the resources
|
||||
func FindComposeChart(rr InterfaceSet, ii Identifiers) (ch *types.Chart) {
|
||||
|
||||
12
pkg/envoy/resource/resource_translation.gen.go
generated
12
pkg/envoy/resource/resource_translation.gen.go
generated
@@ -10,6 +10,18 @@ import (
|
||||
systemTypes "github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func (r *ComposeChart) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
tmp, err := r.encodeTranslations()
|
||||
return append(out, tmp...), err
|
||||
|
||||
}
|
||||
func (r *ComposeModule) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
|
||||
10
pkg/envoy/resource/resource_translation_parse.gen.go
generated
10
pkg/envoy/resource/resource_translation_parse.gen.go
generated
@@ -47,6 +47,16 @@ func ParseResourceTranslation(res string) (string, *Ref, []*Ref, error) {
|
||||
|
||||
// make the resource provide the slice of parent resources we should nest under
|
||||
switch resourceType {
|
||||
case composeTypes.ChartResourceTranslationType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeChartResourceTranslationReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return composeTypes.ChartResourceTranslationType, ref, pp, err
|
||||
|
||||
case composeTypes.ModuleResourceTranslationType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
|
||||
@@ -10,6 +10,16 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
)
|
||||
|
||||
// ComposeChartResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeChartResourceTranslationReferences(namespaceID string, self string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.ChartResourceType, Identifiers: MakeIdentifiers(self)}
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeModuleResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
|
||||
@@ -172,20 +172,20 @@ func (n *resourceTranslation) makeResourceTranslation(pl *payload) (string, erro
|
||||
|
||||
return composeTypes.PageResourceTranslation(p0ID, p1ID), nil
|
||||
|
||||
// case composeTypes.ChartResourceType:
|
||||
// p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
// if p0 == nil {
|
||||
// return "", resource.ComposeNamespaceErrUnresolved(n.refPathRes[0].Identifiers)
|
||||
// }
|
||||
// p0ID = p0.ID
|
||||
case composeTypes.ChartResourceType:
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(n.refPathRes[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
|
||||
// p1 := resource.FindComposeChart(pl.state.ParentResources, n.refLocaleRes.Identifiers)
|
||||
// if p1 == nil {
|
||||
// return "", resource.ComposeChartErrUnresolved(n.refLocaleRes.Identifiers)
|
||||
// }
|
||||
// p1ID = p1.ID
|
||||
p1 := resource.FindComposeChart(pl.state.ParentResources, n.refLocaleRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposeChartErrUnresolved(n.refLocaleRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
|
||||
// return composeTypes.ChartResourceTranslation(p0ID, p1ID), nil
|
||||
return composeTypes.ChartResourceTranslation(p0ID, p1ID), nil
|
||||
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
|
||||
@@ -162,24 +162,24 @@ func (r *resourceTranslation) makeResourceTranslationResource(state *envoy.Resou
|
||||
|
||||
return fmt.Sprintf(composeTypes.ModuleFieldResourceTranslationTpl(), composeTypes.ModuleFieldResourceTranslationType, p0ID, p1ID, p2ID), nil
|
||||
|
||||
// case composeTypes.ChartResourceType:
|
||||
// if len(res.RefPath) > 0 {
|
||||
// p0 := resource.FindComposeNamespace(state.ParentResources, res.RefPath[0].Identifiers)
|
||||
// if p0 == nil {
|
||||
// return "", resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
// }
|
||||
// p0ID = p0.Slug
|
||||
// }
|
||||
case composeTypes.ChartResourceType:
|
||||
if len(res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(state.ParentResources, res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.Slug
|
||||
}
|
||||
|
||||
// if res.RefRes != nil {
|
||||
// p1 := resource.FindComposeChart(state.ParentResources, res.RefRes.Identifiers)
|
||||
// if p1 == nil {
|
||||
// return "", resource.ComposeChartErrUnresolved(res.RefRes.Identifiers)
|
||||
// }
|
||||
// p1ID = p1.Handle
|
||||
// }
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindComposeChart(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposeChartErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
// return fmt.Sprintf(composeTypes.ChartResourceTranslationTpl(), composeTypes.ChartResourceTranslationType, p0ID, p1ID), nil
|
||||
return fmt.Sprintf(composeTypes.ChartResourceTranslationTpl(), composeTypes.ChartResourceTranslationType, p0ID, p1ID), nil
|
||||
|
||||
// case automationTypes.WorkflowResourceType:
|
||||
// if res.RefRes != nil {
|
||||
|
||||
116
pkg/provision/migrations_202203_resource_translations.go
Normal file
116
pkg/provision/migrations_202203_resource_translations.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package provision
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
cmpTypes "github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza-server/pkg/id"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
sysTypes "github.com/cortezaproject/corteza-server/system/types"
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Migrates resource translations from the resource
|
||||
// struct to the dedicated store (table)
|
||||
//
|
||||
// While doing this, we also modify some resource substructure:
|
||||
// - chart reports (assign report IDs)
|
||||
//
|
||||
// Note: we will migrate all translations to current default language
|
||||
// If you do not like that, shut down Corteza after migrations and fix this directly in the store
|
||||
func migratePost202203ResourceTranslations(ctx context.Context, log *zap.Logger, s store.Storer) (err error) {
|
||||
log.Info("migrating post 202203 resource translations")
|
||||
|
||||
var (
|
||||
migrated = make(map[string]bool)
|
||||
)
|
||||
|
||||
set, _, err := store.SearchResourceTranslations(ctx, s, sysTypes.ResourceTranslationFilter{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = set.Walk(func(r *sysTypes.ResourceTranslation) error {
|
||||
var pos = strings.Index(r.Resource, "/")
|
||||
if pos < 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
migrated[r.Resource[0:pos]] = true
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !migrated[cmpTypes.ChartResourceTranslationType] {
|
||||
if err = migrateComposeChartResourceTranslations(ctx, log, s); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// migrate resource translations for compose chart
|
||||
func migrateComposeChartResourceTranslations(ctx context.Context, log *zap.Logger, s store.Storer) error {
|
||||
var (
|
||||
tt sysTypes.ResourceTranslationSet
|
||||
)
|
||||
set, _, err := store.SearchComposeCharts(ctx, s, cmpTypes.ChartFilter{Deleted: filter.StateInclusive})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("migrating compose charts", zap.Int("count", len(set)))
|
||||
|
||||
return s.Tx(ctx, func(ctx context.Context, s store.Storer) error {
|
||||
return set.Walk(func(res *cmpTypes.Chart) (err error) {
|
||||
if tt, err = convertComposeChartReportsTranslations(res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = store.CreateResourceTranslation(ctx, s, tt...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = store.UpdateComposeChart(ctx, s, res); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// collects translations for compose chart blocks and alters them (adding block ID)
|
||||
func convertComposeChartReportsTranslations(res *cmpTypes.Chart) (sysTypes.ResourceTranslationSet, error) {
|
||||
var tt sysTypes.ResourceTranslationSet
|
||||
|
||||
for i, r := range res.Config.Reports {
|
||||
reportID := id.Next()
|
||||
res.Config.Reports[i].ReportID = reportID
|
||||
|
||||
if _, ok := r.YAxis["label"]; ok {
|
||||
tt = append(tt,
|
||||
makeResourceTranslation(res, "yAxis.label", r.YAxis["label"].(string)),
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure chart report metric IDs
|
||||
for j, m := range r.Metrics {
|
||||
metricID := id.Next()
|
||||
res.Config.Reports[i].Metrics[j]["metricID"] = fmt.Sprintf("%d", metricID)
|
||||
cmx := fmt.Sprintf("metrics.%d.", metricID)
|
||||
|
||||
if _, ok := m["label"]; ok {
|
||||
tt = append(tt,
|
||||
makeResourceTranslation(res, cmx+"label", m["label"].(string)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tt, nil
|
||||
}
|
||||
@@ -41,6 +41,9 @@ func Run(ctx context.Context, log *zap.Logger, s store.Storer, provisionOpt opti
|
||||
func() error { return cleanupPre202109Settings(ctx, log.Named("pre-202109-settings"), s) },
|
||||
func() error { return migrateResourceTranslations(ctx, log.Named("resource-translations"), s) },
|
||||
func() error { return migrateReportIdentifiers(ctx, log.Named("report-identifiers"), s) },
|
||||
func() error {
|
||||
return migratePost202203ResourceTranslations(ctx, log.Named("post-202203-resource-translations"), s)
|
||||
},
|
||||
|
||||
// Config (full & partial)
|
||||
func() error { return importConfig(ctx, log.Named("config"), s, provisionOpt.Path) },
|
||||
|
||||
Reference in New Issue
Block a user