Merge branch 'main' into gh-1059-fix-empty-placeholder-in-card-dialog
This commit is contained in:
commit
e5c6619555
25 changed files with 352 additions and 24 deletions
10
.github/workflows/build-mac.yml
vendored
10
.github/workflows/build-mac.yml
vendored
|
@ -12,12 +12,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: npm install
|
||||
run: cd webapp; npm install --no-optional
|
||||
|
||||
|
|
10
.github/workflows/build-ubuntu.yml
vendored
10
.github/workflows/build-ubuntu.yml
vendored
|
@ -11,12 +11,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: npm install
|
||||
run: cd webapp; npm install --no-optional
|
||||
|
||||
|
|
10
.github/workflows/build-win-wpf.yml
vendored
10
.github/workflows/build-win-wpf.yml
vendored
|
@ -11,12 +11,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
|
|
40
.github/workflows/dev-release.yml
vendored
40
.github/workflows/dev-release.yml
vendored
|
@ -16,12 +16,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: npm install
|
||||
run: cd webapp; npm install --no-optional
|
||||
|
||||
|
@ -69,12 +75,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: npm install
|
||||
run: cd webapp; npm install --no-optional
|
||||
|
||||
|
@ -105,12 +117,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
|
@ -154,12 +172,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: npm install
|
||||
run: cd webapp; npm install --no-optional
|
||||
|
||||
|
|
10
.github/workflows/plugin-release.yml
vendored
10
.github/workflows/plugin-release.yml
vendored
|
@ -11,12 +11,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_PROD_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_PROD_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: npm install
|
||||
run: cd webapp; npm install --no-optional
|
||||
|
||||
|
|
10
.github/workflows/prod-release.yml
vendored
10
.github/workflows/prod-release.yml
vendored
|
@ -11,12 +11,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Replace token 1
|
||||
- name: Replace token 1 server
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2
|
||||
- name: Replace token 1 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: Replace token 2 server
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_PROD_KEY }},g" ${{ github.workspace }}/server/services/telemetry/telemetry.go
|
||||
|
||||
- name: Replace token 2 webapp
|
||||
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_PROD_KEY }},g" ${{ github.workspace }}/mattermost-plugin/webapp/src/index.tsx
|
||||
|
||||
- name: npm install
|
||||
run: cd webapp; npm install --no-optional
|
||||
|
||||
|
|
|
@ -88,6 +88,13 @@ func (p *Plugin) OnActivate() error {
|
|||
baseURL = *mmconfig.ServiceSettings.SiteURL
|
||||
}
|
||||
|
||||
serverID := client.System.GetDiagnosticID()
|
||||
|
||||
enableTelemetry := false
|
||||
if mmconfig.LogSettings.EnableDiagnostics != nil {
|
||||
enableTelemetry = *mmconfig.LogSettings.EnableDiagnostics
|
||||
}
|
||||
|
||||
cfg := &config.Configuration{
|
||||
ServerRoot: baseURL + "/plugins/focalboard",
|
||||
Port: -1,
|
||||
|
@ -100,7 +107,8 @@ func (p *Plugin) OnActivate() error {
|
|||
FilesDriver: *mmconfig.FileSettings.DriverName,
|
||||
FilesPath: *mmconfig.FileSettings.Directory,
|
||||
FilesS3Config: filesS3Config,
|
||||
Telemetry: true,
|
||||
Telemetry: enableTelemetry,
|
||||
TelemetryID: serverID,
|
||||
WebhookUpdate: []string{},
|
||||
SessionExpireTime: 2592000,
|
||||
SessionRefreshTime: 18000,
|
||||
|
@ -122,7 +130,6 @@ func (p *Plugin) OnActivate() error {
|
|||
db = layeredStore
|
||||
}
|
||||
|
||||
serverID := client.System.GetDiagnosticID()
|
||||
p.wsPluginAdapter = ws.NewPluginAdapter(p.API, auth.New(cfg, db))
|
||||
|
||||
server, err := server.New(cfg, "", db, logger, serverID, p.wsPluginAdapter)
|
||||
|
|
|
@ -5,6 +5,8 @@ import {Store, Action} from 'redux'
|
|||
import {Provider as ReduxProvider} from 'react-redux'
|
||||
import {useHistory} from 'mm-react-router-dom'
|
||||
|
||||
import {rudderAnalytics, RudderTelemetryHandler} from 'mattermost-redux/client/rudder'
|
||||
|
||||
import {GlobalState} from 'mattermost-redux/types/store'
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences'
|
||||
|
||||
|
@ -20,9 +22,12 @@ import FocalboardIcon from '../../../webapp/src/widgets/icons/logo'
|
|||
import {setMattermostTheme} from '../../../webapp/src/theme'
|
||||
import wsClient, {MMWebSocketClient, ACTION_UPDATE_BLOCK} from './../../../webapp/src/wsclient'
|
||||
|
||||
import TelemetryClient from '../../../webapp/src/telemetry/telemetryClient'
|
||||
|
||||
import '../../../webapp/src/styles/focalboard-variables.scss'
|
||||
import '../../../webapp/src/styles/main.scss'
|
||||
import '../../../webapp/src/styles/labels.scss'
|
||||
import octoClient from '../../../webapp/src/octoClient'
|
||||
|
||||
import manifest from './manifest'
|
||||
import ErrorBoundary from './error_boundary'
|
||||
|
@ -32,6 +37,22 @@ import {PluginRegistry} from './types/mattermost-webapp'
|
|||
|
||||
import './plugin.scss'
|
||||
|
||||
const TELEMETRY_RUDDER_KEY = 'placeholder_rudder_key'
|
||||
const TELEMETRY_RUDDER_DATAPLANE_URL = 'placeholder_rudder_dataplane_url'
|
||||
const TELEMETRY_OPTIONS = {
|
||||
context: {
|
||||
ip: '0.0.0.0',
|
||||
},
|
||||
page: {
|
||||
path: '',
|
||||
referrer: '',
|
||||
search: '',
|
||||
title: '',
|
||||
url: '',
|
||||
},
|
||||
anonymousId: '00000000000000000000000000',
|
||||
}
|
||||
|
||||
type Props = {
|
||||
webSocketClient: MMWebSocketClient
|
||||
}
|
||||
|
@ -150,6 +171,32 @@ export default class Plugin {
|
|||
this.registry.registerCustomRoute('/', MainApp)
|
||||
}
|
||||
|
||||
const config = await octoClient.getClientConfig()
|
||||
if (config?.telemetry) {
|
||||
let rudderKey = TELEMETRY_RUDDER_KEY
|
||||
let rudderUrl = TELEMETRY_RUDDER_DATAPLANE_URL
|
||||
|
||||
if (rudderKey.startsWith('placeholder') && rudderUrl.startsWith('placeholder')) {
|
||||
rudderKey = process.env.RUDDER_KEY as string //eslint-disable-line no-process-env
|
||||
rudderUrl = process.env.RUDDER_DATAPLANE_URL as string //eslint-disable-line no-process-env
|
||||
}
|
||||
|
||||
if (rudderKey !== '') {
|
||||
rudderAnalytics.load(rudderKey, rudderUrl)
|
||||
|
||||
rudderAnalytics.identify(config?.telemetryid, {}, TELEMETRY_OPTIONS)
|
||||
|
||||
rudderAnalytics.page('BoardsLoaded', '',
|
||||
TELEMETRY_OPTIONS.page,
|
||||
{
|
||||
context: TELEMETRY_OPTIONS.context,
|
||||
anonymousId: TELEMETRY_OPTIONS.anonymousId,
|
||||
})
|
||||
|
||||
TelemetryClient.setTelemetryHandler(new RudderTelemetryHandler())
|
||||
}
|
||||
}
|
||||
|
||||
// register websocket handlers
|
||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_BLOCK}`, (e: any) => wsClient.updateBlockHandler(e.data))
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
color: rgba(var(--center-channel-text-rgb), 1);
|
||||
|
||||
i {
|
||||
color: inherit;
|
||||
color: var(--link-color-rgb);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
|
|
@ -143,3 +143,11 @@ module.exports = {
|
|||
mode,
|
||||
plugins,
|
||||
};
|
||||
|
||||
const env = {};
|
||||
env.RUDDER_KEY = JSON.stringify(process.env.RUDDER_KEY || ''); //eslint-disable-line no-process-env
|
||||
env.RUDDER_DATAPLANE_URL = JSON.stringify(process.env.RUDDER_DATAPLANE_URL || ''); //eslint-disable-line no-process-env
|
||||
|
||||
module.exports.plugins.push(new webpack.DefinePlugin({
|
||||
'process.env': env,
|
||||
}));
|
||||
|
|
|
@ -90,6 +90,7 @@ func (a *API) RegisterRoutes(r *mux.Router) {
|
|||
|
||||
apiv1.HandleFunc("/login", a.handleLogin).Methods("POST")
|
||||
apiv1.HandleFunc("/register", a.handleRegister).Methods("POST")
|
||||
apiv1.HandleFunc("/clientConfig", a.getClientConfig).Methods("GET")
|
||||
|
||||
apiv1.HandleFunc("/workspaces/{workspaceID}/{rootID}/files", a.sessionRequired(a.handleUploadFile)).Methods("POST")
|
||||
|
||||
|
@ -115,6 +116,17 @@ func (a *API) requireCSRFToken(next http.Handler) http.Handler {
|
|||
})
|
||||
}
|
||||
|
||||
func (a *API) getClientConfig(w http.ResponseWriter, r *http.Request) {
|
||||
clientConfig := a.app.GetClientConfig()
|
||||
|
||||
configData, err := json.Marshal(clientConfig)
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
}
|
||||
jsonBytesResponse(w, http.StatusOK, configData)
|
||||
}
|
||||
|
||||
func (a *API) checkCSRFToken(r *http.Request) bool {
|
||||
token := r.Header.Get(HeaderRequestedWith)
|
||||
return token == HeaderRequestedWithXML
|
||||
|
|
12
server/app/clientConfig.go
Normal file
12
server/app/clientConfig.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"github.com/mattermost/focalboard/server/model"
|
||||
)
|
||||
|
||||
func (a *App) GetClientConfig() *model.ClientConfig {
|
||||
return &model.ClientConfig{
|
||||
Telemetry: a.config.Telemetry,
|
||||
TelemetryID: a.config.TelemetryID,
|
||||
}
|
||||
}
|
6
server/model/clientConfig.go
Normal file
6
server/model/clientConfig.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package model
|
||||
|
||||
type ClientConfig struct {
|
||||
Telemetry bool `json:"telemetry"`
|
||||
TelemetryID string `json:"telemetryid"`
|
||||
}
|
|
@ -38,6 +38,7 @@ type Configuration struct {
|
|||
FilesS3Config AmazonS3Config `json:"filess3config" mapstructure:"filess3config"`
|
||||
FilesPath string `json:"filespath" mapstructure:"filespath"`
|
||||
Telemetry bool `json:"telemetry" mapstructure:"telemetry"`
|
||||
TelemetryID string `json:"telemetryid" mapstructure:"telemetryid"`
|
||||
PrometheusAddress string `json:"prometheus_address" mapstructure:"prometheus_address"`
|
||||
WebhookUpdate []string `json:"webhook_update" mapstructure:"webhook_update"`
|
||||
Secret string `json:"secret" mapstructure:"secret"`
|
||||
|
@ -73,6 +74,7 @@ func ReadConfigFile() (*Configuration, error) {
|
|||
viper.SetDefault("FilesPath", "./files")
|
||||
viper.SetDefault("FilesDriver", "local")
|
||||
viper.SetDefault("Telemetry", true)
|
||||
viper.SetDefault("TelemetryID", "")
|
||||
viper.SetDefault("WebhookUpdate", nil)
|
||||
viper.SetDefault("SessionExpireTime", 60*60*24*30) // 30 days session lifetime
|
||||
viper.SetDefault("SessionRefreshTime", 60*60*5) // 5 minutes session refresh
|
||||
|
|
62
webapp/i18n/ar.json
Normal file
62
webapp/i18n/ar.json
Normal file
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"BoardComponent.add-a-group": "+ إضافة فريق",
|
||||
"BoardComponent.delete": "حذف",
|
||||
"BoardComponent.hidden-columns": "الأعمدية المخفية",
|
||||
"BoardComponent.hide": "إخفاء",
|
||||
"BoardComponent.new": "+ جديد",
|
||||
"BoardComponent.show": "عرض",
|
||||
"CardDetail.add-content": "إضافة محتوى",
|
||||
"CardDetail.add-icon": "إضافة أيقونة",
|
||||
"CardDetail.new-comment-placeholder": "إضافة تعليق…",
|
||||
"Comment.delete": "حذف",
|
||||
"CommentsList.send": "إرسال",
|
||||
"ContentBlock.Delete": "حذف",
|
||||
"ContentBlock.DeleteAction": "حذف",
|
||||
"ContentBlock.addElement": "إضافة {type}",
|
||||
"ContentBlock.text": "نص",
|
||||
"DashboardPage.title": "أهلًا بك إلى Focalboard (تجريبي)!",
|
||||
"EditableDayPicker.today": "اليوم",
|
||||
"Filter.is-empty": "فارغ",
|
||||
"Filter.is-not-empty": "ليس فارغًا",
|
||||
"FilterComponent.add-filter": "+ إضافة عامل تصفية",
|
||||
"FilterComponent.delete": "حذف",
|
||||
"GalleryCard.delete": "حذف",
|
||||
"KanbanCard.delete": "حذف",
|
||||
"PropertyMenu.Delete": "حذف",
|
||||
"PropertyMenu.typeTitle": "النوع",
|
||||
"PropertyType.CreatedBy": "قام بإنشائها",
|
||||
"PropertyType.Date": "التاريخ",
|
||||
"PropertyType.Email": "البريد الإلكتروني",
|
||||
"PropertyType.File": "ملف أو وسائط",
|
||||
"PropertyType.Number": "رقم",
|
||||
"PropertyType.Person": "شخص",
|
||||
"PropertyType.Text": "نص",
|
||||
"PropertyType.URL": "رابط URL",
|
||||
"RegistrationLink.copiedLink": "تم نسخها",
|
||||
"RegistrationLink.copyLink": "انسخ الرابط",
|
||||
"ShareBoard.copiedLink": "تم نسخها!",
|
||||
"ShareBoard.copyLink": "انسخ الرابط",
|
||||
"Sidebar.about": "عن Focalboard",
|
||||
"Sidebar.add-template": "نموذج جديد",
|
||||
"Sidebar.changePassword": "تغيير الكلمة السرية",
|
||||
"Sidebar.delete-template": "حذف",
|
||||
"Sidebar.edit-template": "تعديل",
|
||||
"Sidebar.logout": "الخروج",
|
||||
"Sidebar.set-language": "ضبط اللغة",
|
||||
"Sidebar.settings": "الإعدادت",
|
||||
"TableComponent.add-icon": "إضافة أيقونة",
|
||||
"TableComponent.name": "الإسم",
|
||||
"TableComponent.plus-new": "+ جديد",
|
||||
"TableHeaderMenu.delete": "حذف",
|
||||
"TableHeaderMenu.hide": "إخفاء",
|
||||
"TableRow.open": "افتح",
|
||||
"View.Table": "جدول",
|
||||
"ViewHeader.add-template": "نموذج جديد",
|
||||
"ViewHeader.delete-template": "حذف",
|
||||
"ViewHeader.new": "جديز",
|
||||
"ViewHeader.search": "البحث",
|
||||
"ViewTitle.pick-icon": "اختر أيقونة",
|
||||
"default-properties.title": "العنوان",
|
||||
"login.log-in-button": "لِج",
|
||||
"login.log-in-title": "لِج"
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
"CardDetail.new-comment-placeholder": "Lägg till kommentar...",
|
||||
"CardDialog.editing-template": "Du redigerar en mall",
|
||||
"CardDialog.nocard": "Detta kort existerar inte eller är oåtkomligt",
|
||||
"ColorOption.selectColor": "Välj {color} färg",
|
||||
"Comment.delete": "Radera",
|
||||
"CommentsList.send": "Skicka",
|
||||
"ContentBlock.Delete": "Radera",
|
||||
|
@ -120,6 +121,8 @@
|
|||
"TableHeaderMenu.sort-ascending": "Sortera stigande",
|
||||
"TableHeaderMenu.sort-descending": "Sortera fallande",
|
||||
"TableRow.open": "Öppna",
|
||||
"ValueSelector.valueSelector": "Värdeväljare",
|
||||
"ValueSelectorLabel.openMenu": "Öppna meny",
|
||||
"View.AddView": "Lägg till vy",
|
||||
"View.Board": "Tavla",
|
||||
"View.DeleteView": "Radera vy",
|
||||
|
|
|
@ -12,6 +12,8 @@ import {DndProvider} from 'react-dnd'
|
|||
import {HTML5Backend} from 'react-dnd-html5-backend'
|
||||
import {TouchBackend} from 'react-dnd-touch-backend'
|
||||
|
||||
import TelemetryClient from './telemetry/telemetryClient'
|
||||
|
||||
import {getMessages} from './i18n'
|
||||
import {FlashMessages} from './components/flashMessages'
|
||||
import BoardPage from './pages/boardPage'
|
||||
|
@ -22,15 +24,18 @@ import LoginPage from './pages/loginPage'
|
|||
import RegisterPage from './pages/registerPage'
|
||||
import {Utils} from './utils'
|
||||
import wsClient from './wsclient'
|
||||
import {fetchMe, getLoggedIn} from './store/users'
|
||||
import {fetchMe, getLoggedIn, getMe} from './store/users'
|
||||
import {getLanguage, fetchLanguage} from './store/language'
|
||||
import {setGlobalError, getGlobalError} from './store/globalError'
|
||||
import {useAppSelector, useAppDispatch} from './store/hooks'
|
||||
|
||||
import {IUser} from './user'
|
||||
|
||||
const App = React.memo((): JSX.Element => {
|
||||
const language = useAppSelector<string>(getLanguage)
|
||||
const loggedIn = useAppSelector<boolean|null>(getLoggedIn)
|
||||
const globalError = useAppSelector<string>(getGlobalError)
|
||||
const me = useAppSelector<IUser|null>(getMe)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -45,6 +50,12 @@ const App = React.memo((): JSX.Element => {
|
|||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (me) {
|
||||
TelemetryClient.setUser(me)
|
||||
}
|
||||
}, [me])
|
||||
|
||||
let globalErrorRedirect = null
|
||||
if (globalError) {
|
||||
globalErrorRedirect = <Route path='/*'><Redirect to={`/error?id=${globalError}`}/></Route>
|
||||
|
|
|
@ -19,6 +19,8 @@ import {updateView} from '../store/views'
|
|||
|
||||
import './centerPanel.scss'
|
||||
|
||||
import TelemetryClient from '../../../webapp/src/telemetry/telemetryClient'
|
||||
|
||||
import CardDialog from './cardDialog'
|
||||
import RootPortal from './rootPortal'
|
||||
import TopBar from './topBar'
|
||||
|
@ -80,6 +82,10 @@ class CenterPanel extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
TelemetryClient.trackEvent('boards', 'view', {viewType: this.props.activeView.fields.viewType})
|
||||
}
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
@ -92,6 +98,10 @@ class CenterPanel extends React.Component<Props, State> {
|
|||
return true
|
||||
}
|
||||
|
||||
componentDidUpdate(): void {
|
||||
TelemetryClient.trackEvent('boards', 'view', {viewType: this.props.activeView.fields.viewType})
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const {groupByProperty, activeView, board, views, cards} = this.props
|
||||
const {visible: visibleGroups, hidden: hiddenGroups} = this.getVisibleAndHiddenGroups(cards, activeView.fields.visibleOptionIds, activeView.fields.hiddenOptionIds, groupByProperty)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
align-items: center;
|
||||
|
||||
> div {
|
||||
margin-right: 16px;
|
||||
margin-right: 12px;
|
||||
white-space: nowrap;
|
||||
|
||||
&:last-child {
|
||||
|
|
7
webapp/src/config/clientConfig.ts
Normal file
7
webapp/src/config/clientConfig.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export type ClientConfig = {
|
||||
telemetry: boolean,
|
||||
telemetryid: string,
|
||||
}
|
|
@ -6,6 +6,7 @@ import {IWorkspace} from './blocks/workspace'
|
|||
import {OctoUtils} from './octoUtils'
|
||||
import {IUser} from './user'
|
||||
import {Utils} from './utils'
|
||||
import {ClientConfig} from './config/clientConfig'
|
||||
|
||||
//
|
||||
// OctoClient is the client interface to the server APIs
|
||||
|
@ -64,6 +65,20 @@ class OctoClient {
|
|||
localStorage.removeItem('focalboardSessionId')
|
||||
}
|
||||
|
||||
async getClientConfig(): Promise<ClientConfig | null> {
|
||||
const path = '/api/v1/clientConfig'
|
||||
const response = await fetch(this.serverUrl + path, {
|
||||
method: 'GET',
|
||||
headers: this.headers(),
|
||||
})
|
||||
if (response.status !== 200) {
|
||||
return null
|
||||
}
|
||||
|
||||
const json = (await this.getJson(response, {})) as ClientConfig
|
||||
return json
|
||||
}
|
||||
|
||||
async register(email: string, username: string, password: string, token?: string): Promise<{code: number, json: any}> {
|
||||
const path = '/api/v1/register'
|
||||
const body = JSON.stringify({email, username, password, token})
|
||||
|
|
7
webapp/src/telemetry/telemetry.ts
Normal file
7
webapp/src/telemetry/telemetry.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export interface TelemetryHandler {
|
||||
trackEvent: (userId: string, userRoles: string, category: string, event: string, props?: any) => void;
|
||||
pageVisited: (userId: string, userRoles: string, category: string, name: string) => void;
|
||||
}
|
24
webapp/src/telemetry/telemetryClient.test.ts
Normal file
24
webapp/src/telemetry/telemetryClient.test.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import '@testing-library/jest-dom'
|
||||
|
||||
import TelemetryClient from './telemetryClient'
|
||||
|
||||
describe('trackEvent', () => {
|
||||
const track = jest.fn()
|
||||
const page = jest.fn()
|
||||
test('should call Rudder\'s track when a RudderTelemetryHandler is attached to TelemetryClient', () => {
|
||||
TelemetryClient.setTelemetryHandler()
|
||||
TelemetryClient.trackEvent('test', 'onClick')
|
||||
TelemetryClient.pageVisited('focalboard', 'test')
|
||||
expect(track).not.toHaveBeenCalled()
|
||||
expect(page).not.toHaveBeenCalled()
|
||||
|
||||
TelemetryClient.setTelemetryHandler({trackEvent: track, pageVisited: page})
|
||||
TelemetryClient.trackEvent('test', 'onClick')
|
||||
TelemetryClient.pageVisited('focalboard', 'test')
|
||||
|
||||
expect(track).toHaveBeenCalledTimes(1)
|
||||
expect(page).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
37
webapp/src/telemetry/telemetryClient.ts
Normal file
37
webapp/src/telemetry/telemetryClient.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import {IUser} from '../user'
|
||||
|
||||
import {TelemetryHandler} from './telemetry'
|
||||
|
||||
class TelemetryClient {
|
||||
public telemetryHandler?: TelemetryHandler
|
||||
public user?: IUser
|
||||
|
||||
setTelemetryHandler(telemetryHandler?: TelemetryHandler): void {
|
||||
this.telemetryHandler = telemetryHandler
|
||||
}
|
||||
|
||||
setUser(user: IUser): void {
|
||||
this.user = user
|
||||
}
|
||||
|
||||
trackEvent(category: string, event: string, props?: any): void {
|
||||
if (this.telemetryHandler) {
|
||||
const userId = this.user?.id
|
||||
this.telemetryHandler.trackEvent(userId || '', '', category, event, props)
|
||||
}
|
||||
}
|
||||
|
||||
pageVisited(category: string, name: string): void {
|
||||
if (this.telemetryHandler) {
|
||||
const userId = this.user?.id
|
||||
this.telemetryHandler.pageVisited(userId || '', '', category, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const telemetryClient = new TelemetryClient()
|
||||
|
||||
export {TelemetryClient}
|
||||
export default telemetryClient
|
|
@ -1,4 +1,5 @@
|
|||
.Button {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
|
@ -12,6 +13,8 @@
|
|||
border: 0;
|
||||
transition: background 100ms ease-out 0s;
|
||||
color: inherit;
|
||||
height: 32px;
|
||||
padding: 0 10px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(var(--center-channel-color-rgb), 0.1);
|
||||
|
@ -41,7 +44,8 @@
|
|||
}
|
||||
|
||||
&.active {
|
||||
color: rgb(var(--link-color));
|
||||
background: rgba(var(--button-bg-rgb), 0.08);
|
||||
color: rgb(var(--button-bg-rgb));
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue