mirror of
https://github.com/mattermost/focalboard.git
synced 2025-02-01 19:14:35 +02:00
Merge remote-tracking branch 'upstream/main' into compliance-history-export
This commit is contained in:
commit
0990089f35
@ -31,6 +31,7 @@ func init() {
|
|||||||
product.ChannelKey: {},
|
product.ChannelKey: {},
|
||||||
product.UserKey: {},
|
product.UserKey: {},
|
||||||
product.PostKey: {},
|
product.PostKey: {},
|
||||||
|
product.PermissionsKey: {},
|
||||||
product.BotKey: {},
|
product.BotKey: {},
|
||||||
product.ClusterKey: {},
|
product.ClusterKey: {},
|
||||||
product.ConfigKey: {},
|
product.ConfigKey: {},
|
||||||
@ -44,6 +45,7 @@ func init() {
|
|||||||
product.StoreKey: {},
|
product.StoreKey: {},
|
||||||
product.SystemKey: {},
|
product.SystemKey: {},
|
||||||
product.PreferencesKey: {},
|
product.PreferencesKey: {},
|
||||||
|
product.HooksKey: {},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -73,127 +75,150 @@ type boardsProduct struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newBoardsProduct(services map[product.ServiceKey]interface{}) (product.Product, error) {
|
func newBoardsProduct(services map[product.ServiceKey]interface{}) (product.Product, error) {
|
||||||
boards := &boardsProduct{}
|
boardsProd := &boardsProduct{}
|
||||||
|
|
||||||
|
if err := populateServices(boardsProd, services); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
boardsProd.logger.Info("Creating boards service")
|
||||||
|
|
||||||
|
adapter := newServiceAPIAdapter(boardsProd)
|
||||||
|
boardsApp, err := boards.NewBoardsApp(adapter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create Boards service: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
boardsProd.boardsApp = boardsApp
|
||||||
|
|
||||||
|
// Add the Boards services API to the services map so other products can access Boards functionality.
|
||||||
|
boardsAPI := boards.NewBoardsServiceAPI(boardsApp)
|
||||||
|
services[product.BoardsKey] = boardsAPI
|
||||||
|
|
||||||
|
return boardsProd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// populateServices populates the boardProduct with all the services needed from the suite.
|
||||||
|
func populateServices(boardsProd *boardsProduct, services map[product.ServiceKey]interface{}) error {
|
||||||
for key, service := range services {
|
for key, service := range services {
|
||||||
switch key {
|
switch key {
|
||||||
case product.TeamKey:
|
case product.TeamKey:
|
||||||
teamService, ok := service.(product.TeamService)
|
teamService, ok := service.(product.TeamService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.teamService = teamService
|
boardsProd.teamService = teamService
|
||||||
case product.ChannelKey:
|
case product.ChannelKey:
|
||||||
channelService, ok := service.(product.ChannelService)
|
channelService, ok := service.(product.ChannelService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.channelService = channelService
|
boardsProd.channelService = channelService
|
||||||
case product.UserKey:
|
case product.UserKey:
|
||||||
userService, ok := service.(product.UserService)
|
userService, ok := service.(product.UserService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.userService = userService
|
boardsProd.userService = userService
|
||||||
case product.PostKey:
|
case product.PostKey:
|
||||||
postService, ok := service.(product.PostService)
|
postService, ok := service.(product.PostService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.postService = postService
|
boardsProd.postService = postService
|
||||||
case product.PermissionsKey:
|
case product.PermissionsKey:
|
||||||
permissionsService, ok := service.(product.PermissionService)
|
permissionsService, ok := service.(product.PermissionService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.permissionsService = permissionsService
|
boardsProd.permissionsService = permissionsService
|
||||||
case product.BotKey:
|
case product.BotKey:
|
||||||
botService, ok := service.(product.BotService)
|
botService, ok := service.(product.BotService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.botService = botService
|
boardsProd.botService = botService
|
||||||
case product.ClusterKey:
|
case product.ClusterKey:
|
||||||
clusterService, ok := service.(product.ClusterService)
|
clusterService, ok := service.(product.ClusterService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.clusterService = clusterService
|
boardsProd.clusterService = clusterService
|
||||||
case product.ConfigKey:
|
case product.ConfigKey:
|
||||||
configService, ok := service.(product.ConfigService)
|
configService, ok := service.(product.ConfigService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.configService = configService
|
boardsProd.configService = configService
|
||||||
case product.LogKey:
|
case product.LogKey:
|
||||||
logger, ok := service.(mlog.LoggerIFace)
|
logger, ok := service.(mlog.LoggerIFace)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.logger = logger.With(mlog.String("product", boardsProductName))
|
boardsProd.logger = logger.With(mlog.String("product", boardsProductName))
|
||||||
case product.LicenseKey:
|
case product.LicenseKey:
|
||||||
licenseService, ok := service.(product.LicenseService)
|
licenseService, ok := service.(product.LicenseService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.licenseService = licenseService
|
boardsProd.licenseService = licenseService
|
||||||
case product.FilestoreKey:
|
case product.FilestoreKey:
|
||||||
filestoreService, ok := service.(product.FilestoreService)
|
filestoreService, ok := service.(product.FilestoreService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.filestoreService = filestoreService
|
boardsProd.filestoreService = filestoreService
|
||||||
case product.FileInfoStoreKey:
|
case product.FileInfoStoreKey:
|
||||||
fileInfoStoreService, ok := service.(product.FileInfoStoreService)
|
fileInfoStoreService, ok := service.(product.FileInfoStoreService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.fileInfoStoreService = fileInfoStoreService
|
boardsProd.fileInfoStoreService = fileInfoStoreService
|
||||||
case product.RouterKey:
|
case product.RouterKey:
|
||||||
routerService, ok := service.(product.RouterService)
|
routerService, ok := service.(product.RouterService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.routerService = routerService
|
boardsProd.routerService = routerService
|
||||||
case product.CloudKey:
|
case product.CloudKey:
|
||||||
cloudService, ok := service.(product.CloudService)
|
cloudService, ok := service.(product.CloudService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.cloudService = cloudService
|
boardsProd.cloudService = cloudService
|
||||||
case product.KVStoreKey:
|
case product.KVStoreKey:
|
||||||
kvStoreService, ok := service.(product.KVStoreService)
|
kvStoreService, ok := service.(product.KVStoreService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.kvStoreService = kvStoreService
|
boardsProd.kvStoreService = kvStoreService
|
||||||
case product.StoreKey:
|
case product.StoreKey:
|
||||||
storeService, ok := service.(product.StoreService)
|
storeService, ok := service.(product.StoreService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.storeService = storeService
|
boardsProd.storeService = storeService
|
||||||
case product.SystemKey:
|
case product.SystemKey:
|
||||||
systemService, ok := service.(product.SystemService)
|
systemService, ok := service.(product.SystemService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.systemService = systemService
|
boardsProd.systemService = systemService
|
||||||
case product.PreferencesKey:
|
case product.PreferencesKey:
|
||||||
preferencesService, ok := service.(product.PreferencesService)
|
preferencesService, ok := service.(product.PreferencesService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.preferencesService = preferencesService
|
boardsProd.preferencesService = preferencesService
|
||||||
case product.HooksKey:
|
case product.HooksKey:
|
||||||
hooksService, ok := service.(product.HooksService)
|
hooksService, ok := service.(product.HooksService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
|
||||||
}
|
}
|
||||||
boards.hooksService = hooksService
|
boardsProd.hooksService = hooksService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return boards, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *boardsProduct) Start() error {
|
func (bp *boardsProduct) Start() error {
|
||||||
|
79
mattermost-plugin/server/boards/boards_service_api.go
Normal file
79
mattermost-plugin/server/boards/boards_service_api.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/focalboard/server/app"
|
||||||
|
"github.com/mattermost/focalboard/server/model"
|
||||||
|
|
||||||
|
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
||||||
|
"github.com/mattermost/mattermost-server/v6/product"
|
||||||
|
)
|
||||||
|
|
||||||
|
// boardsServiceAPI provides a service API for other products such as Channels.
|
||||||
|
type boardsServiceAPI struct {
|
||||||
|
app *app.App
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBoardsServiceAPI(app *BoardsApp) *boardsServiceAPI {
|
||||||
|
return &boardsServiceAPI{
|
||||||
|
app: app.server.App(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) GetTemplates(teamID string, userID string) ([]*model.Board, error) {
|
||||||
|
return bs.app.GetTemplateBoards(teamID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) GetBoard(boardID string) (*model.Board, error) {
|
||||||
|
return bs.app.GetBoard(boardID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) CreateBoard(board *model.Board, userID string, addmember bool) (*model.Board, error) {
|
||||||
|
return bs.app.CreateBoard(board, userID, addmember)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) PatchBoard(boardPatch *model.BoardPatch, boardID string, userID string) (*model.Board, error) {
|
||||||
|
return bs.app.PatchBoard(boardPatch, boardID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) DeleteBoard(boardID string, userID string) error {
|
||||||
|
return bs.app.DeleteBoard(boardID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) SearchBoards(searchTerm string, searchField model.BoardSearchField,
|
||||||
|
userID string, includePublicBoards bool) ([]*model.Board, error) {
|
||||||
|
return bs.app.SearchBoardsForUser(searchTerm, searchField, userID, includePublicBoards)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) LinkBoardToChannel(boardID string, channelID string, userID string) (*model.Board, error) {
|
||||||
|
patch := &model.BoardPatch{
|
||||||
|
ChannelID: &channelID,
|
||||||
|
}
|
||||||
|
return bs.app.PatchBoard(patch, boardID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) GetCards(boardID string) ([]*model.Card, error) {
|
||||||
|
return bs.app.GetCardsForBoard(boardID, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) GetCard(cardID string) (*model.Card, error) {
|
||||||
|
return bs.app.GetCardByID(cardID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) CreateCard(card *model.Card, boardID string, userID string) (*model.Card, error) {
|
||||||
|
return bs.app.CreateCard(card, boardID, userID, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) PatchCard(cardPatch *model.CardPatch, cardID string, userID string) (*model.Card, error) {
|
||||||
|
return bs.app.PatchCard(cardPatch, cardID, userID, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) DeleteCard(cardID string, userID string) error {
|
||||||
|
return bs.app.DeleteBlock(cardID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *boardsServiceAPI) HasPermissionToBoard(userID, boardID string, permission *mm_model.Permission) bool {
|
||||||
|
return bs.app.HasPermissionToBoard(userID, boardID, permission)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure boardsServiceAPI implements product.BoardsService interface.
|
||||||
|
var _ product.BoardsService = (*boardsServiceAPI)(nil)
|
@ -84,6 +84,7 @@ func NewBoardsApp(api model.ServicesAPI) (*BoardsApp, error) {
|
|||||||
return cluster.NewMutex(&mutexAPIAdapter{api: api}, name)
|
return cluster.NewMutex(&mutexAPIAdapter{api: api}, name)
|
||||||
},
|
},
|
||||||
ServicesAPI: api,
|
ServicesAPI: api,
|
||||||
|
ConfigFn: api.GetConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
var db store.Store
|
var db store.Store
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 10px 0;
|
padding: 10px 35px 10px 0;
|
||||||
margin: 0 35px;
|
|
||||||
|
|
||||||
.BoardSelectorItem-info {
|
.BoardSelectorItem-info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
padding-left: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
@ -64,6 +64,7 @@ type App struct {
|
|||||||
metrics *metrics.Metrics
|
metrics *metrics.Metrics
|
||||||
notifications *notify.Service
|
notifications *notify.Service
|
||||||
logger mlog.LoggerIFace
|
logger mlog.LoggerIFace
|
||||||
|
permissions permissions.PermissionsService
|
||||||
blockChangeNotifier *utils.CallbackQueue
|
blockChangeNotifier *utils.CallbackQueue
|
||||||
servicesAPI servicesAPI
|
servicesAPI servicesAPI
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ func New(config *config.Configuration, wsAdapter ws.Adapter, services Services)
|
|||||||
metrics: services.Metrics,
|
metrics: services.Metrics,
|
||||||
notifications: services.Notifications,
|
notifications: services.Notifications,
|
||||||
logger: services.Logger,
|
logger: services.Logger,
|
||||||
|
permissions: services.Permissions,
|
||||||
blockChangeNotifier: utils.NewCallbackQueue("blockChangeNotifier", blockChangeNotifierQueueSize, blockChangeNotifierPoolSize, services.Logger),
|
blockChangeNotifier: utils.NewCallbackQueue("blockChangeNotifier", blockChangeNotifierQueueSize, blockChangeNotifierPoolSize, services.Logger),
|
||||||
servicesAPI: services.ServicesAPI,
|
servicesAPI: services.ServicesAPI,
|
||||||
}
|
}
|
||||||
|
9
server/app/permissions.go
Normal file
9
server/app/permissions.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *App) HasPermissionToBoard(userID, boardID string, permission *mm_model.Permission) bool {
|
||||||
|
return a.permissions.HasPermissionToBoard(userID, boardID, permission)
|
||||||
|
}
|
@ -105,6 +105,21 @@ type Board struct {
|
|||||||
DeleteAt int64 `json:"deleteAt"`
|
DeleteAt int64 `json:"deleteAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPropertyString returns the value of the specified property as a string,
|
||||||
|
// or error if the property does not exist or is not of type string.
|
||||||
|
func (b *Board) GetPropertyString(propName string) (string, error) {
|
||||||
|
val, ok := b.Properties[propName]
|
||||||
|
if !ok {
|
||||||
|
return "", NewErrNotFound(propName)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok := val.(string)
|
||||||
|
if !ok {
|
||||||
|
return "", ErrInvalidPropertyValueType
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BoardPatch is a patch for modify boards
|
// BoardPatch is a patch for modify boards
|
||||||
// swagger:model
|
// swagger:model
|
||||||
type BoardPatch struct {
|
type BoardPatch struct {
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
|
|
||||||
|
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
"github.com/mattermost/mattermost-server/v6/store/sqlstore"
|
"github.com/mattermost/mattermost-server/v6/store/sqlstore"
|
||||||
|
|
||||||
@ -59,14 +60,14 @@ func (s *SQLStore) getMigrationConnection() (*sql.DB, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := sql.Open(s.dbType, connectionString)
|
var settings mmModel.SqlSettings
|
||||||
if err != nil {
|
settings.SetDefaults(false)
|
||||||
return nil, err
|
if s.configFn != nil {
|
||||||
|
settings = s.configFn().SqlSettings
|
||||||
}
|
}
|
||||||
|
*settings.DriverName = s.dbType
|
||||||
|
|
||||||
if err = db.Ping(); err != nil {
|
db := sqlstore.SetupConnection("master", connectionString, &settings)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ type Params struct {
|
|||||||
NewMutexFn MutexFactory
|
NewMutexFn MutexFactory
|
||||||
ServicesAPI servicesAPI
|
ServicesAPI servicesAPI
|
||||||
SkipMigrations bool
|
SkipMigrations bool
|
||||||
|
ConfigFn func() *mmModel.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Params) CheckValid() error {
|
func (p Params) CheckValid() error {
|
||||||
|
@ -29,6 +29,7 @@ type SQLStore struct {
|
|||||||
servicesAPI servicesAPI
|
servicesAPI servicesAPI
|
||||||
isBinaryParam bool
|
isBinaryParam bool
|
||||||
schemaName string
|
schemaName string
|
||||||
|
configFn func() *mmModel.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// MutexFactory is used by the store in plugin mode to generate
|
// MutexFactory is used by the store in plugin mode to generate
|
||||||
@ -53,6 +54,7 @@ func New(params Params) (*SQLStore, error) {
|
|||||||
isSingleUser: params.IsSingleUser,
|
isSingleUser: params.IsSingleUser,
|
||||||
NewMutexFn: params.NewMutexFn,
|
NewMutexFn: params.NewMutexFn,
|
||||||
servicesAPI: params.ServicesAPI,
|
servicesAPI: params.ServicesAPI,
|
||||||
|
configFn: params.ConfigFn,
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
"BoardMember.unlinkChannel": "Verknüpfung aufheben",
|
"BoardMember.unlinkChannel": "Verknüpfung aufheben",
|
||||||
"BoardPage.newVersion": "Eine neue Version von Boards ist verfügbar, klicke hier, um neu zu laden.",
|
"BoardPage.newVersion": "Eine neue Version von Boards ist verfügbar, klicke hier, um neu zu laden.",
|
||||||
"BoardPage.syncFailed": "Das Board kann gelöscht oder der Zugang entzogen werden.",
|
"BoardPage.syncFailed": "Das Board kann gelöscht oder der Zugang entzogen werden.",
|
||||||
"BoardTemplateSelector.add-template": "Neue Vorlage",
|
"BoardTemplateSelector.add-template": "Neue Vorlage erstellen",
|
||||||
"BoardTemplateSelector.create-empty-board": "Leeres Board erstellen",
|
"BoardTemplateSelector.create-empty-board": "Leeres Board erstellen",
|
||||||
"BoardTemplateSelector.delete-template": "Löschen",
|
"BoardTemplateSelector.delete-template": "Löschen",
|
||||||
"BoardTemplateSelector.description": "Füge ein Board hinzu, indem du eine der unten definierten Vorlagen verwendest oder ganz neu beginnst.",
|
"BoardTemplateSelector.description": "Füge ein Board hinzu, indem du eine der unten definierten Vorlagen verwendest oder ganz neu beginnst.",
|
||||||
|
@ -15,9 +15,15 @@
|
|||||||
"BoardPage.newVersion": "Có một phiên bản mới của bảng, click vào đây để nạp lại.",
|
"BoardPage.newVersion": "Có một phiên bản mới của bảng, click vào đây để nạp lại.",
|
||||||
"Calculations.Options.average.displayName": "Trung bình",
|
"Calculations.Options.average.displayName": "Trung bình",
|
||||||
"Calculations.Options.average.label": "Trung bình",
|
"Calculations.Options.average.label": "Trung bình",
|
||||||
|
"TableComponent.add-icon": "Thêm icon",
|
||||||
|
"TableComponent.name": "Tên",
|
||||||
|
"TableComponent.plus-new": "+ Mới",
|
||||||
|
"TableHeaderMenu.delete": "Xóa",
|
||||||
"share-board.publish": "Công khai",
|
"share-board.publish": "Công khai",
|
||||||
"share-board.share": "Chia sẻ",
|
"share-board.share": "Chia sẻ",
|
||||||
"shareBoard.channels-select-group": "Kênh",
|
"shareBoard.channels-select-group": "Kênh",
|
||||||
"shareBoard.members-select-group": "Thành viên",
|
"shareBoard.members-select-group": "Thành viên",
|
||||||
"tutorial_tip.finish_tour": "Xong"
|
"tutorial_tip.finish_tour": "Xong",
|
||||||
|
"tutorial_tip.got_it": "Đã hiểu",
|
||||||
|
"tutorial_tip.ok": "Tiếp theo"
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,7 @@
|
|||||||
"OnboardingTour.CopyLink.Title": "複製連結",
|
"OnboardingTour.CopyLink.Title": "複製連結",
|
||||||
"OnboardingTour.OpenACard.Body": "打開卡片查看看板可以幫助你組織工作的優秀方法",
|
"OnboardingTour.OpenACard.Body": "打開卡片查看看板可以幫助你組織工作的優秀方法",
|
||||||
"OnboardingTour.OpenACard.Title": "瀏覽卡片",
|
"OnboardingTour.OpenACard.Title": "瀏覽卡片",
|
||||||
|
"OnboardingTour.ShareBoard.Body": "您可以在內部、團隊內部分享看板,或公開發布讓組織外部查看。",
|
||||||
"OnboardingTour.ShareBoard.Title": "分享看板",
|
"OnboardingTour.ShareBoard.Title": "分享看板",
|
||||||
"PersonProperty.board-members": "看版成員",
|
"PersonProperty.board-members": "看版成員",
|
||||||
"PersonProperty.non-board-members": "不是看板成員",
|
"PersonProperty.non-board-members": "不是看板成員",
|
||||||
@ -190,25 +191,33 @@
|
|||||||
"PropertyType.Phone": "電話號碼",
|
"PropertyType.Phone": "電話號碼",
|
||||||
"PropertyType.Select": "選取",
|
"PropertyType.Select": "選取",
|
||||||
"PropertyType.Text": "文字框",
|
"PropertyType.Text": "文字框",
|
||||||
|
"PropertyType.Unknown": "未知",
|
||||||
"PropertyType.UpdatedBy": "最後更新者",
|
"PropertyType.UpdatedBy": "最後更新者",
|
||||||
"PropertyType.UpdatedTime": "最後更新時間",
|
"PropertyType.UpdatedTime": "最後更新時間",
|
||||||
|
"PropertyType.Url": "網址",
|
||||||
|
"PropertyValueElement.empty": "空白",
|
||||||
"RegistrationLink.confirmRegenerateToken": "此動作將使先前分享的連結無效。確定要進行嗎?",
|
"RegistrationLink.confirmRegenerateToken": "此動作將使先前分享的連結無效。確定要進行嗎?",
|
||||||
"RegistrationLink.copiedLink": "已複製!",
|
"RegistrationLink.copiedLink": "已複製!",
|
||||||
"RegistrationLink.copyLink": "複製連結",
|
"RegistrationLink.copyLink": "複製連結",
|
||||||
"RegistrationLink.description": "將此連結分享給他人以建立帳號:",
|
"RegistrationLink.description": "將此連結分享給他人以建立帳號:",
|
||||||
"RegistrationLink.regenerateToken": "重新產生 token",
|
"RegistrationLink.regenerateToken": "重新產生 token",
|
||||||
"RegistrationLink.tokenRegenerated": "已重新產生註冊鏈結",
|
"RegistrationLink.tokenRegenerated": "已重新產生註冊鏈結",
|
||||||
|
"ShareBoard.PublishDescription": "發布只能讀取的連結",
|
||||||
"ShareBoard.PublishTitle": "發布至網路",
|
"ShareBoard.PublishTitle": "發布至網路",
|
||||||
"ShareBoard.ShareInternal": "內部分享",
|
"ShareBoard.ShareInternal": "內部分享",
|
||||||
|
"ShareBoard.ShareInternalDescription": "擁有權限的使用者才能使用此連結",
|
||||||
|
"ShareBoard.Title": "分享看板",
|
||||||
"ShareBoard.confirmRegenerateToken": "此動作將使先前分享的鏈結無效。確定要進行嗎?",
|
"ShareBoard.confirmRegenerateToken": "此動作將使先前分享的鏈結無效。確定要進行嗎?",
|
||||||
"ShareBoard.copiedLink": "已複製!",
|
"ShareBoard.copiedLink": "已複製!",
|
||||||
"ShareBoard.copyLink": "複製連結",
|
"ShareBoard.copyLink": "複製連結",
|
||||||
"ShareBoard.regenerate": "重新產生權杖",
|
"ShareBoard.regenerate": "重新產生權杖",
|
||||||
|
"ShareBoard.searchPlaceholder": "查詢人和頻道",
|
||||||
"ShareBoard.teamPermissionsText": "在{teamName}的所有人",
|
"ShareBoard.teamPermissionsText": "在{teamName}的所有人",
|
||||||
"ShareBoard.tokenRegenrated": "已重新產生權杖",
|
"ShareBoard.tokenRegenrated": "已重新產生權杖",
|
||||||
"ShareBoard.userPermissionsRemoveMemberText": "移除成員",
|
"ShareBoard.userPermissionsRemoveMemberText": "移除成員",
|
||||||
"ShareBoard.userPermissionsYouText": "(你)",
|
"ShareBoard.userPermissionsYouText": "(你)",
|
||||||
"ShareTemplate.Title": "分享範本",
|
"ShareTemplate.Title": "分享範本",
|
||||||
|
"ShareTemplate.searchPlaceholder": "查詢人",
|
||||||
"Sidebar.about": "關於 Focalboard",
|
"Sidebar.about": "關於 Focalboard",
|
||||||
"Sidebar.add-board": "+ 新增看板",
|
"Sidebar.add-board": "+ 新增看板",
|
||||||
"Sidebar.changePassword": "變更密碼",
|
"Sidebar.changePassword": "變更密碼",
|
||||||
@ -219,14 +228,22 @@
|
|||||||
"Sidebar.import-archive": "匯入打包檔",
|
"Sidebar.import-archive": "匯入打包檔",
|
||||||
"Sidebar.invite-users": "邀請使用者",
|
"Sidebar.invite-users": "邀請使用者",
|
||||||
"Sidebar.logout": "登出",
|
"Sidebar.logout": "登出",
|
||||||
|
"Sidebar.no-boards-in-category": "沒有看板在裡面",
|
||||||
|
"Sidebar.product-tour": "產品導覽",
|
||||||
"Sidebar.random-icons": "隨機圖示",
|
"Sidebar.random-icons": "隨機圖示",
|
||||||
"Sidebar.set-language": "設定語言",
|
"Sidebar.set-language": "設定語言",
|
||||||
"Sidebar.set-theme": "設定佈景主題",
|
"Sidebar.set-theme": "設定佈景主題",
|
||||||
"Sidebar.settings": "設定",
|
"Sidebar.settings": "設定",
|
||||||
|
"Sidebar.template-from-board": "新的看板模板",
|
||||||
"Sidebar.untitled-board": "(無標題版面)",
|
"Sidebar.untitled-board": "(無標題版面)",
|
||||||
"SidebarCategories.BlocksMenu.Move": "移動至…",
|
"SidebarCategories.BlocksMenu.Move": "移動至…",
|
||||||
"SidebarCategories.CategoryMenu.CreateNew": "新增分類",
|
"SidebarCategories.CategoryMenu.CreateNew": "新增分類",
|
||||||
"SidebarCategories.CategoryMenu.Delete": "刪除分類",
|
"SidebarCategories.CategoryMenu.Delete": "刪除分類",
|
||||||
|
"SidebarCategories.CategoryMenu.DeleteModal.Title": "刪除這個分類?",
|
||||||
|
"SidebarCategories.CategoryMenu.Update": "重新命名分類",
|
||||||
|
"SidebarTour.ManageCategories.Title": "管理分類",
|
||||||
|
"SidebarTour.SearchForBoards.Title": "查詢看板",
|
||||||
|
"SidebarTour.SidebarCategories.Link": "更多",
|
||||||
"TableComponent.add-icon": "加入圖示",
|
"TableComponent.add-icon": "加入圖示",
|
||||||
"TableComponent.name": "姓名",
|
"TableComponent.name": "姓名",
|
||||||
"TableComponent.plus-new": "+ 新增",
|
"TableComponent.plus-new": "+ 新增",
|
||||||
@ -243,7 +260,16 @@
|
|||||||
"URLProperty.copiedLink": "已複製!",
|
"URLProperty.copiedLink": "已複製!",
|
||||||
"URLProperty.copy": "複製",
|
"URLProperty.copy": "複製",
|
||||||
"URLProperty.edit": "編輯",
|
"URLProperty.edit": "編輯",
|
||||||
|
"UndoRedoHotKeys.canRedo": "重新執行",
|
||||||
|
"UndoRedoHotKeys.canRedo-with-description": "撤銷{description}",
|
||||||
|
"UndoRedoHotKeys.canUndo": "撤銷",
|
||||||
|
"UndoRedoHotKeys.canUndo-with-description": "重新執行 {description}",
|
||||||
|
"UndoRedoHotKeys.cannotRedo": "沒有可以重寫的",
|
||||||
|
"UndoRedoHotKeys.cannotUndo": "沒有可以取消的",
|
||||||
|
"ValueSelector.noOptions": "沒有選項.開始輸入第一個字!",
|
||||||
|
"ValueSelector.valueSelector": "值選擇器",
|
||||||
"ValueSelectorLabel.openMenu": "開啟選單",
|
"ValueSelectorLabel.openMenu": "開啟選單",
|
||||||
|
"VersionMessage.help": "查看這個版本有什麼新功能.",
|
||||||
"View.AddView": "新增視圖",
|
"View.AddView": "新增視圖",
|
||||||
"View.Board": "版面",
|
"View.Board": "版面",
|
||||||
"View.DeleteView": "刪除視圖",
|
"View.DeleteView": "刪除視圖",
|
||||||
@ -336,5 +362,6 @@
|
|||||||
"tutorial_tip.finish_tour": "完成",
|
"tutorial_tip.finish_tour": "完成",
|
||||||
"tutorial_tip.got_it": "了解",
|
"tutorial_tip.got_it": "了解",
|
||||||
"tutorial_tip.ok": "下一步",
|
"tutorial_tip.ok": "下一步",
|
||||||
"tutorial_tip.out": "不接受這個提示."
|
"tutorial_tip.out": "不接受這個提示.",
|
||||||
|
"tutorial_tip.seen": "以前有見過嗎?"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user