Prevent boards product from being included automatically (#23539)

* Prevent boards product from being included automatically

* Fix config diff test

* Update prepackaged plugin version

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>

* Readd boards/dist to the gitignore

* Does not enable the focalboard plugin by default

* Update plugin version to v7.10.3

---------

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>
Этот коммит содержится в:
Miguel de la Cruz
2023-06-12 18:51:43 +02:00
коммит произвёл GitHub
родитель d8cb5f3a6e
Коммит 1215584665
16 изменённых файлов: 708 добавлений и 8807 удалений

Просмотреть файл

@@ -131,21 +131,6 @@ export default class Client extends Client4 {
return this.doFetch<PluginManifest>(this.getPluginsRoute(), options); return this.doFetch<PluginManifest>(this.getPluginsRoute(), options);
}; };
// *****************************************************************************
// Boards client
// based on "webapp/boards/src/octoClient.ts"
// *****************************************************************************
async patchUserConfig(userID: string, patch: UserConfigPatch): Promise<UserPreference[] | undefined> {
const path = `/users/${encodeURIComponent(userID)}/config`;
const options = {
method: 'put',
body: JSON.stringify(patch),
};
return this.doFetch<UserPreference[]>(this.getBoardsRoute() + path, options);
}
} }
// Variable to hold cache // Variable to hold cache
@@ -168,9 +153,6 @@ async function makeClient(userRequest?: UserRequest, useCache = true): Promise<C
const userProfile = await client.login(userRequest.username, userRequest.password); const userProfile = await client.login(userRequest.username, userRequest.password);
const user = {...userProfile, password: userRequest.password}; const user = {...userProfile, password: userRequest.password};
// Manually do until boards as product is consistent in all the codebase.
client.setUseBoardsProduct(true);
if (useCache) { if (useCache) {
clients[cacheKey] = {client, user}; clients[cacheKey] = {client, user};
} }
@@ -197,18 +179,4 @@ type ClientCache = {
user: UserProfile | null; user: UserProfile | null;
}; };
// Boards types
interface UserPreference {
user_id: string;
category: string;
name: string;
value: any;
}
interface UserConfigPatch {
updatedFields?: Record<string, string>;
deletedFields?: string[];
}
export {Client, makeClient}; export {Client, makeClient};

Просмотреть файл

@@ -14,20 +14,10 @@ import {getOnPremServerConfig} from './default_config';
import {createRandomTeam} from './team'; import {createRandomTeam} from './team';
import {createRandomUser} from './user'; import {createRandomUser} from './user';
const boardsUserConfigPatch = {
updatedFields: {
welcomePageViewed: '1',
onboardingTourStep: '999',
tourCategory: 'board',
version72MessageCanceled: 'true',
},
};
export async function initSetup({ export async function initSetup({
userPrefix = 'user', userPrefix = 'user',
teamPrefix = {name: 'team', displayName: 'Team'}, teamPrefix = {name: 'team', displayName: 'Team'},
withDefaultProfileImage = true, withDefaultProfileImage = true,
skipBoardsUserConfig = true,
} = {}) { } = {}) {
try { try {
// Login the admin user via API // Login the admin user via API
@@ -65,10 +55,6 @@ export async function initSetup({
]; ];
await userClient.savePreferences(user.id, preferences); await userClient.savePreferences(user.id, preferences);
if (skipBoardsUserConfig) {
await userClient.patchUserConfig(user.id, boardsUserConfigPatch);
}
return { return {
adminClient, adminClient,
adminUser, adminUser,

Просмотреть файл

@@ -147,8 +147,7 @@ DIST_PATH_WIN=$(DIST_ROOT)/windows/mattermost
TESTS=. TESTS=.
# Packages lists # Packages lists
TE_PACKAGES=$(shell $(GO) list ./... | grep -vE 'server/v8/playbooks|server/v8/boards|server/v8/cmd/mmctl') TE_PACKAGES=$(shell $(GO) list ./... | grep -vE 'server/v8/playbooks|server/v8/cmd/mmctl')
BOARDS_PACKAGES=$(shell $(GO) list ./... | grep -E 'server/v8/boards')
PLAYBOOKS_PACKAGES=$(shell $(GO) list ./... | grep -E 'server/v8/playbooks') PLAYBOOKS_PACKAGES=$(shell $(GO) list ./... | grep -E 'server/v8/playbooks')
SUITE_PACKAGES=$(shell $(GO) list ./...| grep -vE 'server/v8/cmd/mmctl') SUITE_PACKAGES=$(shell $(GO) list ./...| grep -vE 'server/v8/cmd/mmctl')
MMCTL_PACKAGES=$(shell $(GO) list ./... | grep -E 'server/v8/cmd/mmctl') MMCTL_PACKAGES=$(shell $(GO) list ./... | grep -E 'server/v8/cmd/mmctl')
@@ -173,6 +172,7 @@ PLUGIN_PACKAGES += mattermost-plugin-todo-v0.6.1
PLUGIN_PACKAGES += mattermost-plugin-welcomebot-v1.3.0 PLUGIN_PACKAGES += mattermost-plugin-welcomebot-v1.3.0
PLUGIN_PACKAGES += mattermost-plugin-zoom-v1.6.0 PLUGIN_PACKAGES += mattermost-plugin-zoom-v1.6.0
PLUGIN_PACKAGES += mattermost-plugin-apps-v1.2.1 PLUGIN_PACKAGES += mattermost-plugin-apps-v1.2.1
PLUGIN_PACKAGES += focalboard-v7.10.3
# Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target # Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target
ifeq ($(BUILD_ENTERPRISE_READY),true) ifeq ($(BUILD_ENTERPRISE_READY),true)
@@ -187,9 +187,9 @@ endif
EE_PACKAGES=$(shell $(GO) list $(BUILD_ENTERPRISE_DIR)/...) EE_PACKAGES=$(shell $(GO) list $(BUILD_ENTERPRISE_DIR)/...)
ifeq ($(BUILD_ENTERPRISE_READY),true) ifeq ($(BUILD_ENTERPRISE_READY),true)
ALL_PACKAGES=$(TE_PACKAGES) $(BOARDS_PACKAGES) $(PLAYBOOKS_PACKAGES) $(EE_PACKAGES) ALL_PACKAGES=$(TE_PACKAGES) $(PLAYBOOKS_PACKAGES) $(EE_PACKAGES)
else else
ALL_PACKAGES=$(TE_PACKAGES) $(BOARDS_PACKAGES) $(PLAYBOOKS_PACKAGES) ALL_PACKAGES=$(TE_PACKAGES) $(PLAYBOOKS_PACKAGES)
endif endif
all: run ## Alias for 'run'. all: run ## Alias for 'run'.
@@ -326,10 +326,6 @@ app-layers: ## Extract interface from App struct
$(GOBIN)/struct2interface -f "channels/app" -o "channels/app/app_iface.go" -p "app" -s "App" -i "AppIface" -t ./channels/app/layer_generators/app_iface.go.tmpl $(GOBIN)/struct2interface -f "channels/app" -o "channels/app/app_iface.go" -p "app" -s "App" -i "AppIface" -t ./channels/app/layer_generators/app_iface.go.tmpl
$(GO) run ./channels/app/layer_generators -in ./channels/app/app_iface.go -out ./channels/app/opentracing/opentracing_layer.go -template ./channels/app/layer_generators/opentracing_layer.go.tmpl $(GO) run ./channels/app/layer_generators -in ./channels/app/app_iface.go -out ./channels/app/opentracing/opentracing_layer.go -template ./channels/app/layer_generators/opentracing_layer.go.tmpl
boards-gen: ## Run generators for Boards
$(GO) install github.com/golang/mock/mockgen@v1.6.0
cd boards && $(GO) generate ./...
i18n-extract: ## Extract strings for translation from the source code i18n-extract: ## Extract strings for translation from the source code
$(GO) install github.com/mattermost/mattermost-utilities/mmgotool@mono-repo $(GO) install github.com/mattermost/mattermost-utilities/mmgotool@mono-repo
$(GOBIN)/mmgotool i18n extract --portal-dir="" $(GOBIN)/mmgotool i18n extract --portal-dir=""
@@ -406,7 +402,7 @@ pluginapi: ## Generates api and hooks glue code for plugins
mocks: store-mocks telemetry-mocks filestore-mocks ldap-mocks plugin-mocks einterfaces-mocks searchengine-mocks sharedchannel-mocks misc-mocks email-mocks platform-mocks mmctl-mocks mocks: store-mocks telemetry-mocks filestore-mocks ldap-mocks plugin-mocks einterfaces-mocks searchengine-mocks sharedchannel-mocks misc-mocks email-mocks platform-mocks mmctl-mocks
layers: app-layers store-layers pluginapi boards-gen layers: app-layers store-layers pluginapi
generated: mocks layers generated: mocks layers
@@ -463,7 +459,6 @@ endif
test-server-race: test-server-pre test-server-race: test-server-pre
./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(TE_PACKAGES) $(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" ./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(TE_PACKAGES) $(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m"
./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(BOARDS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m"
./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(PLAYBOOKS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" ./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(PLAYBOOKS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m"
ifneq ($(IS_CI),true) ifneq ($(IS_CI),true)
ifneq ($(MM_NO_DOCKER),true) ifneq ($(MM_NO_DOCKER),true)

Просмотреть файл

@@ -21,8 +21,10 @@ const (
boardsProductID = "com.mattermost.boards" boardsProductID = "com.mattermost.boards"
) )
//nolint:unused
var errServiceTypeAssert = errors.New("type assertion failed") var errServiceTypeAssert = errors.New("type assertion failed")
/*
func init() { func init() {
product.RegisterProduct(boardsProductName, product.Manifest{ product.RegisterProduct(boardsProductName, product.Manifest{
Initializer: newBoardsProduct, Initializer: newBoardsProduct,
@@ -49,6 +51,7 @@ func init() {
}, },
}) })
} }
*/
type boardsProduct struct { type boardsProduct struct {
teamService product.TeamService teamService product.TeamService
@@ -61,7 +64,7 @@ type boardsProduct struct {
configService product.ConfigService configService product.ConfigService
logger mlog.LoggerIFace logger mlog.LoggerIFace
licenseService product.LicenseService licenseService product.LicenseService
filestoreService product.FilestoreService filestoreService product.FilestoreService //nolint:unused
fileInfoStoreService product.FileInfoStoreService fileInfoStoreService product.FileInfoStoreService
routerService product.RouterService routerService product.RouterService
cloudService product.CloudService cloudService product.CloudService
@@ -74,6 +77,7 @@ type boardsProduct struct {
boardsApp *server.BoardsService boardsApp *server.BoardsService
} }
//nolint:unused
func newBoardsProduct(services map[product.ServiceKey]interface{}) (product.Product, error) { func newBoardsProduct(services map[product.ServiceKey]interface{}) (product.Product, error) {
boardsProd := &boardsProduct{} boardsProd := &boardsProduct{}
@@ -99,6 +103,8 @@ func newBoardsProduct(services map[product.ServiceKey]interface{}) (product.Prod
} }
// populateServices populates the boardProduct with all the services needed from the suite. // populateServices populates the boardProduct with all the services needed from the suite.
//
//nolint:unused
func populateServices(boardsProd *boardsProduct, services map[product.ServiceKey]interface{}) error { func populateServices(boardsProd *boardsProduct, services map[product.ServiceKey]interface{}) error {
for key, service := range services { for key, service := range services {
switch key { switch key {

Просмотреть файл

@@ -107,7 +107,6 @@ var pluginIDBlocklist = map[string]bool{
"playbooks": true, "playbooks": true,
"com.mattermost.plugin-incident-response": true, "com.mattermost.plugin-incident-response": true,
"com.mattermost.plugin-incident-management": true, "com.mattermost.plugin-incident-management": true,
"focalboard": true,
} }
func PluginIDIsBlocked(id string) bool { func PluginIDIsBlocked(id string) bool {

Просмотреть файл

@@ -58,11 +58,9 @@ build: node_modules ## Builds all web app packages
npm run build npm run build
.PHONY: dist .PHONY: dist
dist: build ## Builds all web app packages and copies Boards/Playbooks files into Channels dist folder dist: build ## Builds all web app packages and copies Playbooks files into Channels dist folder
@echo Packaging Mattermost Web App @echo Packaging Mattermost Web App
mkdir -p channels/dist/products/boards
cp -R boards/dist/* channels/dist/products/boards
mkdir -p channels/dist/products/playbooks mkdir -p channels/dist/products/playbooks
cp -R playbooks/dist/* channels/dist/products/playbooks cp -R playbooks/dist/* channels/dist/products/playbooks

Просмотреть файл

@@ -1,6 +1,6 @@
# Mattermost Web App # Mattermost Web App
This folder contains the client code for the Mattermost web app. It's broken up into multiple packages each of which either contains an area of the app (such as `playbooks` or `boards`) or shared logic used across other packages (such as the packages located in the `platform` directory). For anyone who's used to working in [the mattermost/mattermost-webapp repo](https://github.com/mattermost/mattermost-webapp), most of that is now located in `channels`. This folder contains the client code for the Mattermost web app. It's broken up into multiple packages each of which either contains an area of the app (such as `playbooks`) or shared logic used across other packages (such as the packages located in the `platform` directory). For anyone who's used to working in [the mattermost/mattermost-webapp repo](https://github.com/mattermost/mattermost-webapp), most of that is now located in `channels`.
## npm Workspaces ## npm Workspaces
@@ -8,7 +8,7 @@ To interact with a workspace using npm, such as to add a dependency or run a scr
```sh ```sh
# Add a dependency to a single package # Add a dependency to a single package
npm add react --workspace=boards npm add react --workspace=playbooks
# Build multiple packages # Build multiple packages
npm run build --workspace=platform/client --workspace=platform/components npm run build --workspace=platform/client --workspace=platform/components

Просмотреть файл

@@ -1,44 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Client4} from 'mattermost-redux/client';
import testConfigureStore from 'tests/test_store';
import {initializeProducts} from './products';
(window as any).REMOTE_CONTAINERS = {};
describe('initializeProducts', () => {
test('should set Client4 to use the correct Boards URL for product mode', async () => {
const store = testConfigureStore({
entities: {
general: {
config: {
FeatureFlagBoardsProduct: 'true',
},
},
},
});
await store.dispatch(initializeProducts());
expect(Client4.getBoardsRoute().startsWith('/plugins/boards')).toBe(true);
});
test('should set Client4 to use the correct Boards URL for plugin mode', async () => {
const store = testConfigureStore({
entities: {
general: {
config: {
FeatureFlagBoardsProduct: 'false',
},
},
},
});
await store.dispatch(initializeProducts());
expect(Client4.getBoardsRoute().startsWith('/plugins/focalboard')).toBe(true);
});
});

Просмотреть файл

@@ -3,7 +3,6 @@
import {Store} from 'redux'; import {Store} from 'redux';
import {Client4} from 'mattermost-redux/client';
import {getConfig} from 'mattermost-redux/selectors/entities/general'; import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions'; import {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
@@ -26,11 +25,8 @@ export function initializeProducts() {
} }
function configureClient() { function configureClient() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return (dispatch: DispatchFunc, getState: GetStateFunc) => { return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const config = getConfig(getState());
Client4.setUseBoardsProduct(config.FeatureFlagBoardsProduct === 'true');
return Promise.resolve({data: true}); return Promise.resolve({data: true});
}; };
} }
@@ -48,20 +44,10 @@ function loadRemoteModules() {
* can't be constructed based on the name of a product at runtime. * can't be constructed based on the name of a product at runtime.
*/ */
let products = [ let products = [
{
id: 'boards',
load: () => ({
index: import('boards'),
// manifest: import('boards/manifest'),
}),
},
{ {
id: 'playbooks', id: 'playbooks',
load: () => ({ load: () => ({
index: import('playbooks'), index: import('playbooks'),
// manifest: import('boards/manifest'),
}), }),
}, },
]; ];

Просмотреть файл

@@ -279,15 +279,10 @@ if (DEV) {
config.plugins.push({ config.plugins.push({
apply: (compiler) => { apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', () => { compiler.hooks.afterEmit.tap('AfterEmitPlugin', () => {
const boardsDist = path.resolve(__dirname, '../boards/dist');
const boardsSymlink = './dist/products/boards';
const playbooksDist = path.resolve(__dirname, '../playbooks/dist'); const playbooksDist = path.resolve(__dirname, '../playbooks/dist');
const playbooksSymlink = './dist/products/playbooks'; const playbooksSymlink = './dist/products/playbooks';
fs.mkdir('./dist/products', () => { fs.mkdir('./dist/products', () => {
if (!fs.existsSync(boardsSymlink)) {
fs.symlinkSync(boardsDist, boardsSymlink, 'dir');
}
if (!fs.existsSync(playbooksSymlink)) { if (!fs.existsSync(playbooksSymlink)) {
fs.symlinkSync(playbooksDist, playbooksSymlink, 'dir'); fs.symlinkSync(playbooksDist, playbooksSymlink, 'dir');
} }
@@ -334,7 +329,6 @@ async function initializeModuleFederation() {
async function getRemoteContainers() { async function getRemoteContainers() {
const products = [ const products = [
{name: 'boards'},
{name: 'playbooks'}, {name: 'playbooks'},
]; ];

9342
webapp/package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@@ -52,7 +52,6 @@
"platform/client", "platform/client",
"platform/components", "platform/components",
"platform/types", "platform/types",
"playbooks", "playbooks"
"boards"
] ]
} }

Просмотреть файл

@@ -182,8 +182,6 @@ export default class Client4 {
userRoles = ''; userRoles = '';
telemetryHandler?: TelemetryHandler; telemetryHandler?: TelemetryHandler;
useBoardsProduct = false;
getUrl() { getUrl() {
return this.url; return this.url;
} }
@@ -247,10 +245,6 @@ export default class Client4 {
this.telemetryHandler = telemetryHandler; this.telemetryHandler = telemetryHandler;
} }
setUseBoardsProduct(useBoardsProduct: boolean) {
this.useBoardsProduct = useBoardsProduct;
}
getServerVersion() { getServerVersion() {
return this.serverVersion; return this.serverVersion;
} }
@@ -479,10 +473,6 @@ export default class Client4 {
return `${this.getBaseRoute()}/drafts`; return `${this.getBaseRoute()}/drafts`;
} }
getBoardsRoute() {
return `${this.url}/plugins/${this.useBoardsProduct ? 'boards' : 'focalboard'}/api/v2`;
}
getCSRFFromCookie() { getCSRFFromCookie() {
if (typeof document !== 'undefined' && typeof document.cookie !== 'undefined') { if (typeof document !== 'undefined' && typeof document.cookie !== 'undefined') {
const cookies = document.cookie.split(';'); const cookies = document.cookie.split(';');

Просмотреть файл

@@ -41,20 +41,6 @@ async function buildAll() {
console.log('\n' + chalk.inverse.bold('Web app built! ')); console.log('\n' + chalk.inverse.bold('Web app built! '));
console.log(chalk.inverse.bold('Building Boards...') + '\n');
try {
const {result} = concurrently([
{command: 'npm:build --workspace=boards', name: 'boards', prefixColor: 'blue'},
]);
await result;
} catch (e) {
console.error(chalk.inverse.bold.red('Failed to build Boards'), e);
return;
}
console.log('\n' + chalk.inverse.bold('Boards built! '));
console.log(chalk.inverse.bold('Building Playbooks...') + '\n'); console.log(chalk.inverse.bold('Building Playbooks...') + '\n');
try { try {

Просмотреть файл

@@ -13,7 +13,6 @@ async function watchAllWithDevServer() {
const commands = [ const commands = [
{command: 'npm:dev-server --workspace=channels', name: 'webapp', prefixColor: 'cyan'}, {command: 'npm:dev-server --workspace=channels', name: 'webapp', prefixColor: 'cyan'},
{command: 'npm:start:product --workspace=boards', name: 'boards', prefixColor: 'blue'},
{command: 'npm:start:product --workspace=playbooks', name: 'playbooks', prefixColor: 'red'}, {command: 'npm:start:product --workspace=playbooks', name: 'playbooks', prefixColor: 'red'},
]; ];

Просмотреть файл

@@ -16,7 +16,6 @@ async function watchAll(useRunner) {
const commands = [ const commands = [
{command: 'npm:run --workspace=channels', name: 'webapp', prefixColor: 'cyan'}, {command: 'npm:run --workspace=channels', name: 'webapp', prefixColor: 'cyan'},
{command: 'npm:start:product --workspace=boards', name: 'boards', prefixColor: 'blue'},
{command: 'npm:start:product --workspace=playbooks', name: 'playbooks', prefixColor: 'red'}, {command: 'npm:start:product --workspace=playbooks', name: 'playbooks', prefixColor: 'red'},
]; ];