Copy disabled (too large)
Download .txt
Showing preview only (11,952K chars total). Download the full file to get everything.
Repository: mattermost-community/focalboard
Branch: main
Commit: a84bbb65e32e
Files: 1547
Total size: 11.1 MB
Directory structure:
gitextract_a_j2svim/
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── doc_improvement.md
│ │ └── enhancement.md
│ ├── codeql/
│ │ └── codeql-config.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── codeql-analysis.yml
│ ├── dev-release.yml
│ ├── lint-server.yml
│ ├── prod-release.yml
│ └── scorecards-analysis.yml
├── .gitignore
├── .gitlab-ci.yml
├── .gitpod.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile.build
├── LICENSE.txt
├── Makefile
├── NOTICE.txt
├── README.md
├── SECURITY.md
├── app-config.json
├── config.json
├── docker/
│ ├── Dockerfile
│ ├── README.md
│ ├── config.json
│ ├── docker-compose-db-nginx.yml
│ ├── docker-compose.yml
│ └── server_config.json
├── docker-testing/
│ ├── docker-compose-mariadb.yml
│ ├── docker-compose-mysql.yml
│ └── docker-compose-postgres.yml
├── docs/
│ ├── README.md
│ ├── _config.yml
│ ├── code-review.md
│ ├── contribution-checklist.md
│ ├── contributions-without-ticket.md
│ ├── core-committers.md
│ ├── dev-tips.md
│ ├── focalboard-dev-guide.md
│ └── index.md
├── experiments/
│ └── webext/
│ ├── .gitignore
│ ├── .parcelrc
│ ├── README.md
│ ├── manifest.json
│ ├── package.json
│ ├── src/
│ │ ├── utils/
│ │ │ ├── Board.ts
│ │ │ ├── networking.ts
│ │ │ └── settings.ts
│ │ └── views/
│ │ ├── OptionsApp.scss
│ │ ├── OptionsApp.tsx
│ │ ├── PopupApp.scss
│ │ ├── PopupApp.tsx
│ │ ├── options.html
│ │ ├── options.tsx
│ │ ├── popup.html
│ │ └── popup.tsx
│ └── tsconfig.json
├── import/
│ ├── README.md
│ ├── asana/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── asana.ts
│ │ ├── importAsana.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── jira/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importJira.ts
│ │ ├── jiraImporter.test.ts
│ │ ├── jiraImporter.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── nextcloud-deck/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── deck.ts
│ │ ├── importDeck.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── notion/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importNotion.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── todoist/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importTodoist.ts
│ │ ├── package.json
│ │ ├── todoist.ts
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── trello/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importTrello.ts
│ │ ├── package.json
│ │ ├── trello.ts
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ └── util/
│ └── archive.ts
├── linux/
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── mac/
│ ├── Focalboard/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AccentColor.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── AutoSaveWindowController.swift
│ │ ├── Base.lproj/
│ │ │ └── Main.storyboard
│ │ ├── CustomWKWebView.swift
│ │ ├── DownloadHandler.swift
│ │ ├── Focalboard.entitlements
│ │ ├── Globals.swift
│ │ ├── Info.plist
│ │ ├── Inherit.entitlements
│ │ ├── PortUtils.swift
│ │ ├── ViewController.swift
│ │ ├── WhatsNewViewController.swift
│ │ └── whatsnew.txt
│ ├── Focalboard.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Focalboard.xcscheme
│ ├── Focalboard.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ ├── FocalboardTests/
│ │ ├── FocalboardTests.swift
│ │ └── Info.plist
│ ├── FocalboardUITests/
│ │ ├── FocalboardUITests.swift
│ │ └── Info.plist
│ ├── README.md
│ └── export.plist
├── modd-servertest.conf
├── modd.conf
├── noticegen/
│ ├── Readme.md
│ └── config.yaml
├── pull_request_template.md
├── responsible_disclosure_policy.md
├── server/
│ ├── .golangci.yml
│ ├── admin-scripts/
│ │ └── reset-password.sh
│ ├── api/
│ │ ├── admin.go
│ │ ├── api.go
│ │ ├── api_test.go
│ │ ├── archive.go
│ │ ├── audit.go
│ │ ├── auth.go
│ │ ├── blocks.go
│ │ ├── boards.go
│ │ ├── boards_and_blocks.go
│ │ ├── cards.go
│ │ ├── categories.go
│ │ ├── channels.go
│ │ ├── compliance.go
│ │ ├── config.go
│ │ ├── content_blocks.go
│ │ ├── context.go
│ │ ├── files.go
│ │ ├── members.go
│ │ ├── onboarding.go
│ │ ├── search.go
│ │ ├── sharing.go
│ │ ├── statistics.go
│ │ ├── subscriptions.go
│ │ ├── system.go
│ │ ├── system_test.go
│ │ ├── teams.go
│ │ ├── templates.go
│ │ └── users.go
│ ├── app/
│ │ ├── app.go
│ │ ├── app_test.go
│ │ ├── auth.go
│ │ ├── auth_test.go
│ │ ├── blocks.go
│ │ ├── blocks_test.go
│ │ ├── boards.go
│ │ ├── boards_and_blocks.go
│ │ ├── boards_test.go
│ │ ├── cards.go
│ │ ├── cards_test.go
│ │ ├── category.go
│ │ ├── category_boards.go
│ │ ├── category_boards_test.go
│ │ ├── category_test.go
│ │ ├── clientConfig.go
│ │ ├── clientConfig_test.go
│ │ ├── compliance.go
│ │ ├── content_blocks.go
│ │ ├── content_blocks_test.go
│ │ ├── export.go
│ │ ├── files.go
│ │ ├── files_test.go
│ │ ├── helper_test.go
│ │ ├── import.go
│ │ ├── import_test.go
│ │ ├── initialize.go
│ │ ├── onboarding.go
│ │ ├── onboarding_test.go
│ │ ├── permissions.go
│ │ ├── server_metadata.go
│ │ ├── server_metadata_test.go
│ │ ├── sharing.go
│ │ ├── sharing_test.go
│ │ ├── statistics.go
│ │ ├── subscriptions.go
│ │ ├── teams.go
│ │ ├── teams_test.go
│ │ ├── templates.go
│ │ ├── templates_test.go
│ │ ├── user.go
│ │ └── user_test.go
│ ├── assets/
│ │ ├── assets.go
│ │ ├── build-template-archive/
│ │ │ └── main.go
│ │ └── templates-boardarchive/
│ │ ├── b7wnw9awd4pnefryhq51apbzb4c/
│ │ │ └── board.jsonl
│ │ ├── bbkpwdj8x17bdpdqd176n8ctoua/
│ │ │ └── board.jsonl
│ │ ├── bbn1888mprfrm5fjw9f1je9x3xo/
│ │ │ └── board.jsonl
│ │ ├── bc41mwxg9ybb69pn9j5zna6d36c/
│ │ │ └── board.jsonl
│ │ ├── bcm39o11e4ib8tye8mt6iyuec9o/
│ │ │ └── board.jsonl
│ │ ├── bd65qbzuqupfztpg31dgwgwm5ga/
│ │ │ └── board.jsonl
│ │ ├── bgi1yqiis8t8xdqxgnet8ebutky/
│ │ │ └── board.jsonl
│ │ ├── bh4pkixqsjift58e1qy6htrgeay/
│ │ │ └── board.jsonl
│ │ ├── bkqk6hpfx7pbsucue7jan5n1o1o/
│ │ │ └── board.jsonl
│ │ ├── brs9cdimfw7fodyi7erqt747rhc/
│ │ │ └── board.jsonl
│ │ ├── bsjd59qtpbf888mqez3ge77domw/
│ │ │ └── board.jsonl
│ │ ├── bui5izho7dtn77xg3thkiqprc9r/
│ │ │ └── board.jsonl
│ │ ├── buixxjic3xjfkieees4iafdrznc/
│ │ │ └── board.jsonl
│ │ └── version.json
│ ├── auth/
│ │ ├── auth.go
│ │ ├── auth_test.go
│ │ └── mocks/
│ │ └── mockauth_interface.go
│ ├── client/
│ │ └── client.go
│ ├── go.mod
│ ├── go.sum
│ ├── go.tools.mod
│ ├── go.tools.sum
│ ├── integrationtests/
│ │ ├── blocks_test.go
│ │ ├── board_test.go
│ │ ├── boards_and_blocks_test.go
│ │ ├── cards_test.go
│ │ ├── clienttestlib.go
│ │ ├── compliance_test.go
│ │ ├── content_blocks_test.go
│ │ ├── export_test.go
│ │ ├── file_test.go
│ │ ├── permissions_test.go
│ │ ├── pluginteststore.go
│ │ ├── sharing_test.go
│ │ ├── sidebar_test.go
│ │ ├── subscriptions_test.go
│ │ ├── teststore.go
│ │ ├── user_test.go
│ │ └── work_template_test.go
│ ├── main/
│ │ ├── doc.go
│ │ └── main.go
│ ├── model/
│ │ ├── auth.go
│ │ ├── block.go
│ │ ├── block_test.go
│ │ ├── blockid.go
│ │ ├── blocktype.go
│ │ ├── board.go
│ │ ├── board_statistics.go
│ │ ├── boards_and_blocks.go
│ │ ├── boards_and_blocks_test.go
│ │ ├── card.go
│ │ ├── card_test.go
│ │ ├── category.go
│ │ ├── category_boards.go
│ │ ├── clientConfig.go
│ │ ├── cloud.go
│ │ ├── compliance.go
│ │ ├── database.go
│ │ ├── error.go
│ │ ├── errorResponse.go
│ │ ├── file.go
│ │ ├── import_export.go
│ │ ├── log_level.go
│ │ ├── mocks/
│ │ │ ├── mockservicesapi.go
│ │ │ └── propValueResolverMock.go
│ │ ├── notification.go
│ │ ├── permission.go
│ │ ├── properties.go
│ │ ├── properties_test.go
│ │ ├── services_api.go
│ │ ├── sharing.go
│ │ ├── subscription.go
│ │ ├── team.go
│ │ ├── user.go
│ │ ├── util.go
│ │ └── version.go
│ ├── server/
│ │ ├── initHandlers.go
│ │ ├── params.go
│ │ └── server.go
│ ├── services/
│ │ ├── audit/
│ │ │ ├── audit.go
│ │ │ ├── record.go
│ │ │ └── record_test.go
│ │ ├── auth/
│ │ │ ├── email.go
│ │ │ ├── password.go
│ │ │ ├── password_test.go
│ │ │ ├── request_parser.go
│ │ │ └── request_parser_test.go
│ │ ├── config/
│ │ │ └── config.go
│ │ ├── metrics/
│ │ │ ├── metrics.go
│ │ │ └── service.go
│ │ ├── notify/
│ │ │ ├── notifylogger/
│ │ │ │ └── logger_backend.go
│ │ │ ├── notifymentions/
│ │ │ │ ├── app_api.go
│ │ │ │ ├── delivery.go
│ │ │ │ ├── extract.go
│ │ │ │ ├── extract_test.go
│ │ │ │ ├── mentions.go
│ │ │ │ ├── mentions_backend.go
│ │ │ │ └── mentions_test.go
│ │ │ ├── notifysubscriptions/
│ │ │ │ ├── app_api.go
│ │ │ │ ├── delivery.go
│ │ │ │ ├── diff.go
│ │ │ │ ├── diff2markdown.go
│ │ │ │ ├── diff2markdown_test.go
│ │ │ │ ├── diff2slackattachments.go
│ │ │ │ ├── notifier.go
│ │ │ │ ├── subscriptions_backend.go
│ │ │ │ └── util.go
│ │ │ ├── plugindelivery/
│ │ │ │ ├── mention_deliver.go
│ │ │ │ ├── message.go
│ │ │ │ ├── plugin_delivery.go
│ │ │ │ ├── subscription_deliver.go
│ │ │ │ ├── user.go
│ │ │ │ └── user_test.go
│ │ │ └── service.go
│ │ ├── permissions/
│ │ │ ├── localpermissions/
│ │ │ │ ├── helpers_test.go
│ │ │ │ ├── localpermissions.go
│ │ │ │ └── localpermissions_test.go
│ │ │ ├── mmpermissions/
│ │ │ │ ├── helpers_test.go
│ │ │ │ ├── mmpermissions.go
│ │ │ │ ├── mmpermissions_test.go
│ │ │ │ └── mocks/
│ │ │ │ └── mockpluginapi.go
│ │ │ ├── mocks/
│ │ │ │ └── mockstore.go
│ │ │ └── permissions.go
│ │ ├── scheduler/
│ │ │ ├── scheduler.go
│ │ │ └── scheduler_test.go
│ │ ├── store/
│ │ │ ├── generators/
│ │ │ │ ├── main.go
│ │ │ │ └── transactional_store.go.tmpl
│ │ │ ├── mattermostauthlayer/
│ │ │ │ ├── mattermostauthlayer.go
│ │ │ │ └── mattermostauthlayer_test.go
│ │ │ ├── mockstore/
│ │ │ │ └── mockstore.go
│ │ │ ├── sqlstore/
│ │ │ │ ├── blocks.go
│ │ │ │ ├── board.go
│ │ │ │ ├── boards_and_blocks.go
│ │ │ │ ├── category.go
│ │ │ │ ├── category_boards.go
│ │ │ │ ├── cloud.go
│ │ │ │ ├── compliance.go
│ │ │ │ ├── data_migrations.go
│ │ │ │ ├── data_migrations_test.go
│ │ │ │ ├── data_retention.go
│ │ │ │ ├── file.go
│ │ │ │ ├── helpers_test.go
│ │ │ │ ├── legacy_blocks.go
│ │ │ │ ├── migrate.go
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 000001_init.down.sql
│ │ │ │ │ ├── 000001_init.up.sql
│ │ │ │ │ ├── 000002_system_settings_table.down.sql
│ │ │ │ │ ├── 000002_system_settings_table.up.sql
│ │ │ │ │ ├── 000003_blocks_rootid.down.sql
│ │ │ │ │ ├── 000003_blocks_rootid.up.sql
│ │ │ │ │ ├── 000004_auth_table.down.sql
│ │ │ │ │ ├── 000004_auth_table.up.sql
│ │ │ │ │ ├── 000005_blocks_modifiedby.down.sql
│ │ │ │ │ ├── 000005_blocks_modifiedby.up.sql
│ │ │ │ │ ├── 000006_sharing_table.down.sql
│ │ │ │ │ ├── 000006_sharing_table.up.sql
│ │ │ │ │ ├── 000007_workspaces_table.down.sql
│ │ │ │ │ ├── 000007_workspaces_table.up.sql
│ │ │ │ │ ├── 000008_teams.down.sql
│ │ │ │ │ ├── 000008_teams.up.sql
│ │ │ │ │ ├── 000009_blocks_history.down.sql
│ │ │ │ │ ├── 000009_blocks_history.up.sql
│ │ │ │ │ ├── 000010_blocks_created_by.down.sql
│ │ │ │ │ ├── 000010_blocks_created_by.up.sql
│ │ │ │ │ ├── 000011_match_collation.down.sql
│ │ │ │ │ ├── 000011_match_collation.up.sql
│ │ │ │ │ ├── 000012_match_column_collation.down.sql
│ │ │ │ │ ├── 000012_match_column_collation.up.sql
│ │ │ │ │ ├── 000013_millisecond_timestamps.down.sql
│ │ │ │ │ ├── 000013_millisecond_timestamps.up.sql
│ │ │ │ │ ├── 000014_add_not_null_constraint.down.sql
│ │ │ │ │ ├── 000014_add_not_null_constraint.up.sql
│ │ │ │ │ ├── 000015_blocks_history_no_nulls.down.sql
│ │ │ │ │ ├── 000015_blocks_history_no_nulls.up.sql
│ │ │ │ │ ├── 000016_subscriptions_table.down.sql
│ │ │ │ │ ├── 000016_subscriptions_table.up.sql
│ │ │ │ │ ├── 000017_add_file_info.down.sql
│ │ │ │ │ ├── 000017_add_file_info.up.sql
│ │ │ │ │ ├── 000018_add_teams_and_boards.down.sql
│ │ │ │ │ ├── 000018_add_teams_and_boards.up.sql
│ │ │ │ │ ├── 000019_populate_categories.down.sql
│ │ │ │ │ ├── 000019_populate_categories.up.sql
│ │ │ │ │ ├── 000020_populate_category_blocks.down.sql
│ │ │ │ │ ├── 000020_populate_category_blocks.up.sql
│ │ │ │ │ ├── 000021_create_boards_members_history.down.sql
│ │ │ │ │ ├── 000021_create_boards_members_history.up.sql
│ │ │ │ │ ├── 000022_create_default_board_role.down.sql
│ │ │ │ │ ├── 000022_create_default_board_role.up.sql
│ │ │ │ │ ├── 000023_persist_category_collapsed_state.down.sql
│ │ │ │ │ ├── 000023_persist_category_collapsed_state.up.sql
│ │ │ │ │ ├── 000024_mark_existsing_categories_collapsed.down.sql
│ │ │ │ │ ├── 000024_mark_existsing_categories_collapsed.up.sql
│ │ │ │ │ ├── 000025_indexes_update.down.sql
│ │ │ │ │ ├── 000025_indexes_update.up.sql
│ │ │ │ │ ├── 000026_create_preferences_table.down.sql
│ │ │ │ │ ├── 000026_create_preferences_table.up.sql
│ │ │ │ │ ├── 000027_migrate_user_props_to_preferences.down.sql
│ │ │ │ │ ├── 000027_migrate_user_props_to_preferences.up.sql
│ │ │ │ │ ├── 000028_remove_template_channel_link.down.sql
│ │ │ │ │ ├── 000028_remove_template_channel_link.up.sql
│ │ │ │ │ ├── 000029_add_category_type_field.down.sql
│ │ │ │ │ ├── 000029_add_category_type_field.up.sql
│ │ │ │ │ ├── 000030_add_category_sort_order.down.sql
│ │ │ │ │ ├── 000030_add_category_sort_order.up.sql
│ │ │ │ │ ├── 000031_add_category_boards_sort_order.down.sql
│ │ │ │ │ ├── 000031_add_category_boards_sort_order.up.sql
│ │ │ │ │ ├── 000032_move_boards_category_to_end.down.sql
│ │ │ │ │ ├── 000032_move_boards_category_to_end.up.sql
│ │ │ │ │ ├── 000033_remove_deleted_category_boards.down.sql
│ │ │ │ │ ├── 000033_remove_deleted_category_boards.up.sql
│ │ │ │ │ ├── 000034_category_boards_remove_unused_delete_at_column.down.sql
│ │ │ │ │ ├── 000034_category_boards_remove_unused_delete_at_column.up.sql
│ │ │ │ │ ├── 000035_add_hidden_board_column.down.sql
│ │ │ │ │ ├── 000035_add_hidden_board_column.up.sql
│ │ │ │ │ ├── 000036_category_board_add_unique_constraint.down.sql
│ │ │ │ │ ├── 000036_category_board_add_unique_constraint.up.sql
│ │ │ │ │ ├── 000037_hidden_boards_from_preferences.down.sql
│ │ │ │ │ ├── 000037_hidden_boards_from_preferences.up.sql
│ │ │ │ │ ├── 000038_delete_hiddenBoardIDs_from_preferences.down.sql
│ │ │ │ │ ├── 000038_delete_hiddenBoardIDs_from_preferences.up.sql
│ │ │ │ │ ├── 000039_add_path_to_file_info.down.sql
│ │ │ │ │ ├── 000039_add_path_to_file_info.up.sql
│ │ │ │ │ ├── 000040_fix_fileinfo_soft_deletes.down.sql
│ │ │ │ │ ├── 000040_fix_fileinfo_soft_deletes.up.sql
│ │ │ │ │ └── README.md
│ │ │ │ ├── migrationstests/
│ │ │ │ │ ├── boards_migrator_test.go
│ │ │ │ │ ├── de_duplicate_category_boards_migration_test.go
│ │ │ │ │ ├── fixtures/
│ │ │ │ │ │ ├── deletedMembershipBoardsMigrationFixtures.sql
│ │ │ │ │ │ ├── test18AddTeamsAndBoardsSQLMigrationFixtures.sql
│ │ │ │ │ │ ├── test27MigrateUserPropsToPreferences.sql
│ │ │ │ │ │ ├── test28RemoveTemplateChannelLink.sql
│ │ │ │ │ │ ├── test33_with_deleted_data.sql
│ │ │ │ │ │ ├── test33_with_no_deleted_data.sql
│ │ │ │ │ │ ├── test34_drop_delete_at_column.sql
│ │ │ │ │ │ ├── test35_add_hidden_column.sql
│ │ │ │ │ │ ├── test36_add_unique_constraint.sql
│ │ │ │ │ │ ├── test37_valid_data.sql
│ │ │ │ │ │ ├── test37_valid_data_no_hidden_boards.sql
│ │ │ │ │ │ ├── test37_valid_data_preference_but_no_hidden_board.sql
│ │ │ │ │ │ ├── test37_valid_data_sqlite.sql
│ │ │ │ │ │ ├── test37_valid_data_sqlite_preference_but_no_hidden_board.sql
│ │ │ │ │ │ ├── test38_add_plugin_preferences.sql
│ │ │ │ │ │ ├── test38_add_standalone_preferences.sql
│ │ │ │ │ │ ├── test40FixFileinfoSoftDeletes.sql
│ │ │ │ │ │ └── testDeDuplicateCategoryBoardsMigration.sql
│ │ │ │ │ ├── helpers_test.go
│ │ │ │ │ ├── migrate_34_test.go
│ │ │ │ │ ├── migration35_test.go
│ │ │ │ │ ├── migration36_test.go
│ │ │ │ │ ├── migration37_test.go
│ │ │ │ │ ├── migration38_test.go
│ │ │ │ │ ├── migration_27_test.go
│ │ │ │ │ ├── migration_28_test.go
│ │ │ │ │ └── migration_33_test.go
│ │ │ │ ├── notificationhints.go
│ │ │ │ ├── params.go
│ │ │ │ ├── public_methods.go
│ │ │ │ ├── schema_table_migration.go
│ │ │ │ ├── schema_table_migration_test.go
│ │ │ │ ├── session.go
│ │ │ │ ├── sharing.go
│ │ │ │ ├── sqlite.go
│ │ │ │ ├── sqlstore.go
│ │ │ │ ├── sqlstore_test.go
│ │ │ │ ├── subscriptions.go
│ │ │ │ ├── system.go
│ │ │ │ ├── team.go
│ │ │ │ ├── templates.go
│ │ │ │ ├── user.go
│ │ │ │ └── util.go
│ │ │ ├── store.go
│ │ │ └── storetests/
│ │ │ ├── blocks.go
│ │ │ ├── boards.go
│ │ │ ├── boards_and_blocks.go
│ │ │ ├── category.go
│ │ │ ├── categoryBoards.go
│ │ │ ├── cloud.go
│ │ │ ├── compliance.go
│ │ │ ├── data_retention.go
│ │ │ ├── files.go
│ │ │ ├── helpers.go
│ │ │ ├── notificationhints.go
│ │ │ ├── session.go
│ │ │ ├── sharing.go
│ │ │ ├── subscriptions.go
│ │ │ ├── system.go
│ │ │ ├── teams.go
│ │ │ ├── users.go
│ │ │ └── util.go
│ │ ├── telemetry/
│ │ │ ├── mocks/
│ │ │ │ └── ServerIface.go
│ │ │ ├── telemetry.go
│ │ │ └── telemetry_test.go
│ │ └── webhook/
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── swagger/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── html/
│ │ │ ├── .openapi-generator/
│ │ │ │ └── VERSION
│ │ │ ├── .openapi-generator-ignore
│ │ │ └── index.html
│ │ └── swagger.yml
│ ├── utils/
│ │ ├── callbackqueue.go
│ │ ├── callbackqueue_test.go
│ │ ├── debug.go
│ │ ├── links.go
│ │ ├── testUtils.go
│ │ └── utils.go
│ ├── web/
│ │ ├── webserver.go
│ │ └── webserver_test.go
│ └── ws/
│ ├── adapter.go
│ ├── common.go
│ ├── helpers_test.go
│ ├── mocks/
│ │ ├── mockpluginapi.go
│ │ └── mockstore.go
│ ├── plugin_adapter.go
│ ├── plugin_adapter_client.go
│ ├── plugin_adapter_cluster.go
│ ├── plugin_adapter_test.go
│ ├── server.go
│ └── server_test.go
├── server-config.json
├── webapp/
│ ├── .eslintignore
│ ├── .eslintrc.json
│ ├── .nvmrc
│ ├── .prettierignore
│ ├── .prettierrc.json
│ ├── .stylelintrc.json
│ ├── NOTICE.txt
│ ├── __mocks__/
│ │ ├── fileMock.js
│ │ └── styleMock.js
│ ├── cypress/
│ │ ├── config.json
│ │ ├── global.d.ts
│ │ ├── integration/
│ │ │ ├── cardBadges.ts
│ │ │ ├── cardURLProperty.ts
│ │ │ ├── createBoard.ts
│ │ │ ├── groupByProperty.ts
│ │ │ ├── loginActions.ts
│ │ │ └── manageGroups.ts
│ │ ├── plugins/
│ │ │ └── index.js
│ │ ├── support/
│ │ │ ├── api_commands.ts
│ │ │ ├── index.ts
│ │ │ └── ui_commands.ts
│ │ └── tsconfig.json
│ ├── cypress.json
│ ├── html-templates/
│ │ ├── deveditor.ejs
│ │ └── page.ejs
│ ├── i18n/
│ │ ├── ar.json
│ │ ├── ars.json
│ │ ├── ca.json
│ │ ├── de.json
│ │ ├── el.json
│ │ ├── en.json
│ │ ├── en_AU.json
│ │ ├── es.json
│ │ ├── et.json
│ │ ├── fa.json
│ │ ├── fr.json
│ │ ├── he.json
│ │ ├── hr.json
│ │ ├── hu.json
│ │ ├── id.json
│ │ ├── it.json
│ │ ├── ja.json
│ │ ├── ka.json
│ │ ├── kab.json
│ │ ├── kk.json
│ │ ├── ko.json
│ │ ├── lt.json
│ │ ├── ml.json
│ │ ├── nb_NO.json
│ │ ├── nl.json
│ │ ├── oc.json
│ │ ├── pl.json
│ │ ├── pt.json
│ │ ├── pt_BR.json
│ │ ├── ru.json
│ │ ├── sk.json
│ │ ├── sl.json
│ │ ├── sv.json
│ │ ├── tr.json
│ │ ├── uk.json
│ │ ├── vi.json
│ │ ├── zh_Hans.json
│ │ └── zh_Hant.json
│ ├── package.json
│ ├── src/
│ │ ├── app.tsx
│ │ ├── archiver.ts
│ │ ├── blockIcons.ts
│ │ ├── blocks/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── block.test.ts.snap
│ │ │ │ └── board.test.ts.snap
│ │ │ ├── attachmentBlock.tsx
│ │ │ ├── block.test.ts
│ │ │ ├── block.ts
│ │ │ ├── board.test.ts
│ │ │ ├── board.ts
│ │ │ ├── boardView.test.ts
│ │ │ ├── boardView.ts
│ │ │ ├── card.ts
│ │ │ ├── checkboxBlock.ts
│ │ │ ├── commentBlock.ts
│ │ │ ├── contentBlock.ts
│ │ │ ├── dividerBlock.ts
│ │ │ ├── filterClause.test.ts
│ │ │ ├── filterClause.ts
│ │ │ ├── filterGroup.ts
│ │ │ ├── h1Block.tsx
│ │ │ ├── h2Block.tsx
│ │ │ ├── h3Block.tsx
│ │ │ ├── imageBlock.ts
│ │ │ ├── sharing.ts
│ │ │ ├── team.ts
│ │ │ ├── textBlock.ts
│ │ │ └── workspace.ts
│ │ ├── boardCloudLimits/
│ │ │ └── index.ts
│ │ ├── boardUtils.ts
│ │ ├── boardsCloudLimits/
│ │ │ └── index.ts
│ │ ├── cardFilter.test.ts
│ │ ├── cardFilter.ts
│ │ ├── components/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── addContentMenuItem.test.tsx.snap
│ │ │ │ ├── blockIconSelector.test.tsx.snap
│ │ │ │ ├── cardBadges.test.tsx.snap
│ │ │ │ ├── cardDialog.test.tsx.snap
│ │ │ │ ├── centerPanel.test.tsx.snap
│ │ │ │ ├── confirmAddUserForNotifications.test.tsx.snap
│ │ │ │ ├── confirmationDialogBox.test.tsx.snap
│ │ │ │ ├── contentBlock.test.tsx.snap
│ │ │ │ ├── dialog.test.tsx.snap
│ │ │ │ ├── flashMessages.test.tsx.snap
│ │ │ │ ├── markdownEditor.test.tsx.snap
│ │ │ │ ├── modal.test.tsx.snap
│ │ │ │ ├── personSelector.test.tsx.snap
│ │ │ │ ├── propertyValueElement.test.tsx.snap
│ │ │ │ ├── rootPortal.test.tsx.snap
│ │ │ │ ├── topBar.test.tsx.snap
│ │ │ │ ├── viewMenu.test.tsx.snap
│ │ │ │ ├── viewTitle.test.tsx.snap
│ │ │ │ └── workspace.test.tsx.snap
│ │ │ ├── addContentMenuItem.test.tsx
│ │ │ ├── addContentMenuItem.tsx
│ │ │ ├── blockIconSelector.test.tsx
│ │ │ ├── blockIconSelector.tsx
│ │ │ ├── blocksEditor/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── blockContent.test.tsx.snap
│ │ │ │ │ ├── blocksEditor.test.tsx.snap
│ │ │ │ │ ├── editor.test.tsx.snap
│ │ │ │ │ └── rootInput.test.tsx.snap
│ │ │ │ ├── blockContent.scss
│ │ │ │ ├── blockContent.test.tsx
│ │ │ │ ├── blockContent.tsx
│ │ │ │ ├── blocks/
│ │ │ │ │ ├── attachment/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── attachment.test.tsx.snap
│ │ │ │ │ │ ├── attachment.scss
│ │ │ │ │ │ ├── attachment.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── checkbox/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── checkbox.test.tsx.snap
│ │ │ │ │ │ ├── checkbox.scss
│ │ │ │ │ │ ├── checkbox.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── divider/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── divider.test.tsx.snap
│ │ │ │ │ │ ├── divider.scss
│ │ │ │ │ │ ├── divider.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── h1/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── h1.test.tsx.snap
│ │ │ │ │ │ ├── h1.scss
│ │ │ │ │ │ ├── h1.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── h2/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── h2.test.tsx.snap
│ │ │ │ │ │ ├── h2.scss
│ │ │ │ │ │ ├── h2.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── h3/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── h3.test.tsx.snap
│ │ │ │ │ │ ├── h3.scss
│ │ │ │ │ │ ├── h3.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── image/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── image.test.tsx.snap
│ │ │ │ │ │ ├── image.scss
│ │ │ │ │ │ ├── image.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── list-item/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── list-item.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── list-item.scss
│ │ │ │ │ │ └── list-item.test.tsx
│ │ │ │ │ ├── quote/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── quote.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── quote.scss
│ │ │ │ │ │ └── quote.test.tsx
│ │ │ │ │ ├── text/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── text.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── text.scss
│ │ │ │ │ │ └── text.test.tsx
│ │ │ │ │ ├── text-dev/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── text.scss
│ │ │ │ │ ├── types.tsx
│ │ │ │ │ └── video/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── video.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── video.scss
│ │ │ │ │ └── video.test.tsx
│ │ │ │ ├── blocksEditor.test.tsx
│ │ │ │ ├── blocksEditor.tsx
│ │ │ │ ├── devmain.scss
│ │ │ │ ├── devmain.tsx
│ │ │ │ ├── editor.scss
│ │ │ │ ├── editor.test.tsx
│ │ │ │ ├── editor.tsx
│ │ │ │ ├── rootInput.test.tsx
│ │ │ │ └── rootInput.tsx
│ │ │ ├── boardIconSelector.tsx
│ │ │ ├── boardTemplateSelector/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── boardTemplateSelector.test.tsx.snap
│ │ │ │ │ ├── boardTemplateSelectorItem.test.tsx.snap
│ │ │ │ │ └── boardTemplateSelectorPreview.test.tsx.snap
│ │ │ │ ├── boardTemplateSelector.scss
│ │ │ │ ├── boardTemplateSelector.test.tsx
│ │ │ │ ├── boardTemplateSelector.tsx
│ │ │ │ ├── boardTemplateSelectorItem.scss
│ │ │ │ ├── boardTemplateSelectorItem.test.tsx
│ │ │ │ ├── boardTemplateSelectorItem.tsx
│ │ │ │ ├── boardTemplateSelectorPreview.scss
│ │ │ │ ├── boardTemplateSelectorPreview.test.tsx
│ │ │ │ └── boardTemplateSelectorPreview.tsx
│ │ │ ├── boardsSwitcher/
│ │ │ │ ├── boardsSwitcher.scss
│ │ │ │ └── boardsSwitcher.tsx
│ │ │ ├── boardsSwitcherDialog/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── boardSwitcherDialog.test.tsx.snap
│ │ │ │ ├── boardSwitcherDialog.scss
│ │ │ │ ├── boardSwitcherDialog.test.tsx
│ │ │ │ └── boardSwitcherDialog.tsx
│ │ │ ├── calculations/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── calculation.test.tsx.snap
│ │ │ │ │ └── options.test.tsx.snap
│ │ │ │ ├── calculation.scss
│ │ │ │ ├── calculation.test.tsx
│ │ │ │ ├── calculation.tsx
│ │ │ │ ├── calculations.test.tsx
│ │ │ │ ├── calculations.ts
│ │ │ │ ├── options.test.tsx
│ │ │ │ └── options.tsx
│ │ │ ├── calendar/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── fullCalendar.test.tsx.snap
│ │ │ │ ├── fullCalendar.test.tsx
│ │ │ │ ├── fullCalendar.tsx
│ │ │ │ └── fullcalendar.scss
│ │ │ ├── cardActionsMenu/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── cardActionsMenu.test.tsx.snap
│ │ │ │ ├── cardActionsMenu.test.tsx
│ │ │ │ ├── cardActionsMenu.tsx
│ │ │ │ ├── cardActionsMenuIcon.scss
│ │ │ │ └── cardActionsMenuIcon.tsx
│ │ │ ├── cardBadges.scss
│ │ │ ├── cardBadges.test.tsx
│ │ │ ├── cardBadges.tsx
│ │ │ ├── cardDetail/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── cardDetail.test.tsx.snap
│ │ │ │ │ ├── cardDetailContents.test.tsx.snap
│ │ │ │ │ ├── cardDetailContentsMenu.test.tsx.snap
│ │ │ │ │ ├── cardDetailProperties.test.tsx.snap
│ │ │ │ │ ├── comment.test.tsx.snap
│ │ │ │ │ └── commentsList.test.tsx.snap
│ │ │ │ ├── attachment.scss
│ │ │ │ ├── attachment.tsx
│ │ │ │ ├── cardDetail.scss
│ │ │ │ ├── cardDetail.test.tsx
│ │ │ │ ├── cardDetail.tsx
│ │ │ │ ├── cardDetailContents.test.tsx
│ │ │ │ ├── cardDetailContents.tsx
│ │ │ │ ├── cardDetailContentsMenu.test.tsx
│ │ │ │ ├── cardDetailContentsMenu.tsx
│ │ │ │ ├── cardDetailContentsUtility.test.ts
│ │ │ │ ├── cardDetailContentsUtility.ts
│ │ │ │ ├── cardDetailContext.tsx
│ │ │ │ ├── cardDetailProperties.test.tsx
│ │ │ │ ├── cardDetailProperties.tsx
│ │ │ │ ├── comment.scss
│ │ │ │ ├── comment.test.tsx
│ │ │ │ ├── comment.tsx
│ │ │ │ ├── commentsList.scss
│ │ │ │ ├── commentsList.test.tsx
│ │ │ │ ├── commentsList.tsx
│ │ │ │ └── imagePaste.tsx
│ │ │ ├── cardDialog.scss
│ │ │ ├── cardDialog.test.tsx
│ │ │ ├── cardDialog.tsx
│ │ │ ├── cardLimitNotification.scss
│ │ │ ├── cardLimitNotification.tsx
│ │ │ ├── centerPanel.scss
│ │ │ ├── centerPanel.test.tsx
│ │ │ ├── centerPanel.tsx
│ │ │ ├── confirmAddUserForNotifications.scss
│ │ │ ├── confirmAddUserForNotifications.test.tsx
│ │ │ ├── confirmAddUserForNotifications.tsx
│ │ │ ├── confirmationDialogBox.scss
│ │ │ ├── confirmationDialogBox.test.tsx
│ │ │ ├── confirmationDialogBox.tsx
│ │ │ ├── content/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── attachmentElement.test.tsx.snap
│ │ │ │ │ ├── checkboxElement.test.tsx.snap
│ │ │ │ │ ├── contentElement.test.tsx.snap
│ │ │ │ │ ├── dividerElement.test.tsx.snap
│ │ │ │ │ ├── imageElement.test.tsx.snap
│ │ │ │ │ └── textElement.test.tsx.snap
│ │ │ │ ├── archivedFile/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── archivedFile.test.tsx.snap
│ │ │ │ │ ├── archivedFile.scss
│ │ │ │ │ ├── archivedFile.test.tsx
│ │ │ │ │ └── archivedFile.tsx
│ │ │ │ ├── attachmentElement.scss
│ │ │ │ ├── attachmentElement.test.tsx
│ │ │ │ ├── attachmentElement.tsx
│ │ │ │ ├── checkboxElement.scss
│ │ │ │ ├── checkboxElement.test.tsx
│ │ │ │ ├── checkboxElement.tsx
│ │ │ │ ├── contentElement.test.tsx
│ │ │ │ ├── contentElement.tsx
│ │ │ │ ├── contentRegistry.test.tsx
│ │ │ │ ├── contentRegistry.tsx
│ │ │ │ ├── dividerElement.scss
│ │ │ │ ├── dividerElement.test.tsx
│ │ │ │ ├── dividerElement.tsx
│ │ │ │ ├── imageElement.test.tsx
│ │ │ │ ├── imageElement.tsx
│ │ │ │ ├── textElement.scss
│ │ │ │ ├── textElement.test.tsx
│ │ │ │ └── textElement.tsx
│ │ │ ├── contentBlock.scss
│ │ │ ├── contentBlock.test.tsx
│ │ │ ├── contentBlock.tsx
│ │ │ ├── createCategory/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── createCategory.test.tsx.snap
│ │ │ │ ├── createCategory.scss
│ │ │ │ ├── createCategory.test.tsx
│ │ │ │ └── createCategory.tsx
│ │ │ ├── dialog.scss
│ │ │ ├── dialog.test.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── flashMessages.scss
│ │ │ ├── flashMessages.test.tsx
│ │ │ ├── flashMessages.tsx
│ │ │ ├── gallery/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── gallery.test.tsx.snap
│ │ │ │ │ └── galleryCard.test.tsx.snap
│ │ │ │ ├── gallery.scss
│ │ │ │ ├── gallery.test.tsx
│ │ │ │ ├── gallery.tsx
│ │ │ │ ├── galleryCard.scss
│ │ │ │ ├── galleryCard.test.tsx
│ │ │ │ └── galleryCard.tsx
│ │ │ ├── globalHeader/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── globalHeader.test.tsx.snap
│ │ │ │ │ └── globalHeaderSettingsMenu.test.tsx.snap
│ │ │ │ ├── globalHeader.scss
│ │ │ │ ├── globalHeader.test.tsx
│ │ │ │ ├── globalHeader.tsx
│ │ │ │ ├── globalHeaderSettingsMenu.scss
│ │ │ │ ├── globalHeaderSettingsMenu.test.tsx
│ │ │ │ └── globalHeaderSettingsMenu.tsx
│ │ │ ├── guestNoBoards.scss
│ │ │ ├── guestNoBoards.tsx
│ │ │ ├── hiddenCardCount/
│ │ │ │ ├── hiddenCardCount.scss
│ │ │ │ └── hiddenCardCount.tsx
│ │ │ ├── iconSelector.scss
│ │ │ ├── iconSelector.tsx
│ │ │ ├── kanban/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── kanban.test.tsx.snap
│ │ │ │ │ ├── kanbanCard.test.tsx.snap
│ │ │ │ │ ├── kanbanColumn.test.tsx.snap
│ │ │ │ │ ├── kanbanColumnHeader.test.tsx.snap
│ │ │ │ │ └── kanbanHiddenColumnItem.test.tsx.snap
│ │ │ │ ├── calculation/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── calculation.test.tsx.snap
│ │ │ │ │ │ ├── calculationOptions.test.tsx.snap
│ │ │ │ │ │ └── kanbanOption.test.tsx.snap
│ │ │ │ │ ├── calculation.scss
│ │ │ │ │ ├── calculation.test.tsx
│ │ │ │ │ ├── calculation.tsx
│ │ │ │ │ ├── calculationOption.scss
│ │ │ │ │ ├── calculationOptions.test.tsx
│ │ │ │ │ ├── calculationOptions.tsx
│ │ │ │ │ ├── kanbanOption.test.tsx
│ │ │ │ │ └── kanbanOption.tsx
│ │ │ │ ├── kanban.scss
│ │ │ │ ├── kanban.test.tsx
│ │ │ │ ├── kanban.tsx
│ │ │ │ ├── kanbanCard.scss
│ │ │ │ ├── kanbanCard.test.tsx
│ │ │ │ ├── kanbanCard.tsx
│ │ │ │ ├── kanbanColumn.scss
│ │ │ │ ├── kanbanColumn.test.tsx
│ │ │ │ ├── kanbanColumn.tsx
│ │ │ │ ├── kanbanColumnHeader.test.tsx
│ │ │ │ ├── kanbanColumnHeader.tsx
│ │ │ │ ├── kanbanHiddenColumnItem.test.tsx
│ │ │ │ └── kanbanHiddenColumnItem.tsx
│ │ │ ├── live-markdown-plugin/
│ │ │ │ ├── block-types/
│ │ │ │ │ ├── codeBlockStrategy.ts
│ │ │ │ │ └── headingBlockStrategy.ts
│ │ │ │ ├── inline-styles/
│ │ │ │ │ ├── boldStyleStrategy.ts
│ │ │ │ │ ├── headingDelimiterStyleStrategy.ts
│ │ │ │ │ ├── inlineCodeStyleStrategy.ts
│ │ │ │ │ ├── italicStyleStrategy.ts
│ │ │ │ │ ├── olDelimiterStyleStrategy.ts
│ │ │ │ │ ├── quoteStyleStrategy.ts
│ │ │ │ │ ├── strikethroughStyleStrategy.ts
│ │ │ │ │ └── ulDelimiterStyleStrategy.ts
│ │ │ │ ├── liveMarkdownPlugin.ts
│ │ │ │ ├── pluginStrategy.ts
│ │ │ │ └── utils/
│ │ │ │ └── findRangesWithRegex.ts
│ │ │ ├── markdownEditor.scss
│ │ │ ├── markdownEditor.test.tsx
│ │ │ ├── markdownEditor.tsx
│ │ │ ├── markdownEditorInput/
│ │ │ │ ├── entryComponent/
│ │ │ │ │ ├── entryComponent.scss
│ │ │ │ │ └── entryComponent.tsx
│ │ │ │ ├── markdownEditorInput.scss
│ │ │ │ └── markdownEditorInput.tsx
│ │ │ ├── messages/
│ │ │ │ ├── versionMessage.scss
│ │ │ │ ├── versionMessage.test.tsx
│ │ │ │ └── versionMessage.tsx
│ │ │ ├── modal.scss
│ │ │ ├── modal.test.tsx
│ │ │ ├── modal.tsx
│ │ │ ├── modalWrapper.scss
│ │ │ ├── modalWrapper.tsx
│ │ │ ├── newVersionBanner.scss
│ │ │ ├── newVersionBanner.tsx
│ │ │ ├── onboardingTour/
│ │ │ │ ├── addComments/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addComments.test.tsx.snap
│ │ │ │ │ ├── addComments.test.tsx
│ │ │ │ │ ├── addComments.tsx
│ │ │ │ │ └── add_comments.scss
│ │ │ │ ├── addDescription/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addDescription.test.tsx.snap
│ │ │ │ │ ├── addDescription.test.tsx
│ │ │ │ │ ├── add_description.scss
│ │ │ │ │ └── add_description.tsx
│ │ │ │ ├── addProperties/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addProperties.test.tsx.snap
│ │ │ │ │ ├── addProperties.test.tsx
│ │ │ │ │ ├── add_properties.scss
│ │ │ │ │ └── add_properties.tsx
│ │ │ │ ├── addView/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addView.test.tsx.snap
│ │ │ │ │ ├── addView.test.tsx
│ │ │ │ │ ├── add_view.scss
│ │ │ │ │ └── add_view.tsx
│ │ │ │ ├── copyLink/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── copyLink.test.tsx.snap
│ │ │ │ │ ├── copyLink.test.tsx
│ │ │ │ │ ├── copy_link.scss
│ │ │ │ │ └── copy_link.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── manageCategories/
│ │ │ │ │ ├── manageCategories.scss
│ │ │ │ │ └── manageCategories.tsx
│ │ │ │ ├── openCard/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── openCard.test.tsx.snap
│ │ │ │ │ ├── openCard.test.tsx
│ │ │ │ │ ├── open_card.scss
│ │ │ │ │ └── open_card.tsx
│ │ │ │ ├── searchForBoards/
│ │ │ │ │ ├── searchForBoards.scss
│ │ │ │ │ └── searchForBoards.tsx
│ │ │ │ ├── shareBoard/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── shareBoard.test.tsx.snap
│ │ │ │ │ ├── shareBoard.scss
│ │ │ │ │ ├── shareBoard.test.tsx
│ │ │ │ │ └── shareBoard.tsx
│ │ │ │ ├── sidebarCategories/
│ │ │ │ │ ├── sidebarCategories.scss
│ │ │ │ │ └── sidebarCategories.tsx
│ │ │ │ └── tourTipRenderer/
│ │ │ │ └── tourTipRenderer.tsx
│ │ │ ├── permissions/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── boardPermissionGate.test.tsx.snap
│ │ │ │ ├── boardPermissionGate.test.tsx
│ │ │ │ └── boardPermissionGate.tsx
│ │ │ ├── personSelector.scss
│ │ │ ├── personSelector.test.tsx
│ │ │ ├── personSelector.tsx
│ │ │ ├── propertyValueElement.test.tsx
│ │ │ ├── propertyValueElement.tsx
│ │ │ ├── pulsating_dot/
│ │ │ │ ├── index.tsx
│ │ │ │ └── pulsating_dot.scss
│ │ │ ├── rootPortal.test.tsx
│ │ │ ├── rootPortal.tsx
│ │ │ ├── searchDialog/
│ │ │ │ ├── searchDialog.scss
│ │ │ │ └── searchDialog.tsx
│ │ │ ├── shareBoard/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── shareBoard.test.tsx.snap
│ │ │ │ │ ├── shareBoardButton.test.tsx.snap
│ │ │ │ │ ├── shareBoardLoginButton.test.tsx.snap
│ │ │ │ │ ├── teamPermissionsRow.test.tsx.snap
│ │ │ │ │ └── userPermissionsRow.test.tsx.snap
│ │ │ │ ├── shareBoard.scss
│ │ │ │ ├── shareBoard.test.tsx
│ │ │ │ ├── shareBoard.tsx
│ │ │ │ ├── shareBoardButton.scss
│ │ │ │ ├── shareBoardButton.test.tsx
│ │ │ │ ├── shareBoardButton.tsx
│ │ │ │ ├── shareBoardLoginButton.scss
│ │ │ │ ├── shareBoardLoginButton.test.tsx
│ │ │ │ ├── shareBoardLoginButton.tsx
│ │ │ │ ├── teamPermissionsRow.test.tsx
│ │ │ │ ├── teamPermissionsRow.tsx
│ │ │ │ ├── userPermissionsRow.test.tsx
│ │ │ │ └── userPermissionsRow.tsx
│ │ │ ├── sidebar/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── deleteBoardDialog.test.tsx.snap
│ │ │ │ │ ├── registrationLink.test.tsx.snap
│ │ │ │ │ ├── sidebar.test.tsx.snap
│ │ │ │ │ ├── sidebarBoardItem.test.tsx.snap
│ │ │ │ │ ├── sidebarCategory.test.tsx.snap
│ │ │ │ │ └── sidebarSettingsMenu.test.tsx.snap
│ │ │ │ ├── deleteBoardDialog.scss
│ │ │ │ ├── deleteBoardDialog.test.tsx
│ │ │ │ ├── deleteBoardDialog.tsx
│ │ │ │ ├── registrationLink.scss
│ │ │ │ ├── registrationLink.test.tsx
│ │ │ │ ├── registrationLink.tsx
│ │ │ │ ├── sidebar.scss
│ │ │ │ ├── sidebar.test.tsx
│ │ │ │ ├── sidebar.tsx
│ │ │ │ ├── sidebarBoardItem.scss
│ │ │ │ ├── sidebarBoardItem.test.tsx
│ │ │ │ ├── sidebarBoardItem.tsx
│ │ │ │ ├── sidebarCategory.scss
│ │ │ │ ├── sidebarCategory.test.tsx
│ │ │ │ ├── sidebarCategory.tsx
│ │ │ │ ├── sidebarSettingsMenu.scss
│ │ │ │ ├── sidebarSettingsMenu.test.tsx
│ │ │ │ ├── sidebarSettingsMenu.tsx
│ │ │ │ ├── sidebarUserMenu.scss
│ │ │ │ └── sidebarUserMenu.tsx
│ │ │ ├── table/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── table.test.tsx.snap
│ │ │ │ │ ├── tableGroupHeaderRow.test.tsx.snap
│ │ │ │ │ ├── tableHeader.test.tsx.snap
│ │ │ │ │ ├── tableHeaderMenu.test.tsx.snap
│ │ │ │ │ ├── tableHeaders.test.tsx.snap
│ │ │ │ │ ├── tableRow.test.tsx.snap
│ │ │ │ │ └── tableRows.test.tsx.snap
│ │ │ │ ├── calculation/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── calculationRow.test.tsx.snap
│ │ │ │ │ ├── calculationRow.scss
│ │ │ │ │ ├── calculationRow.test.tsx
│ │ │ │ │ ├── calculationRow.tsx
│ │ │ │ │ └── tableCalculationOptions.tsx
│ │ │ │ ├── horizontalGrip.scss
│ │ │ │ ├── horizontalGrip.tsx
│ │ │ │ ├── table.scss
│ │ │ │ ├── table.test.tsx
│ │ │ │ ├── table.tsx
│ │ │ │ ├── tableColumnResizeContext.tsx
│ │ │ │ ├── tableGroup.tsx
│ │ │ │ ├── tableGroupHeaderRow.test.tsx
│ │ │ │ ├── tableGroupHeaderRow.tsx
│ │ │ │ ├── tableHeader.test.tsx
│ │ │ │ ├── tableHeader.tsx
│ │ │ │ ├── tableHeaderMenu.test.tsx
│ │ │ │ ├── tableHeaderMenu.tsx
│ │ │ │ ├── tableHeaders.test.tsx
│ │ │ │ ├── tableHeaders.tsx
│ │ │ │ ├── tableRow.scss
│ │ │ │ ├── tableRow.test.tsx
│ │ │ │ ├── tableRow.tsx
│ │ │ │ ├── tableRows.test.tsx
│ │ │ │ └── tableRows.tsx
│ │ │ ├── topBar.scss
│ │ │ ├── topBar.test.tsx
│ │ │ ├── topBar.tsx
│ │ │ ├── tutorial_tour_tip/
│ │ │ │ ├── hooks.ts
│ │ │ │ ├── tutorial_tour_tip.scss
│ │ │ │ ├── tutorial_tour_tip.tsx
│ │ │ │ ├── tutorial_tour_tip_backdrop.tsx
│ │ │ │ ├── tutorial_tour_tip_manager.tsx
│ │ │ │ └── useElementAvailable.ts
│ │ │ ├── viewHeader/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── dateFilter.test.tsx.snap
│ │ │ │ │ ├── emptyCardButton.test.tsx.snap
│ │ │ │ │ ├── filterComponent.test.tsx.snap
│ │ │ │ │ ├── filterEntry.test.tsx.snap
│ │ │ │ │ ├── filterValue.test.tsx.snap
│ │ │ │ │ ├── newCardButton.test.tsx.snap
│ │ │ │ │ ├── newCardButtonTemplateItem.test.tsx.snap
│ │ │ │ │ ├── viewHeader.test.tsx.snap
│ │ │ │ │ ├── viewHeaderActionsMenu.test.tsx.snap
│ │ │ │ │ ├── viewHeaderGroupByMenu.test.tsx.snap
│ │ │ │ │ ├── viewHeaderPropertiesMenu.test.tsx.snap
│ │ │ │ │ ├── viewHeaderSearch.test.tsx.snap
│ │ │ │ │ └── viewHeaderSortMenu.test.tsx.snap
│ │ │ │ ├── dateFilter.scss
│ │ │ │ ├── dateFilter.test.tsx
│ │ │ │ ├── dateFilter.tsx
│ │ │ │ ├── emptyCardButton.test.tsx
│ │ │ │ ├── emptyCardButton.tsx
│ │ │ │ ├── filterComponent.scss
│ │ │ │ ├── filterComponent.test.tsx
│ │ │ │ ├── filterComponent.tsx
│ │ │ │ ├── filterEntry.scss
│ │ │ │ ├── filterEntry.test.tsx
│ │ │ │ ├── filterEntry.tsx
│ │ │ │ ├── filterValue.scss
│ │ │ │ ├── filterValue.test.tsx
│ │ │ │ ├── filterValue.tsx
│ │ │ │ ├── multiperson.scss
│ │ │ │ ├── multipersonFilterValue.tsx
│ │ │ │ ├── newCardButton.test.tsx
│ │ │ │ ├── newCardButton.tsx
│ │ │ │ ├── newCardButtonTemplateItem.test.tsx
│ │ │ │ ├── newCardButtonTemplateItem.tsx
│ │ │ │ ├── viewHeader.scss
│ │ │ │ ├── viewHeader.test.tsx
│ │ │ │ ├── viewHeader.tsx
│ │ │ │ ├── viewHeaderActionsMenu.test.tsx
│ │ │ │ ├── viewHeaderActionsMenu.tsx
│ │ │ │ ├── viewHeaderDisplayByMenu.tsx
│ │ │ │ ├── viewHeaderGroupByMenu.test.tsx
│ │ │ │ ├── viewHeaderGroupByMenu.tsx
│ │ │ │ ├── viewHeaderPropertiesMenu.test.tsx
│ │ │ │ ├── viewHeaderPropertiesMenu.tsx
│ │ │ │ ├── viewHeaderSearch.test.tsx
│ │ │ │ ├── viewHeaderSearch.tsx
│ │ │ │ ├── viewHeaderSortMenu.test.tsx
│ │ │ │ └── viewHeaderSortMenu.tsx
│ │ │ ├── viewMenu.scss
│ │ │ ├── viewMenu.test.tsx
│ │ │ ├── viewMenu.tsx
│ │ │ ├── viewTitle.scss
│ │ │ ├── viewTitle.test.tsx
│ │ │ ├── viewTitle.tsx
│ │ │ ├── withWebSockets.tsx
│ │ │ ├── workspace.scss
│ │ │ ├── workspace.test.tsx
│ │ │ └── workspace.tsx
│ │ ├── config/
│ │ │ └── clientConfig.ts
│ │ ├── constants.ts
│ │ ├── csvExporter.ts
│ │ ├── emojiList.ts
│ │ ├── errors.ts
│ │ ├── file.ts
│ │ ├── fileIcons.ts
│ │ ├── hooks/
│ │ │ ├── permissions.tsx
│ │ │ ├── sortable.tsx
│ │ │ ├── useGetAllTemplates.ts
│ │ │ └── websockets.tsx
│ │ ├── i18n.tsx
│ │ ├── insights/
│ │ │ └── index.ts
│ │ ├── main.tsx
│ │ ├── mutator.test.ts
│ │ ├── mutator.ts
│ │ ├── nativeApp.ts
│ │ ├── octoClient.test.ts
│ │ ├── octoClient.ts
│ │ ├── octoUtils.test.ts
│ │ ├── octoUtils.tsx
│ │ ├── onboardingTour/
│ │ │ └── index.ts
│ │ ├── pages/
│ │ │ ├── boardPage/
│ │ │ │ ├── backwardCompatibilityQueryParamsRedirect.tsx
│ │ │ │ ├── boardPage.scss
│ │ │ │ ├── boardPage.tsx
│ │ │ │ ├── setWindowTitleAndIcon.tsx
│ │ │ │ ├── teamToBoardAndViewRedirect.tsx
│ │ │ │ ├── undoRedoHotKeys.tsx
│ │ │ │ └── websocketConnection.tsx
│ │ │ ├── changePasswordPage.scss
│ │ │ ├── changePasswordPage.tsx
│ │ │ ├── errorPage.scss
│ │ │ ├── errorPage.tsx
│ │ │ ├── loginPage.scss
│ │ │ ├── loginPage.tsx
│ │ │ ├── registerPage.scss
│ │ │ ├── registerPage.tsx
│ │ │ └── welcome/
│ │ │ ├── __snapshots__/
│ │ │ │ └── welcomePage.test.tsx.snap
│ │ │ ├── welcomePage.scss
│ │ │ ├── welcomePage.test.tsx
│ │ │ └── welcomePage.tsx
│ │ ├── properties/
│ │ │ ├── baseTextEditor.tsx
│ │ │ ├── checkbox/
│ │ │ │ ├── checkbox.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── createdBy/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── createdBy.test.tsx.snap
│ │ │ │ ├── createdBy.test.tsx
│ │ │ │ ├── createdBy.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── createdTime/
│ │ │ │ ├── createdTime.scss
│ │ │ │ ├── createdTime.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── date/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── date.test.tsx.snap
│ │ │ │ ├── date.scss
│ │ │ │ ├── date.test.tsx
│ │ │ │ ├── date.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── email/
│ │ │ │ ├── email.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── index.tsx
│ │ │ ├── multiperson/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── multiperson.test.tsx.snap
│ │ │ │ ├── multiperson.test.tsx
│ │ │ │ ├── multiperson.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── multiselect/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── multiselect.test.tsx.snap
│ │ │ │ ├── multiselect.test.tsx
│ │ │ │ ├── multiselect.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── number/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── number.test.tsx.snap
│ │ │ │ ├── number.test.tsx
│ │ │ │ ├── number.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── person/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── confirmPerson.test.tsx.snap
│ │ │ │ │ └── person.test.tsx.snap
│ │ │ │ ├── confirmPerson.test.tsx
│ │ │ │ ├── confirmPerson.tsx
│ │ │ │ ├── person.test.tsx
│ │ │ │ ├── person.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── phone/
│ │ │ │ ├── phone.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── select/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── select.test.tsx.snap
│ │ │ │ ├── property.tsx
│ │ │ │ ├── select.test.tsx
│ │ │ │ └── select.tsx
│ │ │ ├── text/
│ │ │ │ ├── property.tsx
│ │ │ │ └── text.tsx
│ │ │ ├── types.tsx
│ │ │ ├── unknown/
│ │ │ │ └── property.tsx
│ │ │ ├── updatedBy/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── updatedBy.test.tsx.snap
│ │ │ │ ├── property.tsx
│ │ │ │ ├── updatedBy.scss
│ │ │ │ ├── updatedBy.test.tsx
│ │ │ │ └── updatedBy.tsx
│ │ │ ├── updatedTime/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── updatedTime.test.tsx.snap
│ │ │ │ ├── property.tsx
│ │ │ │ ├── updatedTime.scss
│ │ │ │ ├── updatedTime.test.tsx
│ │ │ │ └── updatedTime.tsx
│ │ │ └── url/
│ │ │ ├── __snapshots__/
│ │ │ │ └── url.test.tsx.snap
│ │ │ ├── property.tsx
│ │ │ ├── url.scss
│ │ │ ├── url.test.tsx
│ │ │ └── url.tsx
│ │ ├── route.tsx
│ │ ├── router.tsx
│ │ ├── statistics/
│ │ │ └── index.ts
│ │ ├── store/
│ │ │ ├── attachments.ts
│ │ │ ├── boards.ts
│ │ │ ├── cards.ts
│ │ │ ├── channels.ts
│ │ │ ├── clientConfig.ts
│ │ │ ├── comments.ts
│ │ │ ├── contents.ts
│ │ │ ├── globalError.ts
│ │ │ ├── globalTemplates.ts
│ │ │ ├── hooks.ts
│ │ │ ├── index.ts
│ │ │ ├── initialLoad.ts
│ │ │ ├── language.ts
│ │ │ ├── limits.ts
│ │ │ ├── searchText.ts
│ │ │ ├── sidebar.ts
│ │ │ ├── teams.ts
│ │ │ ├── users.ts
│ │ │ └── views.ts
│ │ ├── styles/
│ │ │ ├── _markdown.scss
│ │ │ ├── _modifiers.scss
│ │ │ ├── _typography.scss
│ │ │ ├── _z-index.scss
│ │ │ ├── focalboard-variables.scss
│ │ │ ├── labels.scss
│ │ │ ├── main.scss
│ │ │ ├── shared-variables.scss
│ │ │ └── variables.scss
│ │ ├── svg/
│ │ │ ├── card-skeleton.tsx
│ │ │ ├── error-illustration.tsx
│ │ │ └── search-illustration.tsx
│ │ ├── telemetry/
│ │ │ ├── telemetry.ts
│ │ │ ├── telemetryClient.test.ts
│ │ │ └── telemetryClient.ts
│ │ ├── test/
│ │ │ ├── fetchMock.ts
│ │ │ └── testBlockFactory.ts
│ │ ├── testUtils.tsx
│ │ ├── theme.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── images.d.ts
│ │ │ └── index.d.ts
│ │ ├── undoManager.test.ts
│ │ ├── undomanager.ts
│ │ ├── user.tsx
│ │ ├── userSettings.ts
│ │ ├── utils.test.ts
│ │ ├── utils.ts
│ │ ├── widgets/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── guestBadge.test.tsx.snap
│ │ │ │ └── propertyMenu.test.tsx.snap
│ │ │ ├── adminBadge/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── adminBadge.test.tsx.snap
│ │ │ │ ├── adminBadge.scss
│ │ │ │ ├── adminBadge.test.tsx
│ │ │ │ └── adminBadge.tsx
│ │ │ ├── buttons/
│ │ │ │ ├── button.scss
│ │ │ │ ├── button.tsx
│ │ │ │ ├── buttonWithMenu.scss
│ │ │ │ ├── buttonWithMenu.tsx
│ │ │ │ ├── iconButton.scss
│ │ │ │ └── iconButton.tsx
│ │ │ ├── editable.scss
│ │ │ ├── editable.tsx
│ │ │ ├── editableArea.scss
│ │ │ ├── editableArea.tsx
│ │ │ ├── editableDayPicker.scss
│ │ │ ├── editableDayPicker.tsx
│ │ │ ├── emojiPicker.scss
│ │ │ ├── emojiPicker.tsx
│ │ │ ├── guestBadge.scss
│ │ │ ├── guestBadge.test.tsx
│ │ │ ├── guestBadge.tsx
│ │ │ ├── icons/
│ │ │ │ ├── HandRight.tsx
│ │ │ │ ├── Link.tsx
│ │ │ │ ├── add.scss
│ │ │ │ ├── add.tsx
│ │ │ │ ├── alert.tsx
│ │ │ │ ├── apps.tsx
│ │ │ │ ├── board.scss
│ │ │ │ ├── board.tsx
│ │ │ │ ├── brokenFile.tsx
│ │ │ │ ├── calendar.scss
│ │ │ │ ├── calendar.tsx
│ │ │ │ ├── card.scss
│ │ │ │ ├── card.tsx
│ │ │ │ ├── check.scss
│ │ │ │ ├── check.tsx
│ │ │ │ ├── checkIcon.tsx
│ │ │ │ ├── chevronDown.tsx
│ │ │ │ ├── chevronRight.tsx
│ │ │ │ ├── chevronUp.tsx
│ │ │ │ ├── close.tsx
│ │ │ │ ├── closeCircle.tsx
│ │ │ │ ├── compassIcon.tsx
│ │ │ │ ├── delete.scss
│ │ │ │ ├── delete.tsx
│ │ │ │ ├── disclosureTriangle.scss
│ │ │ │ ├── disclosureTriangle.tsx
│ │ │ │ ├── divider.scss
│ │ │ │ ├── divider.tsx
│ │ │ │ ├── dot.scss
│ │ │ │ ├── dot.tsx
│ │ │ │ ├── dropdown.scss
│ │ │ │ ├── dropdown.tsx
│ │ │ │ ├── duplicate.scss
│ │ │ │ ├── duplicate.tsx
│ │ │ │ ├── edit.tsx
│ │ │ │ ├── emoji.scss
│ │ │ │ ├── emoji.tsx
│ │ │ │ ├── focalboard_logo.scss
│ │ │ │ ├── focalboard_logo.tsx
│ │ │ │ ├── folder.tsx
│ │ │ │ ├── gallery.scss
│ │ │ │ ├── gallery.tsx
│ │ │ │ ├── globe.tsx
│ │ │ │ ├── grip.scss
│ │ │ │ ├── grip.tsx
│ │ │ │ ├── hamburger.scss
│ │ │ │ ├── hamburger.tsx
│ │ │ │ ├── help.scss
│ │ │ │ ├── help.tsx
│ │ │ │ ├── hide.scss
│ │ │ │ ├── hide.tsx
│ │ │ │ ├── hideSidebar.scss
│ │ │ │ ├── hideSidebar.tsx
│ │ │ │ ├── image.scss
│ │ │ │ ├── image.tsx
│ │ │ │ ├── link.scss
│ │ │ │ ├── lockOutline.tsx
│ │ │ │ ├── logo.scss
│ │ │ │ ├── logo.tsx
│ │ │ │ ├── logoWithName.scss
│ │ │ │ ├── logoWithName.tsx
│ │ │ │ ├── logoWithNameWhite.scss
│ │ │ │ ├── logoWithNameWhite.tsx
│ │ │ │ ├── message.tsx
│ │ │ │ ├── newFolder.tsx
│ │ │ │ ├── options.scss
│ │ │ │ ├── options.tsx
│ │ │ │ ├── random.tsx
│ │ │ │ ├── search.tsx
│ │ │ │ ├── settings.scss
│ │ │ │ ├── settings.tsx
│ │ │ │ ├── show.scss
│ │ │ │ ├── show.tsx
│ │ │ │ ├── showSidebar.scss
│ │ │ │ ├── showSidebar.tsx
│ │ │ │ ├── sortDown.scss
│ │ │ │ ├── sortDown.tsx
│ │ │ │ ├── sortUp.scss
│ │ │ │ ├── sortUp.tsx
│ │ │ │ ├── submenuTriangle.scss
│ │ │ │ ├── submenuTriangle.tsx
│ │ │ │ ├── table.scss
│ │ │ │ ├── table.tsx
│ │ │ │ ├── text.scss
│ │ │ │ ├── text.tsx
│ │ │ │ └── update.tsx
│ │ │ ├── label.scss
│ │ │ ├── label.tsx
│ │ │ ├── menu/
│ │ │ │ ├── colorOption.scss
│ │ │ │ ├── colorOption.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── labelOption.scss
│ │ │ │ ├── labelOption.tsx
│ │ │ │ ├── menu.scss
│ │ │ │ ├── menu.tsx
│ │ │ │ ├── menuItem.tsx
│ │ │ │ ├── menuUtil.ts
│ │ │ │ ├── separatorOption.scss
│ │ │ │ ├── separatorOption.tsx
│ │ │ │ ├── subMenuOption.scss
│ │ │ │ ├── subMenuOption.tsx
│ │ │ │ ├── switchOption.tsx
│ │ │ │ ├── textInputOption.tsx
│ │ │ │ └── textOption.tsx
│ │ │ ├── menuWrapper.scss
│ │ │ ├── menuWrapper.tsx
│ │ │ ├── notificationBox/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── notificationBox.test.tsx.snap
│ │ │ │ ├── notificationBox.scss
│ │ │ │ ├── notificationBox.test.tsx
│ │ │ │ └── notificationBox.tsx
│ │ │ ├── propertyMenu.scss
│ │ │ ├── propertyMenu.test.tsx
│ │ │ ├── propertyMenu.tsx
│ │ │ ├── switch.scss
│ │ │ ├── switch.tsx
│ │ │ ├── tooltip.scss
│ │ │ ├── tooltip.tsx
│ │ │ ├── valueSelector.scss
│ │ │ └── valueSelector.tsx
│ │ └── wsclient.ts
│ ├── tsconfig.json
│ ├── tslint.json
│ ├── webpack.common.js
│ ├── webpack.dev.js
│ ├── webpack.editor.js
│ └── webpack.prod.js
├── website/
│ ├── .editorconfig
│ ├── .gitignore
│ ├── Makefile
│ ├── README.md
│ └── site/
│ ├── archetypes/
│ │ └── default.md
│ ├── config.toml
│ ├── content/
│ │ ├── blog/
│ │ │ ├── 2021-1-7-hello.md
│ │ │ ├── 2021-4-21-Focalboard v0.6.5 release.md
│ │ │ ├── 2021-4-27-Mattermost-Focalboard-early-preview.md
│ │ │ ├── 2021-5-07-meeting-agenda-template.md
│ │ │ ├── 2021-5-13-Focalboard-the-road-to-v1.md
│ │ │ └── 2021-6-18-Mattermost-Focalboard-release.md
│ │ ├── docs/
│ │ │ └── personal-edition/
│ │ │ ├── _index.md
│ │ │ ├── desktop.md
│ │ │ ├── docker.md
│ │ │ ├── ubuntu-upgrade.md
│ │ │ └── ubuntu.md
│ │ ├── download/
│ │ │ └── index.html
│ │ ├── feedback/
│ │ │ └── _index.md
│ │ ├── fwlink/
│ │ │ ├── doc-boards.html
│ │ │ ├── feedback-boards.html
│ │ │ ├── feedback-focalboard.html
│ │ │ ├── plugin-setup.html
│ │ │ ├── setup-536.html
│ │ │ ├── v1-focalboard.html
│ │ │ └── websocket-connect-error.html
│ │ └── guide/
│ │ ├── admin/
│ │ │ └── _index.md
│ │ ├── server-setup/
│ │ │ └── _index.md
│ │ ├── user/
│ │ │ └── _index.md
│ │ └── websocket-errors/
│ │ └── _index.md
│ ├── layouts/
│ │ ├── 404.html
│ │ ├── _default/
│ │ │ ├── _markup/
│ │ │ │ └── render-link.html
│ │ │ ├── list.html
│ │ │ ├── page.html
│ │ │ ├── single.html
│ │ │ └── taxonomy.html
│ │ ├── blog/
│ │ │ ├── li.html
│ │ │ ├── list.html
│ │ │ ├── single.html
│ │ │ └── summary.html
│ │ ├── index.html
│ │ ├── indexes/
│ │ │ └── tag.html
│ │ ├── partials/
│ │ │ ├── blogauthor.html
│ │ │ ├── footer.html
│ │ │ ├── hanchor.html
│ │ │ ├── head.html
│ │ │ ├── hero.html
│ │ │ ├── intro.html
│ │ │ ├── mailinglist.html
│ │ │ ├── nav.html
│ │ │ ├── notification.html
│ │ │ ├── page-edit.html
│ │ │ ├── series_link.html
│ │ │ └── sidebar.html
│ │ └── shortcodes/
│ │ ├── baseurl.html
│ │ ├── bignumber.html
│ │ ├── blogurl.html
│ │ ├── content.html
│ │ ├── md.html
│ │ └── note.html
│ ├── static/
│ │ ├── css/
│ │ │ ├── bar.css
│ │ │ ├── code.css
│ │ │ ├── markdown.css
│ │ │ ├── note.css
│ │ │ ├── partials/
│ │ │ │ ├── banners.css
│ │ │ │ ├── base.css
│ │ │ │ ├── blog.css
│ │ │ │ ├── buttons.css
│ │ │ │ ├── fontawesome.css
│ │ │ │ ├── footer.css
│ │ │ │ ├── header.css
│ │ │ │ ├── homepage.css
│ │ │ │ ├── root.css
│ │ │ │ ├── sidebar.css
│ │ │ │ └── template-picker.css
│ │ │ ├── styles.css
│ │ │ └── tabs.css
│ │ ├── fonts/
│ │ │ └── FontAwesome.otf
│ │ ├── js/
│ │ │ ├── main.js
│ │ │ └── tabs.js
│ │ ├── lottie/
│ │ │ └── intro-section.json
│ │ └── robots.txt
│ └── themes/
│ ├── archetypes/
│ │ └── default.md
│ ├── config.toml
│ ├── content/
│ │ └── contribute/
│ │ └── _index.md
│ └── layouts/
│ ├── 404.html
│ ├── _default/
│ │ ├── list.html
│ │ └── single.html
│ ├── index.html
│ └── partials/
│ ├── about.html
│ ├── contact.html
│ ├── counters.html
│ ├── footer.html
│ ├── head.html
│ ├── hero.html
│ ├── intro.html
│ ├── js.html
│ ├── nav.html
│ ├── nav2.html
│ ├── services.html
│ ├── testimonials.html
│ └── work.html
└── win-wpf/
├── .gitignore
├── AppxManifest.xml
├── Focalboard/
│ ├── App.config
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Focalboard.csproj
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── Properties/
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── Utils.cs
│ ├── Webview2Installer.cs
│ └── packages.config
├── Focalboard.sln
├── README.md
├── build.bat
├── package-zip.bat
└── package.bat
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
CHANGELOG.md
README.md
node_modules
.github/
mac/
win-wpf/
website/
linux/
go.work
go.work.sum
================================================
FILE: .editorconfig
================================================
# http://editorconfig.org/
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
[*.go]
indent_style = tab
[*.{js,jsx,json,html}]
indent_style = space
indent_size = 4
[{package.json,.eslintrc.json}]
indent_size = 2
[i18n/**.json]
indent_size = 2
[Makefile]
indent_style = tab
[*.scss]
indent_style = space
indent_size = 4
================================================
FILE: .gitattributes
================================================
website/** linguist-documentation
server/swagger/** linguist-generated
================================================
FILE: .github/CODEOWNERS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: 'Bug: '
labels: Bug, Triage
assignees: ''
---
## Steps to reproduce the behavior
1. Go to ...
2. Select ...
3. Scroll down to ...
4. See error
## Expected behavior
A clear and concise description of what you expected to happen.
## Screenshots (optional)
If applicable, add screenshots or a screen recording to elaborate on the problem.
## Edition and Platform
- Edition: Personal Desktop / Personal Server / Mattermost Boards (plugin)
- Version: [e.g. v0.15.0]
- Browser and OS: [e.g. Chrome on Mac, Edge on Windows]
## Additional context (optional)
Add any other context about the problem here, and any notes about the severity:
* Sev 1: Affects critical functionality without a workaround
* Sev 2: Affects major functionality with a difficult or non-obvious workaround
* Sev 3: Affects minor, non-critical functionality
================================================
FILE: .github/ISSUE_TEMPLATE/doc_improvement.md
================================================
---
name: Documentation Request
about: Request improvement to our documentation
title: 'Doc: '
labels: Documentation, Triage
assignees: ''
---
## Summary
Concisely summarize improvement to documentation requested.
## Link to documentation page
If applicable, link to the documentation page and/or section where you feel the improvement could be added. E.g. `https://docs.mattermost.com/boards/accessing-boards.html`
## (Optional) Additional context and/or screenshot
Add additional context and/or a screenshot of the product feature you'd like explained in documentation.
================================================
FILE: .github/ISSUE_TEMPLATE/enhancement.md
================================================
---
name: Enhancement/Feature Idea
about: Suggest a new capability
title: 'Feature Idea: '
labels: Enhancement, Triage
assignees: ''
---
## Summary
What the new capability is.
## How important this is to me and why
Importance: High/Medium/Low
Use cases:
1.
2.
3.
## Additional context/similar features
Any examples of good implementations of this capability.
================================================
FILE: .github/codeql/codeql-config.yml
================================================
name: "CodeQL config"
query-filters:
- exclude:
problem.severity:
- warning
- recommendation
- exclude:
id: go/log-injection
paths-ignore:
- 'server/swagger/**/*.html'
- 'website/**/*.html'
- '**/*_test.go'
- 'webapp/cypress/**'
- '**/*.test.*'
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directories:
- "**/*"
reviewers:
- "mattermost/cloud-sre"
open-pull-requests-limit: 5
groups:
Github Actions updates:
applies-to: version-updates
dependency-type: production
schedule:
# Check for updates to GitHub Actions every week
day: "monday"
time: "09:00"
interval: "weekly"
================================================
FILE: .github/workflows/ci.yml
================================================
name: Check-in tests
on:
push:
branches:
- 'main'
- 'releases-**'
pull_request:
workflow_dispatch:
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
EXCLUDE_ENTERPRISE: true
jobs:
ci-ubuntu-server:
runs-on: ubuntu-22.04
strategy:
matrix:
db:
- sqlite
- mysql
- mariadb
- postgres
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: server/go.mod
- name: "Test server: ${{matrix['db']}}"
run: make server-test-${{matrix['db']}}
ci-ubuntu-webapp:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: npm ci
run: cd focalboard/webapp && npm ci && cd -
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: focalboard/server/go.mod
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version-file: focalboard/webapp/.nvmrc
- name: Build Linux server
run: cd focalboard; make server-linux-package
- name: Copy server binary for Cypress
run: cp focalboard/bin/linux/focalboard-server focalboard/bin/
- name: Upload server package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-server-linux-amd64.tar.gz
path: ${{ github.workspace }}/focalboard/dist/focalboard-server-linux-amd64.tar.gz
- name: Lint & test webapp
run: cd focalboard; make webapp-ci
ci-windows-server:
runs-on: windows-2022
strategy:
matrix:
db:
- sqlite
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: focalboard/server/go.mod
- name: "Test server (minimum): ${{matrix['db']}}"
run: cd focalboard; make server-test-mini-${{matrix['db']}}
ci-mac-server:
runs-on: macos-15
strategy:
matrix:
db:
- sqlite
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: focalboard/server/go.mod
- name: "Test server (minimum): ${{matrix['db']}}"
run: cd focalboard; make server-test-mini-${{matrix['db']}}
================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
name: "CodeQL"
on:
push:
branches: [ main, release-** ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main, release-** ]
schedule:
- cron: '30 4 * * 0'
permissions:
contents: read
jobs:
analyze:
permissions:
security-events: write # for github/codeql-action/autobuild to send a status report
name: Analyze
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
language: [ 'go', 'javascript' ]
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@fca7ace96b7d713c7035871441bd52efbe39e27e
with:
languages: ${{ matrix.language }}
debug: false
config-file: ./.github/codeql/codeql-config.yml
# Autobuild attempts to build any compiled languages
- name: Autobuild
uses: github/codeql-action/autobuild@fca7ace96b7d713c7035871441bd52efbe39e27e
# Perform Analysis
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@fca7ace96b7d713c7035871441bd52efbe39e27e
================================================
FILE: .github/workflows/dev-release.yml
================================================
name: Dev-Release
on:
push:
branches: [ main, release-** ]
pull_request:
branches: [ main, release-** ]
workflow_dispatch:
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
EXCLUDE_ENTERPRISE: true
jobs:
ubuntu:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Replace token 1 server
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: Replace token 2 server
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: npm ci
run: cd focalboard/webapp; npm ci --no-optional
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version: 1.21
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 20.11.0
- name: apt-get update
run: sudo apt-get update
- name: apt-get install -y libgtk-3-dev
run: sudo apt-get install -y libgtk-3-dev
- name: apt-get install -y libwebkit2gtk-4.0-dev
run: sudo apt-get install -y libwebkit2gtk-4.0-dev
- name: Build Linux server and app
run: cd focalboard/; make server-linux-package linux-app
env:
BUILD_NUMBER: ${{ github.run_id }}
- name: Upload server package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-server-linux-amd64.tar.gz
path: ${{ github.workspace }}/focalboard/dist/focalboard-server-linux-amd64.tar.gz
- name: Upload app package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-linux.tar.gz
path: ${{ github.workspace }}/focalboard/linux/dist/focalboard-linux.tar.gz
macos:
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Replace token 1 server
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: Replace token 2 server
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_DEV_KEY }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: npm ci
run: cd focalboard/webapp; npm ci --no-optional
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version: 1.21
- name: List Xcode versions
run: ls -n /Applications/ | grep Xcode*
- name: Build macOS
run: cd focalboard; make mac-app
env:
DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer
BUILD_NUMBER: ${{ github.run_id }}
- name: Upload macOS package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-mac.zip
path: ${{ github.workspace }}/focalboard/mac/dist/focalboard-mac.zip
windows:
runs-on: windows-2022
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Replace token 1 server
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.3
- name: npm ci
run: cd focalboard/webapp; npm ci --no-optional
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version: 1.21
- name: Setup NuGet
uses: nuget/setup-nuget@323ab0502cd38fdc493335025a96c8fdb0edc71f
with:
nuget-version: '5.x'
- name: NuGet Restore
run: nuget restore focalboard\win-wpf\Focalboard.sln
- name: Build Windows WPF app
run: cd focalboard; make win-wpf-app
env:
BUILD_NUMBER: ${{ github.run_id }}
- name: Upload app msix package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard.msix
path: ${{ github.workspace }}/focalboard/win-wpf/focalboard.msix
- name: Upload app zip package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-win.zip
path: ${{ github.workspace }}/focalboard/win-wpf/dist/focalboard-win.zip
================================================
FILE: .github/workflows/lint-server.yml
================================================
name: golangci-lint
on:
push:
branches: [ main, release-** ]
pull_request:
branches: [ main, release-** ]
workflow_dispatch:
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
EXCLUDE_ENTERPRISE: true
jobs:
down-migrations:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: assert that down migrations are SELECT 1 scripts
run: |
cd focalboard
echo 'SELECT 1;' > downmigration
for file in server/services/store/sqlstore/migrations/*.down.sql; do diff -Bw downmigration $file; done
golangci:
name: plugin
runs-on: ubuntu-22.04
steps:
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version: 1.21
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: set up golangci-lint
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.59.0
- name: lint
run: |
cd focalboard
make server-lint
================================================
FILE: .github/workflows/prod-release.yml
================================================
name: Production-Release
on: workflow_dispatch
env:
EXCLUDE_ENTERPRISE: true
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
jobs:
ubuntu:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Replace token 1 server
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: Replace token 2 server
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_PROD_KEY }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: npm ci
run: cd focalboard/webapp; npm ci --no-optional
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version: 1.21
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 20.11.0
- name: apt-get update
run: sudo apt-get update
- name: apt-get install -y libgtk-3-dev
run: sudo apt-get install -y libgtk-3-dev
- name: apt-get install -y libwebkit2gtk-4.0-dev
run: sudo apt-get install -y libwebkit2gtk-4.0-dev
- name: Build Linux server and app
run: cd focalboard; make server-linux-package linux-app
env:
BUILD_NUMBER: ${{ github.run_id }}
- name: Upload server package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-server-linux-amd64.tar.gz
path: ${{ github.workspace }}/focalboard/dist/focalboard-server-linux-amd64.tar.gz
- name: Upload app package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-linux.tar.gz
path: ${{ github.workspace }}/focalboard/linux/dist/focalboard-linux.tar.gz
macos:
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Replace token 1 server
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: Replace token 2 server
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_PROD_KEY }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: npm ci
run: cd focalboard/webapp; npm ci --no-optional
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version: 1.21
- name: List Xcode versions
run: ls -n /Applications/ | grep Xcode*
- name: Build macOS
run: cd focalboard; make mac-app
env:
DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer
BUILD_NUMBER: ${{ github.run_id }}
- name: Upload macOS package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-mac.zip
path: ${{ github.workspace }}/focalboard/mac/dist/focalboard-mac.zip
windows:
runs-on: windows-2025
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: "focalboard"
- name: Replace token 1 server
run: sed -i -e "s,placeholder_rudder_dataplane_url,${{ secrets.RUDDER_DATAPLANE_URL }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: Replace token 2 server
run: sed -i -e "s,placeholder_rudder_key,${{ secrets.RUDDER_PROD_KEY }},g" ${{ github.workspace }}/focalboard/server/services/telemetry/telemetry.go
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.3
- name: npm ci
run: cd focalboard/webapp; npm ci --no-optional
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version: 1.21
- name: Setup NuGet
uses: nuget/setup-nuget@323ab0502cd38fdc493335025a96c8fdb0edc71f
with:
nuget-version: '5.x'
- name: NuGet Restore
run: nuget restore focalboard\win-wpf\Focalboard.sln
- name: Build Windows WPF app
run: cd focalboard; make win-wpf-app
env:
BUILD_NUMBER: ${{ github.run_id }}
- name: Upload app msix package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard.msix
path: ${{ github.workspace }}/focalboard/win-wpf/focalboard.msix
- name: Upload app zip package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: focalboard-win.zip
path: ${{ github.workspace }}/focalboard/win-wpf/dist/focalboard-win.zip
================================================
FILE: .github/workflows/scorecards-analysis.yml
================================================
name: Scorecards supply-chain security
on:
# Only the default branch is supported.
branch_protection_rule:
schedule:
- cron: '38 10 * * 2'
push:
branches: [ main ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecards analysis
runs-on: ubuntu-22.04
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
actions: read
contents: read
steps:
- name: "Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
with:
results_file: results.sarif
results_format: sarif
# Read-only PAT token. To create it,
# follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation.
repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
# Publish the results to enable scorecard badges. For more details, see
# https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories, `publish_results` will automatically be set to `false`,
# regardless of the value entered here.
publish_results: true
# Upload the results as artifacts (optional).
- name: "Upload artifact"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e
with:
sarif_file: results.sarif
================================================
FILE: .gitignore
================================================
# Created by https://www.gitignore.io/api/node
### Node ###
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# OS Files
.DS_Store
# VSCode project files
.vscode
*.code-workspace
# golang
go.work
go.work.sum
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Environment files
.env
# Dependency directory
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
node_modules
dist
pack
package
bin
debug
__debug_bin
files
octo*.db
focalboard*.db
*.boardarchive
.eslintcache
.vscode/settings.json
# config.json is copied from app-config.json in the Makefile
mac/resources/config.json
mac/temp
mac/dist
mac/*.xcodeproj/**/xcuserdata
linux/bin
linux/dist
linux/temp
win/temp
win/dist
webapp/cypress/screenshots
webapp/cypress/videos
server/swagger/clients
server/vendor
.idea
docker/certs
docker/data
server/**/*.coverage
================================================
FILE: .gitlab-ci.yml
================================================
stages:
- build
- s3
variables:
BUILD: "yes"
IMAGE_BUILDER: $CI_REGISTRY/mattermost/ci/images/builder:go-1.19.5-node-16.15.0-1
include:
- project: mattermost/ci/focalboard
ref: main
file: private.yml
================================================
FILE: .gitpod.yml
================================================
mainConfiguration: https://github.com/mattermost/mattermost-gitpod-config
================================================
FILE: CHANGELOG.md
================================================
# Focalboard Changelog
Focalboard is an open source, self-hosted alternative to Trello, Notion, Asana and Jira for project management. We help individuals and teams define, organize, track and manage their work.
This changelog summarizes updates to our open source project. You can also find the [latest releases and release notes on GitHub here](https://github.com/mattermost/focalboard/releases).
## v0.15 Release - March, 2022
* Onboarding tour. Thanks @harshilsharma63! @jespino!
* Channel intro link to Boards. Thanks @sbishel!
* Improved share board UI. Thanks @sbishel!
* New error pages. Thanks @wiggin77! @asaadmahmood!
* In-app links to import Help Docs. Thanks @justinegeffen! @sbishel!
* Toggle to hide empty groups for TableView. Thanks @vish9812!
* Removed transactions from sqlite backend to prevent locking issues. Thanks @jespino!
* Update readme with accurate Linux standalone app build instructions. Thanks @wiggin77!
* Change wrapping in React.memo. Thanks @kamre!
* Don't use property value for key construction. Thanks @kamre!
* Updated comment box alignment. Thanks @asaadmahmood!
* Show "(Deleted User)" instead of UUID when user not found. Thanks @akkivasu!
## v0.14 Release - February, 2022
* Template selector dialog. Thanks @jespino!
* New standard templates. Thanks @wiggin77!
* Archive file format has changed and now supports images. Thanks @wiggin77!
* Card badges. Thanks @kamre!
* URL property improvement. Thanks @kamre!
* GIF support in card descriptions. Thanks @asaadmahmood!
* Add links to linode. Thanks @ChaseKnowlden!
* Add `chown` for nobody in the docker run example. Thanks @K3UL!
* Fixed Mac M1 chip build. Thanks @jpaldeano!
* Removed link to deleted css file. Thanks @kamre!
* Fixed typo in config.toml. Thanks @krmh04!
## v0.12 Release - January, 2022
* Change notifications. Thanks @wiggin77!
* Person avatars. Thanks @asaadmahmood!
* Updated comment sort order. Thanks @asaadmahmood!
## v0.11 Release - December, 2021
* Calendar view. Thanks @sbishel!
* `@mention` autocomplete. Thanks @hahmadia!
## v0.10 Release - November, 2021
* @mention notifications. Thanks @wiggin77!
* Board calculations. Thanks @harshilsharma63!
* Unfurl card previews in posts. Thanks @hahmadia!
* Plus many, many contributions from Hacktoberfest and beyond, including from: @jufab, @kamre, @Johennes, @nishantwrp, @tiago154, @DeeJayBro, @CuriousCorrelation, @prakharporwal, @donno2048, @anchepiece, @puerco, @adithyaakrishna, @JenyaFTW, @ivernus, @grsky360, @b4sen, @naresh1205, @JtheBAB, @ssensalo, @berkeka, @yedamao, @Prassud, @NakulChauhan2001, @achie27, @crspeller, @sahil9001, @alauregaillard, @igordsm, @rafaeelaudibert, @kaakaa, @Sayanta66, @Bhavin789, @Shahzayb, @kayazeren, @fcoiuri, @tsabi, @DeviousLab, @leosunmo, @xMicky24GIT, @majidsajadi, @marcvelasco, and @aloks98. Sorry if we missed anyone in this list!
## v0.9 Release - August, 2021
* New date range property type. Thanks @sbishel!
* Changed the urls to use routes instead of query parameters. Thanks @jespino!
* Add clear button to value selectors. Thanks @jespino!
* Fix auto-size columns in FireFox. Thanks @kamre!
* Fix comments not appearing in readonly view. Thanks @harshilsharma63!
* Multi-line card titles. Thanks @kamre!
* Add unit tests for sqlstore. Thanks @yedamao!
* Add makefile documentation. Thanks @Szymongib!
## v0.8 Release - July, 2021
* CreatedBy property. Thanks @harshilsharma63!
* Fix dragged card order. Thanks @kamre!
* Date format user setting. Thanks @darkLord19!
* Add property tooltip in board view. Thanks @ditsemto!
* Fix plugin links. Thanks @N3rdP1um23!
* Add MySQL documentation. Thanks @ctlaltdieliet and @3l0w!
* RPC API support. Thanks @agnivade!
## v0.7.0 Release - June, 2021
* Multi-select property type. Thanks @hahmadia!
* Checkbox property type. Thanks @mickmister!
* Person property type. Thanks @harshilsharma63!
* Grouped table view. Thanks @sbishel!
* Export individual boards. Thanks @hahmadia!
* Focalboard can now be built as a Mattermost plugin! Thanks @mgdelacroix and @jespino!
* Improved read-only fields display. Thanks @Johennes!
* Improved logging. Thanks @wiggin77!
* Prometheus metrics. Thanks @spirosoik!
* Mac: Open window by clicking on the dock icon. Thanks @Johennes!
* Additional unit tests. Thanks @matheusmosca!
* Fixed Linux app caret display. Thanks @fritsstegmann!
* Added CodeQL check. Thanks @srkgupta!
## v0.6.7 Release - May, 2021
* Key Updates:
* Added Todoist import script. Thanks @harshilsharma63!
* Added MySql database support. Thanks @jespino!
* Added URL and phone number properties. Thanks @BharatKalluri!
* Added documentation for share board. Thanks @haardikdharma10!
* Persist Mac app settings. Thanks @Johennes!
* Improved board sorting without leading emoji. Thanks @Johennes!
* Added Prettier linting for SCSS. Thanks @signalwerk!
* Improved table headers. Thanks @sbishel!
* Disable unused Mac tab menu. Thanks @@haardikdharma10!
* Fixed server lint issues. Thanks @harshilsharma63!
* Updated open button. Thanks @arjitc!
## v0.6.5 Release - April 19, 2021
* Key Updates:
* Focalboard now available on DockerHub at https://hub.docker.com/r/mattermost/focalboard. [#91](https://github.com/mattermost/focalboard/issues/91) Thanks @jwilander @obbardc!
* You can now contribute translations to Focalboard on https://translate.mattermost.com/. Thanks @jespino!
* Added German language translation. Thanks @svelle!
* Added Japanese language translation. Thanks @kaakaa!
* Added French language translation. Thanks @CyrilLD!
* Added Occitan language translation. Thanks Quentin PAGÈS!
* Added Dutch language translation. Thanks Tom De Moor!
* Added Turkish language translation. Thanks Abdullah Musab!
* Added Chinese language translation. Thanks Yao Xie and toto6038!
* Added Russian language translation. Thanks Edward Smirnov!
* Add Dockerfile to run service in a container. [#76](https://github.com/mattermost/focalboard/pull/76) Thanks @proffalken!
* Add docker-compose to run the whole service in containers. [#105](https://github.com/mattermost/focalboard/pull/105) Thanks @jbutler992!
* Added Gallery view.
* Added Checkbox content type.
* Added Selected cards duplication with Ctrl+D.
* Added Search shortcut (Ctrl+Shift+F).
* Requested Contributions
* Add more frontend unit test coverage. [#126](https://github.com/mattermost/focalboard/pull/126) Thanks @renjithgr!
* [GH-40](https://github.com/mattermost/focalboard/issues/40) - Add property type email [#84](https://github.com/mattermost/focalboard/pull/84). Thanks @renjithgr!
## v0.6.1 Release - March 15, 2021
* Focalboard Personal Desktop is now live in the App Stores:
* [Mac App Store](https://apps.apple.com/app/apple-store/id1556908618?pt=2114704&ct=changelog&mt=8)
* [Microsoft App Store](https://www.microsoft.com/store/apps/9NLN2T0SX9VF?cid=changelog)
* Added [Windows native app (WPF)](https://github.com/mattermost/focalboard/tree/main/win-wpf) support
* Added [Swagger / OpenAPI definition and documentation](https://htmlpreview.github.io/?https://github.com/mattermost/focalboard/blob/main/server/swagger/docs/html/index.html)
* Added [Import scripts for Trello, Asana, and Notion](https://github.com/mattermost/focalboard/tree/main/import)
* Added [Developer Tips and Tricks article](https://www.focalboard.com/contribute/getting-started/dev-tips/).
* Added Security improvements:
* [Single-user session token](https://github.com/mattermost/focalboard/commit/0fe96ad7ed3b0c3a68c9a5889b34b764782f9266)
* [CSRF prevention with X-Requested-With header](https://github.com/mattermost/focalboard/commit/43c656c9a440e12f87b61d66654ed3d9873b1620)
================================================
FILE: CONTRIBUTING.md
================================================
# Disclaimer
> [!WARNING]
> **Effective September 15th, 2023, Mattermost, Inc. staff are no longer reviewing or merging pull requests for either Focalboard or the Mattermost Boards plugin in this repository (`mattermost/focalboard`). We encourage the community to fork this repository for continued development and contributions.**
>
> The reason behind these changes is to focus Mattermost developer resources on improving the platform’s performance and core features to ensure Mattermost continues being resilient, stable, and best-in-breed for critical operations.
>
> ️💡 [Learn more](https://forum.mattermost.com/t/upcoming-product-changes-to-boards-and-various-plugins/16669)
## Past maintainers
- **Scott Bishel**: [@sbishel](https://github.com/sbishel)
- **Jesús Espino**: [@jespino](https://github.com/jespino)
- **Doug Lauder**: [@wiggin77](https://github.com/wiggin77)
- **Miguel de la Cruz**: [@mgdelacroix](https://github.com/mgdelacroix)
- **Harshil Sharma**: [@harshilsharma63](https://github.com/harshilsharma63)
- **Chen Lim**: [@chenilim](https://github.com/chenilim)
- **Ogi Marušić**: [@ogi-m](https://github.com/ogi-m)
- **Winson Wu**: [@wuwinson](https://github.com/wuwinson)
- **Justine Geffen**: [@justinegeffen](https://github.com/justinegeffen)
================================================
FILE: Dockerfile.build
================================================
# This Dockerfile is used to build Focalboard for Linux. It builds all the parts inside the image
# and the last stage just holds the package which is then copied back to the host.
#
# docker buildx build -f Dockerfile.build --no-cache --platform linux/amd64 -t focalboard-build:dirty --output out .
# docker buildx build -f Dockerfile.build --no-cache --platform linux/arm64 -t focalboard-build:dirty --output out .
#
# Afterwards the packages can be found in the ./out folder.
# build frontend
FROM node:16.3.0@sha256:ca6daf1543242acb0ca59ff425509eab7defb9452f6ae07c156893db06c7a9a4 AS frontend
WORKDIR /webapp
COPY webapp .
### 'CPPFLAGS="-DPNG_ARM_NEON_OPT=0"' Needed To Avoid Bug Described in: https://github.com/imagemin/optipng-bin/issues/118#issuecomment-1019838562
### Can be Removed when Ticket will be Closed
RUN CPPFLAGS="-DPNG_ARM_NEON_OPT=0" npm install --no-optional && \
npm run pack
# build backend and package
FROM golang:1.18.3@sha256:b203dc573d81da7b3176264bfa447bd7c10c9347689be40540381838d75eebef AS backend
COPY . .
COPY --from=frontend /webapp/pack webapp/pack
ARG TARGETARCH
# RUN apt-get update && apt-get install libgtk-3-dev libwebkit2gtk-4.0-dev -y
RUN EXCLUDE_PLUGIN=true EXCLUDE_SERVER=true EXCLUDE_ENTERPRISE=true make server-linux arch=${TARGETARCH}
RUN make server-linux-package-docker arch=${TARGETARCH}
# Copy package back to host
FROM scratch AS dist
ARG TARGETARCH
COPY --from=backend /go/dist/focalboard-server-linux-${TARGETARCH}.tar.gz .
================================================
FILE: LICENSE.txt
================================================
Mattermost Licensing
SOFTWARE LICENSING
You are licensed to use compiled versions of Focalboard produced by Mattermost, Inc. under an MIT LICENSE
- See MIT-COMPILED-LICENSE.md included in compiled versions for details
You may be licensed to use source code to create compiled versions not produced by Mattermost, Inc. in one of two ways:
1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or
2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com
You are licensed to use the source code in Admin Tools and Configuration Files (webapp/html-templates/, app-config.json,
config.json, webapp/i18n/, server/model/, plugin/ and all subdirectories thereof) under the Apache License v2.0.
We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not
link to Focalboard directly, but exclusively uses Focalboard's Admin Tools and Configuration Files, and
(b) you have not modified, added to or adapted the source code of Focalboard in a way that results in the creation of
a “modified version” or “work based on” Focalboard as these terms are defined in the AGPL v3.0 license.
MATTERMOST TRADEMARK GUIDELINES
Your use of the mark Mattermost is subject to Mattermost, Inc's prior written approval and our organization’s Trademark
Standards of Use at http://www.mattermost.org/trademark-standards-of-use/. For trademark approval or any questions
you have about using these trademarks, please email trademark@mattermost.com
------------------------------------------------------------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------------------------------------------------------------------------------
The software is released under the terms of the GNU Affero General Public
License, version 3.
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
================================================
FILE: Makefile
================================================
.PHONY: prebuild clean cleanall ci server server-mac server-linux server-win server-linux-package generate watch-server webapp mac-app win-app-wpf linux-app modd-precheck templates-archive
PACKAGE_FOLDER = focalboard
# Build Flags
BUILD_NUMBER ?= $(BUILD_NUMBER:)
BUILD_DATE = $(shell date -u)
BUILD_HASH = $(shell git rev-parse HEAD)
# If we don't set the build number it defaults to dev
ifeq ($(BUILD_NUMBER),)
BUILD_NUMBER := dev
BUILD_DATE := n/a
endif
BUILD_TAGS += json1 sqlite3
LDFLAGS += -X "github.com/mattermost/focalboard/server/model.BuildNumber=$(BUILD_NUMBER)"
LDFLAGS += -X "github.com/mattermost/focalboard/server/model.BuildDate=$(BUILD_DATE)"
LDFLAGS += -X "github.com/mattermost/focalboard/server/model.BuildHash=$(BUILD_HASH)"
RACE = -race
ifeq ($(OS),Windows_NT)
RACE := ''
endif
# MAC cpu architecture
ifeq ($(shell uname -m),arm64)
MAC_GO_ARCH := arm64
else
MAC_GO_ARCH := amd64
endif
all: webapp server ## Build server and webapp.
prebuild: ## Run prebuild actions (install dependencies etc.).
cd webapp; npm install
ci: webapp-ci server-test ## Simulate CI, locally.
templates-archive: ## Build templates archive file
cd server/assets/build-template-archive; go run -tags '$(BUILD_TAGS)' main.go --dir="../templates-boardarchive" --out="../templates.boardarchive"
server: ## Build server for local environment.
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=dev")
cd server; go build -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -o ../bin/focalboard-server ./main
server-mac: ## Build server for Mac.
mkdir -p bin/mac
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=mac")
ifeq ($(FB_PROD),)
cd server; env GOOS=darwin GOARCH=$(MAC_GO_ARCH) go build -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -o ../bin/mac/focalboard-server ./main
else
# Always build x86 for production, to work on both Apple Silicon and legacy Macs
cd server; env GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -o ../bin/mac/focalboard-server ./main
endif
server-linux: ## Build server for Linux.
mkdir -p bin/linux
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=linux")
cd server; env GOOS=linux GOARCH=$(arch) go build -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -o ../bin/linux/focalboard-server ./main
server-docker: ## Build server for Docker Architectures.
mkdir -p bin/docker
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=linux")
cd server; env GOOS=$(os) GOARCH=$(arch) go build -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -o ../bin/docker/focalboard-server ./main
server-win: ## Build server for Windows.
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=win")
cd server; env GOOS=windows GOARCH=amd64 go build -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -o ../bin/win/focalboard-server.exe ./main
server-dll: ## Build server as Windows DLL.
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=win")
cd server; env GOOS=windows GOARCH=amd64 go build -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -buildmode=c-shared -o ../bin/win-dll/focalboard-server.dll ./main
server-linux-package: server-linux webapp
rm -rf package
mkdir -p package/${PACKAGE_FOLDER}/bin
cp bin/linux/focalboard-server package/${PACKAGE_FOLDER}/bin
cp -R webapp/pack package/${PACKAGE_FOLDER}/pack
cp server-config.json package/${PACKAGE_FOLDER}/config.json
cp NOTICE.txt package/${PACKAGE_FOLDER}
cp webapp/NOTICE.txt package/${PACKAGE_FOLDER}/webapp-NOTICE.txt
mkdir -p dist
cd package && tar -czvf ../dist/focalboard-server-linux-amd64.tar.gz ${PACKAGE_FOLDER}
rm -rf package
server-linux-package-docker:
rm -rf package
mkdir -p package/${PACKAGE_FOLDER}/bin
cp bin/linux/focalboard-server package/${PACKAGE_FOLDER}/bin
cp -R webapp/pack package/${PACKAGE_FOLDER}/pack
cp server-config.json package/${PACKAGE_FOLDER}/config.json
cp NOTICE.txt package/${PACKAGE_FOLDER}
cp webapp/NOTICE.txt package/${PACKAGE_FOLDER}/webapp-NOTICE.txt
mkdir -p dist
cd package && tar -czvf ../dist/focalboard-server-linux-$(arch).tar.gz ${PACKAGE_FOLDER}
rm -rf package
generate: ## Install and run code generators.
cd server; go install github.com/golang/mock/mockgen@v1.6.0
cd server; go generate ./...
server-lint: ## Run linters on server code.
@if ! [ -x "$$(command -v golangci-lint)" ]; then \
echo "golangci-lint is not installed. Please see https://github.com/golangci/golangci-lint#install-golangci-lint for installation instructions."; \
exit 1; \
fi;
cd server; golangci-lint run ./...
modd-precheck:
@if ! [ -x "$$(command -v modd)" ]; then \
echo "modd is not installed. Please see https://github.com/cortesi/modd#install for installation instructions"; \
exit 1; \
fi; \
watch: modd-precheck ## Run both server and webapp watching for changes
env FOCALBOARD_BUILD_TAGS='$(BUILD_TAGS)' modd
watch-single-user: modd-precheck ## Run both server and webapp in single user mode watching for changes
env FOCALBOARDSERVER_ARGS=--single-user FOCALBOARD_BUILD_TAGS='$(BUILD_TAGS)' modd
watch-server-test: modd-precheck ## Run server tests watching for changes
env FOCALBOARD_BUILD_TAGS='$(BUILD_TAGS)' modd -f modd-servertest.conf
server-test: server-test-sqlite server-test-mysql server-test-mariadb server-test-postgres ## Run server tests
server-test-sqlite: export FOCALBOARD_UNIT_TESTING=1
server-test-sqlite: ## Run server tests using sqlite
cd server; go test -tags '$(BUILD_TAGS)' -race -v -coverpkg=./... -coverprofile=server-sqlite-profile.coverage -count=1 -timeout=30m ./...
cd server; go tool cover -func server-sqlite-profile.coverage
server-test-mini-sqlite: export FOCALBOARD_UNIT_TESTING=1
server-test-mini-sqlite: ## Run server tests using sqlite
cd server/integrationtests; go test -tags '$(BUILD_TAGS)' $(RACE) -v -count=1 -timeout=30m ./...
server-test-mysql: export FOCALBOARD_UNIT_TESTING=1
server-test-mysql: export FOCALBOARD_STORE_TEST_DB_TYPE=mysql
server-test-mysql: export FOCALBOARD_STORE_TEST_DOCKER_PORT=44446
server-test-mysql: ## Run server tests using mysql
@echo Starting docker container for mysql
docker compose -f ./docker-testing/docker-compose-mysql.yml down -v --remove-orphans
docker compose -f ./docker-testing/docker-compose-mysql.yml run start_dependencies
cd server; go test -tags '$(BUILD_TAGS)' -race -v -coverpkg=./... -coverprofile=server-mysql-profile.coverage -count=1 -timeout=30m ./...
cd server; go tool cover -func server-mysql-profile.coverage
docker compose -f ./docker-testing/docker-compose-mysql.yml down -v --remove-orphans
server-test-mariadb: export FOCALBOARD_UNIT_TESTING=1
server-test-mariadb: export FOCALBOARD_STORE_TEST_DB_TYPE=mariadb
server-test-mariadb: export FOCALBOARD_STORE_TEST_DOCKER_PORT=44445
server-test-mariadb: templates-archive ## Run server tests using mysql
@echo Starting docker container for mariadb
docker compose -f ./docker-testing/docker-compose-mariadb.yml down -v --remove-orphans
docker compose -f ./docker-testing/docker-compose-mariadb.yml run start_dependencies
cd server; go test -tags '$(BUILD_TAGS)' -race -v -coverpkg=./... -coverprofile=server-mariadb-profile.coverage -count=1 -timeout=30m ./...
cd server; go tool cover -func server-mariadb-profile.coverage
docker compose -f ./docker-testing/docker-compose-mariadb.yml down -v --remove-orphans
server-test-postgres: export FOCALBOARD_UNIT_TESTING=1
server-test-postgres: export FOCALBOARD_STORE_TEST_DB_TYPE=postgres
server-test-postgres: export FOCALBOARD_STORE_TEST_DOCKER_PORT=44447
server-test-postgres: ## Run server tests using postgres
@echo Starting docker container for postgres
docker compose -f ./docker-testing/docker-compose-postgres.yml down -v --remove-orphans
docker compose -f ./docker-testing/docker-compose-postgres.yml run start_dependencies
cd server; go test -tags '$(BUILD_TAGS)' -race -v -coverpkg=./... -coverprofile=server-postgres-profile.coverage -count=1 -timeout=30m ./...
cd server; go tool cover -func server-postgres-profile.coverage
docker compose -f ./docker-testing/docker-compose-postgres.yml down -v --remove-orphans
webapp: ## Build webapp.
cd webapp; npm run pack
webapp-ci: ## Webapp CI: linting & testing.
cd webapp; npm run check
cd webapp; npm run test
cd webapp; npm run cypress:ci
webapp-test: ## jest tests for webapp
cd webapp; npm run test
mac-app: server-mac webapp ## Build Mac application.
rm -rf mac/temp
rm -rf mac/dist
rm -rf mac/resources/bin
rm -rf mac/resources/pack
mkdir -p mac/resources/bin
cp bin/mac/focalboard-server mac/resources/bin/focalboard-server
cp app-config.json mac/resources/config.json
cp -R webapp/pack mac/resources/pack
mkdir -p mac/temp
xcodebuild archive -workspace mac/Focalboard.xcworkspace -scheme Focalboard -archivePath mac/temp/focalboard.xcarchive CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGNING_ALLOWED="NO" \
|| { echo "xcodebuild failed, did you install the full Xcode and not just the CLI tools?"; exit 1; }
mkdir -p mac/dist
cp -R mac/temp/focalboard.xcarchive/Products/Applications/Focalboard.app mac/dist/
# xcodebuild -exportArchive -archivePath mac/temp/focalboard.xcarchive -exportPath mac/dist -exportOptionsPlist mac/export.plist
cp NOTICE.txt mac/dist
cp webapp/NOTICE.txt mac/dist/webapp-NOTICE.txt
cd mac/dist; zip -r focalboard-mac.zip Focalboard.app MIT-COMPILED-LICENSE.md NOTICE.txt webapp-NOTICE.txt
win-wpf-app: server-dll webapp ## Build Windows WPF application.
cd win-wpf && ./build.bat
cd win-wpf && ./package.bat
cd win-wpf && ./package-zip.bat
linux-app: webapp ## Build Linux application.
rm -rf linux/temp
rm -rf linux/dist
mkdir -p linux/dist
mkdir -p linux/temp/focalboard-app
cp app-config.json linux/temp/focalboard-app/config.json
cp NOTICE.txt linux/temp/focalboard-app/
cp webapp/NOTICE.txt linux/temp/focalboard-app/webapp-NOTICE.txt
cp -R webapp/pack linux/temp/focalboard-app/pack
cd linux; make build
cp -R linux/bin/focalboard-app linux/temp/focalboard-app/
cd linux/temp; tar -zcf ../dist/focalboard-linux.tar.gz focalboard-app
rm -rf linux/temp
swagger: ## Generate swagger API spec and clients based on it.
mkdir -p server/swagger/docs
mkdir -p server/swagger/clients
cd server && swagger generate spec -m -o ./swagger/swagger.yml
cd server/swagger && openapi-generator generate -i swagger.yml -g html2 -o docs/html
cd server/swagger && openapi-generator generate -i swagger.yml -g go -o clients/go
cd server/swagger && openapi-generator generate -i swagger.yml -g javascript -o clients/javascript
cd server/swagger && openapi-generator generate -i swagger.yml -g typescript-fetch -o clients/typescript
cd server/swagger && openapi-generator generate -i swagger.yml -g swift5 -o clients/swift
cd server/swagger && openapi-generator generate -i swagger.yml -g python -o clients/python
clean: ## Clean build artifacts.
rm -rf bin
rm -rf dist
rm -rf webapp/pack
rm -rf mac/temp
rm -rf mac/dist
rm -rf linux/dist
rm -rf win-wpf/msix
rm -f win-wpf/focalboard.msix
cleanall: clean ## Clean all build artifacts and dependencies.
rm -rf webapp/node_modules
## Help documentatin à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
help:
@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' ./Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
================================================
FILE: NOTICE.txt
================================================
Focalboard
© 2015-present Mattermost, Inc. All Rights Reserved. See LICENSE.txt for license information.
NOTICES:
--------
This document includes a list of open source components used in Focalboard, including those that have been modified.
-----
## Go
This product uses the Go programming language by the Go authors.
* HOMEPAGE:
* https://golang.org
* LICENSE: BSD-style
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## Masterminds/squirrel
This product contains 'squirrel' by GitHub user "Masterminds".
Fluent SQL generation for golang
* HOMEPAGE:
* https://github.com/Masterminds/squirrel
* LICENSE: MIT
Squirrel
The Masterminds
Copyright (C) 2014-2015, Lann Martin
Copyright (C) 2015-2016, Google
Copyright (C) 2015, Matt Farina and Matt Butcher
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
## golang-migrate/migrate
This product contains 'migrate' by GitHub user "golang-migrate".
Database migrations. CLI and Golang library.
* HOMEPAGE:
* https://github.com/golang-migrate/migrate
* LICENSE: MIT
The MIT License (MIT)
Original Work
Copyright (c) 2016 Matthias Kadenbach
https://github.com/mattes/migrate
Modified Work
Copyright (c) 2018 Dale Hui
https://github.com/golang-migrate/migrate
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
## x/tools
This product contains 'tools' by The Go Authors.
[mirror] Go tools
* HOMEPAGE:
* https://github.com/golang/tools
* LICENSE: BSD-3-Clause
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## x/crypto
This product contains 'crypto' by The Go Authors.
[mirror] Go supplementary cryptography libraries
* HOMEPAGE:
* https://github.com/golang/crypto
* LICENSE: BSD-3-Clause
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## gorilla/handlers
This product contains 'handlers' by Gorilla web toolkit.
A collection of useful handlers for Go's net/http package.
* HOMEPAGE:
* https://github.com/gorilla/handlers
* LICENSE: BSD-2-Clause
Copyright (c) 2013 The Gorilla Handlers Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## gorilla/mux
This product contains 'mux' by Gorilla web toolkit.
A powerful URL router and dispatcher for golang.
* HOMEPAGE:
* https://github.com/gorilla/mux
* LICENSE: BSD-3-Clause
Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## gorilla/websocket
This product contains 'websocket' by Gorilla web toolkit.
A WebSocket implementation for Go.
* HOMEPAGE:
* https://github.com/gorilla/websocket
* LICENSE: BSD-2-Clause
Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## zserge/lorca
This product contains 'lorca' by GitHub user "zserge".
A very small library to build modern HTML5 desktop apps in Go.
* HOMEPAGE:
* https://github.com/zserge/lorca
* LICENSE: MIT
MIT License
Copyright (c) 2018 Serge Zaitsev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## webview/webview
This product contains 'webview' by GitHub user "webview".
Tiny cross-platform webview library for C/C++/Golang.
* HOMEPAGE:
* https://github.com/webview/webview
* LICENSE: MIT
MIT License
Copyright (c) 2017 Serge Zaitsev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## lib/pq
This product contains 'pq' by GitHub user "lib".
Pure Go Postgres driver for database/sql
* HOMEPAGE:
* https://github.com/lib/pq
* LICENSE: MIT
Copyright (c) 2011-2013, 'pq' Contributors
Portions Copyright (C) 2011 Blake Mizerany
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
This product contains 'viper' by GitHub user "spf13".
Go configuration with fangs
* HOMEPAGE:
* https://github.com/spf13/viper
* LICENSE: MIT
Copyright (c) 2014 Steve Francia
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
This product contains 'uuid' by Google Inc.
Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
* HOMEPAGE:
* https://github.com/google/uuid
* LICENSE: BSD-3-Clause
Copyright (c) 2009,2014 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## pkg/errors
This product contains 'errors' by GitHub user "pkg".
Simple error handling primitives
* HOMEPAGE:
* https://github.com/pkg/errors
* LICENSE: BSD-2-Clause
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## rudderlabs/analytics-go
This product contains 'analytics-go' by Segment, Inc.
A toolkit with common assertions and mocks that plays nicely with the standard library
* HOMEPAGE:
* https://github.com/rudderlabs/analytics-go
* LICENSE: MIT
The MIT License (MIT)
Copyright (c) 2016 Segment, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
## gonutz/w32
This product contains 'testify' by Stretchr, Inc..
A wrapper of Windows APIs for the Go Programming Language.
* HOMEPAGE:
* https://github.com/gonutz/w32
* LICENSE: BSD-style
Copyright (c) 2010-2012 The w32 Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## stretchr/testify
This product contains 'testify' by Stretchr, Inc..
A toolkit with common assertions and mocks that plays nicely with the standard library
* HOMEPAGE:
* https://github.com/stretchr/testify
* LICENSE: MIT
MIT License
Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## mattn/go-sqlite3
This product contains 'go-sqlite3' by GitHub user "mattn".
sqlite3 driver for go using database/sql
* HOMEPAGE:
* https://github.com/mattn/go-sqlite3
* LICENSE: MIT
The MIT License (MIT)
Copyright (c) 2014 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## zap
This product contains 'zap' by Uber Technologies, Inc.
Blazing fast, structured, leveled logging in Go.
* HOMEPAGE:
* https://github.com/uber-go/zap
* LICENSE: MIT
Copyright (c) 2016-2017 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
## nicksnyder/go-i18n
This product contains 'go-i18n' by GitHub user 'nicksnyder'.
Translate your Go program into multiple languages.
* HOMEPAGE:
* https://github.com/nicksnyder/go-i18n
* LICENSE: MIT
Copyright (c) 2014 Nick Snyder https://github.com/nicksnyder
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
## niemeyer/pretty
This product contains 'pretty' by GitHub user "niemeyer"
Pretty printing for Go values
* HOMEPAGE:
* https://github.com/niemeyer/pretty
* LICENSE: MIT
Copyright 2012 Keith Rarick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
## wiggin77/merror
This product contains 'merror' by GitHub user 'wiggin77'.
Multiple Error aggregator for Go.
* HOMEPAGE:
* https://github.com/wiggin77/merror
* LICENSE: MIT
MIT License
Copyright (c) 2018 wiggin77
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
> [!WARNING]
> This repository is currently not maintained. If you're interested in becoming a maintainer please [let us know here](https://github.com/mattermost-community/focalboard/issues/5038).
>
> This repository only contains standalone Focalboard. If you're looking for the Mattermost plugin please see [mattermost/mattermost-plugin-boards](https://github.com/mattermost/mattermost-plugin-boards).
>
# Focalboard





Focalboard is an open source, multilingual, self-hosted project management tool that's an alternative to Trello, Notion, and Asana.
It helps define, organize, track and manage work across individuals and teams. Focalboard comes in two editions:
* **[Personal Desktop](https://www.focalboard.com/docs/personal-edition/desktop/)**: A standalone, single-user [macOS](https://apps.apple.com/app/apple-store/id1556908618?pt=2114704&ct=website&mt=8), [Windows](https://www.microsoft.com/store/apps/9NLN2T0SX9VF?cid=website), or [Linux](https://www.focalboard.com/download/personal-edition/desktop/#linux-desktop) desktop app for your own todos and personal projects.
* **[Personal Server](https://www.focalboard.com/download/personal-edition/ubuntu/)**: A standalone, multi-user server for development and personal use.
## Try Focalboard
### Personal Desktop (Windows, Mac or Linux Desktop)
* **Windows**: Download from the [Windows App Store](https://www.microsoft.com/store/productId/9NLN2T0SX9VF) or download `focalboard-win.zip` from the [latest release](https://github.com/mattermost/focalboard/releases), unpack, and run `Focalboard.exe`.
* **Mac**: Download from the [Mac App Store](https://apps.apple.com/us/app/focalboard-insiders/id1556908618?mt=12).
* **Linux Desktop**: Download `focalboard-linux.tar.gz` from the [latest release](https://github.com/mattermost/focalboard/releases), unpack, and open `focalboard-app`.
### Personal Server
**Ubuntu**: You can download and run the compiled Focalboard **Personal Server** on Ubuntu by following [our latest install guide](https://www.focalboard.com/download/personal-edition/ubuntu/).
### API Docs
Boards API docs can be found over at <https://htmlpreview.github.io/?https://github.com/mattermost/focalboard/blob/main/server/swagger/docs/html/index.html>
### Getting started
Our [developer guide](https://developers.mattermost.com/contribute/focalboard/personal-server-setup-guide) has detailed instructions on how to set up your development environment for the **Personal Server**. You can also join the [~Focalboard community channel](https://community.mattermost.com/core/channels/focalboard) to connect with other developers.
Create an `.env` file in the focalboard directory that contains:
```
EXCLUDE_ENTERPRISE="1"
```
To build the server:
```
make prebuild
make
```
To run the server:
```
./bin/focalboard-server
```
Then navigate your browser to [`http://localhost:8000`](http://localhost:8000) to access your Focalboard server. The port is configured in `config.json`.
Once the server is running, you can rebuild just the web app via `make webapp` in a separate terminal window. Reload your browser to see the changes.
### Building and running standalone desktop apps
You can build standalone apps that package the server to run locally against SQLite:
* **Windows**:
* *Requires Windows 10, [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/) 10.0.19041.0, and .NET 4.8 developer pack*
* Open a `git-bash` prompt.
* Run `make prebuild`
* The above prebuild step needs to be run only when you make changes to or want to install your npm dependencies, etc.
* Once the prebuild is completed, you can keep repeating the below steps to build the app & see the changes.
* Run `make win-wpf-app`
* Run `cd win-wpf/msix && focalboard.exe`
* **Mac**:
* *Requires macOS 11.3+ and Xcode 13.2.1+*
* Run `make prebuild`
* The above prebuild step needs to be run only when you make changes to or want to install your npm dependencies, etc.
* Once the prebuild is completed, you can keep repeating the below steps to build the app & see the changes.
* Run `make mac-app`
* Run `open mac/dist/Focalboard.app`
* **Linux**:
* *Tested on Ubuntu 18.04*
* Install `webgtk` dependencies
* Run `sudo apt-get install libgtk-3-dev`
* Run `sudo apt-get install libwebkit2gtk-4.0-dev`
* Run `make prebuild`
* The above prebuild step needs to be run only when you make changes to or want to install your npm dependencies, etc.
* Once the prebuild is completed, you can keep repeating the below steps to build the app & see the changes.
* Run `make linux-app`
* Uncompress `linux/dist/focalboard-linux.tar.gz` to a directory of your choice
* Run `focalboard-app` from the directory you have chosen
* **Docker**:
* To run it locally from offical image:
* `docker run -it -p 80:8000 mattermost/focalboard`
* To build it for your current architecture:
* `docker build -f docker/Dockerfile .`
* To build it for a custom architecture (experimental):
* `docker build -f docker/Dockerfile --platform linux/arm64 .`
Cross-compilation currently isn't fully supported, so please build on the appropriate platform. Refer to the GitHub Actions workflows (`build-mac.yml`, `build-win.yml`, `build-ubuntu.yml`) for the detailed list of steps on each platform.
### Unit testing
Before checking in commits, run `make ci`, which is similar to the `.gitlab-ci.yml` workflow and includes:
* **Server unit tests**: `make server-test`
* **Web app ESLint**: `cd webapp; npm run check`
* **Web app unit tests**: `cd webapp; npm run test`
* **Web app UI tests**: `cd webapp; npm run cypress:ci`
### Staying informed
* **Changes**: See the [CHANGELOG](CHANGELOG.md) for the latest updates
* **Bug Reports**: [File a bug report](https://github.com/mattermost/focalboard/issues/new?assignees=&labels=bug&template=bug_report.md&title=)
* **Chat**: Join the [~Focalboard community channel](https://community.mattermost.com/core/channels/focalboard)
================================================
FILE: SECURITY.md
================================================
Security
========
Safety and data security is of the utmost priority for the Mattermost community. If you are a security researcher and have discovered a security vulnerability in our codebase, we would appreciate your help in disclosing it to us in a responsible manner.
Reporting security issues
-------------------------
**Please do not use GitHub issues for security-sensitive communication.**
Security issues in the community test server, any of the open source codebases maintained by Mattermost, or any of our commercial offerings should be reported via email to [responsibledisclosure@mattermost.com](mailto:responsibledisclosure@mattermost.com). Mattermost is committed to working together with researchers and keeping them updated throughout the patching process. Researchers who responsibly report valid security issues will be publicly credited for their efforts (if they so choose).
For a more detailed description of the disclosure process and a list of researchers who have previously contributed to the disclosure program, see [Report a Security Vulnerability](https://mattermost.com/security-vulnerability-report/) on the Mattermost website.
Security updates
----------------
Mattermost has a mandatory upgrade policy, and updates are only provided for the latest release. Critical updates are delivered as dot releases. Details on security updates are announced 30 days after the availability of the update.
For more details about the security content of past releases, see the [Security Updates](https://mattermost.com/security-updates/) page on the Mattermost website. For timely notifications about new security updates, subscribe to the [Security Bulletins Mailing List](https://about.mattermost.com/security-bulletin).
Contributing to this policy
---------------------------
If you have feedback or suggestions on improving this policy document, please [create an issue](https://github.com/mattermost/focalboard/issues/new/choose).
================================================
FILE: app-config.json
================================================
{
"serverRoot": "http://localhost:8088",
"port": 8088,
"dbtype": "sqlite3",
"dbconfig": "./focalboard.db",
"useSSL": false,
"webpath": "./pack",
"filespath": "./files",
"telemetry": true,
"localOnly": true
}
================================================
FILE: config.json
================================================
{
"serverRoot": "http://localhost:8000",
"port": 8000,
"dbtype": "sqlite3",
"dbconfig": "./focalboard.db?_busy_timeout=5000",
"dbpingattempts": 5,
"dbtableprefix": "",
"postgres_dbconfig": "dbname=focalboard sslmode=disable",
"useSSL": false,
"webpath": "./webapp/pack",
"filesdriver": "local",
"filespath": "./files",
"telemetry": true,
"prometheusaddress": ":9092",
"webhook_update": [],
"session_expire_time": 2592000,
"session_refresh_time": 18000,
"localOnly": false,
"enableLocalMode": true,
"localModeSocketLocation": "/var/tmp/focalboard_local.socket",
"authMode": "native",
"logging_cfg_file": "",
"audit_cfg_file": "",
"enablePublicSharedBoards": false
}
================================================
FILE: docker/Dockerfile
================================================
### Webapp build
FROM node:16.3.0@sha256:ca6daf1543242acb0ca59ff425509eab7defb9452f6ae07c156893db06c7a9a4 as nodebuild
WORKDIR /webapp
ADD webapp/ /webapp
### 'CPPFLAGS="-DPNG_ARM_NEON_OPT=0"' Needed To Avoid Bug Described in: https://github.com/imagemin/optipng-bin/issues/118#issuecomment-1019838562
### Can be Removed when Ticket will be Closed
RUN CPPFLAGS="-DPNG_ARM_NEON_OPT=0" npm install --no-optional && \
npm run pack
### Go build
FROM golang:1.18.3@sha256:b203dc573d81da7b3176264bfa447bd7c10c9347689be40540381838d75eebef AS gobuild
WORKDIR /go/src/focalboard
ADD . /go/src/focalboard
# Get target architecture
ARG TARGETOS
ARG TARGETARCH
RUN EXCLUDE_PLUGIN=true EXCLUDE_SERVER=true EXCLUDE_ENTERPRISE=true make server-docker os=${TARGETOS} arch=${TARGETARCH}
## Final image
FROM debian:buster-slim@sha256:5b0b1a9a54651bbe9d4d3ee96bbda2b2a1da3d2fa198ddebbced46dfdca7f216
RUN mkdir -p /opt/focalboard/data/files
RUN chown -R nobody:nogroup /opt/focalboard
WORKDIR /opt/focalboard
COPY --from=nodebuild --chown=nobody:nogroup /webapp/pack pack/
COPY --from=gobuild --chown=nobody:nogroup /go/src/focalboard/bin/docker/focalboard-server bin/
COPY --from=gobuild --chown=nobody:nogroup /go/src/focalboard/LICENSE.txt LICENSE.txt
COPY --from=gobuild --chown=nobody:nogroup /go/src/focalboard/docker/server_config.json config.json
USER nobody
EXPOSE 8000/tcp
EXPOSE 8000/tcp 9092/tcp
VOLUME /opt/focalboard/data
CMD ["/opt/focalboard/bin/focalboard-server"]
================================================
FILE: docker/README.md
================================================
# Deploy Focalboard with Docker
## Docker
The Dockerfile gives a quick and easy way to build the latest Focalboard server and deploy it locally. In the example below,
the Focalboard database and files will be persisted in a named volumed called `fbdata`.
From the Focalboard project root directory:
```bash
docker build -f docker/Dockerfile -t focalboard .
docker run -it -v "fbdata:/opt/focalboard/data" -p 80:8000 focalboard
```
Open a browser to [localhost](http://localhost) to start
## Alternative architectures
From the Focalboard project root directory:
```bash
docker build -f docker/Dockerfile --platform linux/arm64 -t focalboard .
docker run -it -v "fbdata:/opt/focalboard/data" -p 80:8000 focalboard
```
## Docker-Compose
Docker-Compose provides the option to automate the build and run step, or even include some of the steps from the [personal server setup](https://www.focalboard.com/download/personal-edition/ubuntu/).
To start the server, change directory to `focalboard/docker` and run:
```bash
docker-compose up
```
This will automatically build the focalboard image and start it with the http port mapping. These examples also create a persistent named volume called `fbdata`.
To run Focalboard with a nginx proxy and a postgres backend, change directory to `focalboard/docker` and run:
```bash
docker-compose -f docker-compose-db-nginx.yml up
```
================================================
FILE: docker/config.json
================================================
{
"serverRoot": "http://localhost:8000",
"port": 8000,
"dbtype": "postgres",
"dbconfig": "postgres://boardsuser:boardsuser-password@focalboard-db/boards?sslmode=disable&connect_timeout=10",
"postgres_dbconfig": "dbname=boards sslmode=disable",
"useSSL": false,
"webpath": "./pack",
"filespath": "./data/files",
"telemetry": true,
"prometheusaddress": ":9092",
"session_expire_time": 2592000,
"session_refresh_time": 18000,
"localOnly": false,
"enableLocalMode": true,
"localModeSocketLocation": "/var/tmp/focalboard_local.socket"
}
================================================
FILE: docker/docker-compose-db-nginx.yml
================================================
version: "3"
services:
app:
build:
context: ../
dockerfile: docker/Dockerfile
container_name: focalboard
depends_on:
- focalboard-db
expose:
- 8000
environment:
- VIRTUAL_HOST=localhost
- VIRTUAL_PORT=8000
- VIRTUAL_PROTO=http
volumes:
- "./config.json:/opt/focalboard/config.json"
- fbdata:/opt/focalboard/data
restart: always
networks:
- proxy
- default
proxy:
image: jwilder/nginx-proxy:latest
container_name: focalboard-proxy
restart: always
ports:
- 80:80
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:
- proxy
focalboard-db:
image: postgres:latest
container_name: focalboard-postgres
restart: always
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: boards
POSTGRES_USER: boardsuser
POSTGRES_PASSWORD: boardsuser-password
volumes:
fbdata:
pgdata:
networks:
proxy:
================================================
FILE: docker/docker-compose.yml
================================================
version: "3"
services:
app:
build:
context: ../
dockerfile: docker/Dockerfile
container_name: focalboard
volumes:
- fbdata:/opt/focalboard/data
ports:
- 80:8000
environment:
- VIRTUAL_HOST=focalboard.local
- VIRTUAL_PORT=8000
volumes:
fbdata:
================================================
FILE: docker/server_config.json
================================================
{
"serverRoot": "http://localhost:8000",
"port": 8000,
"dbtype": "sqlite3",
"dbconfig": "./data/focalboard.db",
"postgres_dbconfig": "dbname=focalboard sslmode=disable",
"useSSL": false,
"webpath": "./pack",
"filespath": "./data/files",
"telemetry": true,
"session_expire_time": 2592000,
"session_refresh_time": 18000,
"localOnly": false,
"enableLocalMode": true,
"localModeSocketLocation": "/var/tmp/focalboard_local.socket"
}
================================================
FILE: docker-testing/docker-compose-mariadb.yml
================================================
version: '2.4'
services:
mariadb:
image: "mariadb:10.9.3"
restart: always
environment:
MARIADB_ROOT_HOST: "%"
MARIADB_ROOT_PASSWORD: mostest
MARIADB_PASSWORD: mostest
MARIADB_USER: mmuser
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost", "-u", "mmuser", "-pmostest"]
interval: 5s
timeout: 10s
retries: 3
tmpfs: /var/lib/mariadb
ports:
- 44445:3306
start_dependencies:
image: mattermost/mattermost-wait-for-dep:latest
depends_on:
- mariadb
command: mariadb:3306
================================================
FILE: docker-testing/docker-compose-mysql.yml
================================================
version: '2.4'
services:
mysql:
image: "mysql/mysql-server:8.0.32"
restart: always
environment:
MYSQL_ROOT_HOST: "%"
MYSQL_ROOT_PASSWORD: mostest
MYSQL_PASSWORD: mostest
MYSQL_USER: mmuser
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
interval: 5s
timeout: 10s
retries: 3
tmpfs: /var/lib/mysql
ports:
- 44446:3306
start_dependencies:
image: mattermost/mattermost-wait-for-dep:latest
depends_on:
- mysql
command: mysql
================================================
FILE: docker-testing/docker-compose-postgres.yml
================================================
version: '2.4'
services:
postgres:
image: "postgres:10"
restart: always
environment:
POSTGRES_USER: mmuser
POSTGRES_PASSWORD: mostest
healthcheck:
test: [ "CMD", "pg_isready", "-h", "localhost" ]
interval: 5s
timeout: 10s
retries: 3
tmpfs: /var/lib/postgresql/data
ports:
- 44447:5432
start_dependencies:
image: mattermost/mattermost-wait-for-dep:latest
depends_on:
- postgres
command: postgres:5432
================================================
FILE: docs/README.md
================================================
# Disclaimer
> [!WARNING]
> **Effective September 15th, 2023, Mattermost, Inc. staff are no longer reviewing or merging pull requests for either Focalboard or the Mattermost Boards plugin in this repository (`mattermost/focalboard`). We encourage the community to fork this repository for continued development and contributions.**
>
> The reason behind these changes is to focus Mattermost developer resources on improving the platform’s performance and core features to ensure Mattermost continues being resilient, stable, and best-in-breed for critical operations.
>
> ️💡 [Learn more](https://forum.mattermost.com/t/upcoming-product-changes-to-boards-and-various-plugins/16669)
================================================
FILE: docs/_config.yml
================================================
title: Focalboard Developers
google_analytics: UA-64458817-2
theme: jekyll-theme-architect
================================================
FILE: docs/code-review.md
================================================
# Code Review Checklist
Currently, all changes to the product must be reviewed by a [core committer](core-committers.md).
## If you are a community member seeking a review
1. Submit your pull request (PR).
* Follow the [contribution checklist](../contribution-checklist/).
2. Wait for a reviewer to be assigned.
* Product managers are on the lookout for new pull requests and usually handle this for you automatically.
* If you have been working alongside a core committer, feel free to message them for help.
* When in doubt, ask for help in the [Focalboard](https://community.mattermost.com/core/channels/focalboard) channel on our community server.
* If you are still stuck, please message Chen Lim (@chenilim on GitHub).
3. [Wait for a review](#if-you-are-awaiting-a-review).
* Expect some interaction with at least one reviewer within 5 business days (weekdays, Monday through Friday, excluding [statutory holidays](https://docs.mattermost.com/process/working-at-mattermost.html#holidays)).
* Keep in mind that core committers are geographically distributed around the world and likely in a different time zone than your own.
* If no interaction has occurred after 5 business days, please [at-mention](https://github.blog/2011-03-23-mention-somebody-they-re-notified/) a reviewer with a comment on your pull request.
4. Make any necessary changes.
* If a reviewer requests changes, your pull request will disappear from their queue of reviews.
* Once you've addressed the concerns, please at-mention the reviewer with a comment on your pull request.
5. Wait for your code to be merged.
* Larger pull requests may require more time to review.
* Once all reviewers have approved your changes, they will handle merging your code.
## If you are awaiting a review
1. Wait patiently for reviews to complete.
* Expect some interaction with each of your reviewers within 5 business days.
* There is no need to explicitly mention them on the pull request or to explicitly reach out on our community server.
2. Make any necessary changes.
* If a reviewer requests changes, your pull request will disappear from their queue of reviews.
* Once you've addressed the concerns, assign them as a reviewer again to put your pull request back in their queue.
## If you are a core committer asked to give a review
1. Respond promptly to requested reviews.
* Assume the requested review is urgent and blocking unless explicitly stated otherwise.
* Try to interact with the author within 2 business days.
* Configure the GitHub plugin to automate notifications.
* Review your outstanding requested reviews daily to avoid blocking authors.
* Prioritize earlier milestones when reviewing to help with the release process.
* Responding quickly doesn't necessarily mean reviewing quickly! Just don't leave the author hanging.
2. Feel free to clarify expectations with the author.
* If the code is experimental, they may need only a cursory glance and thumbs up to proceed with productizing their changes.
* If the review is large or complex, additional time may be required to complete your review. Be upfront with the author.
* If you are not comfortable reviewing the code, avoid "rubber stamping" the review. Be honest with the author and ask them to consider another core committer.
3. Never rush a review.
* Take the time necessary to review the code thoroughly.
* Don't be afraid to ask for changes repeatedly until all concerns are addressed.
* Feel free to challenge assumptions and timelines. Rushing a change into a patch release may cause more harm than good.
4. Avoid leaving a review hanging.
* Try to accept or reject the review instead of just leaving comments.
5. Merge the pull request.
* Do not merge if there are outstanding changes requested.
* Merge the pull request, and delete the branch if not from a fork.
================================================
FILE: docs/contribution-checklist.md
================================================
# Contribution Checklist
Thanks for your interest in contributing code!
Follow this checklist for submitting a pull request (PR):
1. You've signed the [Contributor License Agreement](http://www.mattermost.org/mattermost-contributor-agreement/), so you can be added to the Mattermost [Approved Contributor List](https://docs.google.com/spreadsheets/d/1NTCeG-iL_VS9bFqtmHSfwETo5f-8MQ7oMDE5IUYJi_Y/pubhtml?gid=0&single=true).
2. Your ticket is a Help Wanted GitHub issue for the project you're contributing to.
- If not, follow the process [here](contributions-without-ticket.md).
3. Your code is thoroughly tested, including appropriate unit tests, and manual testing.
4. If applicable, user interface strings are included in the localization file ([en.json](https://github.com/mattermost/focalboard/blob/main/webapp/i18n/en.json))
- In the webapp folder, run `npm run i18n-extract` to generate the new/updated strings.
5. The PR is submitted against the `main` branch from your fork.
6. The PR title begins with the GitHub Ticket ID (e.g. `[GH-394]`) and the summary template is filled out.
Once submitted, the automated build process must pass in order for the PR to be accepted. Any errors or failures need to be addressed in order for the PR to be accepted. Next, the PR goes through [code review](code-review.md). To learn about the review process for each project, read the [CONTRIBUTING.md](https://github.com/mattermost/focalboard/blob/main/CONTRIBUTING.md) file of that GitHub repository.
================================================
FILE: docs/contributions-without-ticket.md
================================================
# Contributions Without Ticket
Contributions for minor corrections and improvements without a corresponding `Help Wanted` ticket are welcome. For example, a pull request for a bug or incremental improvement, with less than 20 lines of code change, is usually accepted if the change to existing behaviour is minor.
All pull requests submitted without a corresponding ticket will first be reviewed by a core team product manager. Some examples of minor corrections and improvements include:
- [Fix a formatting error in help text](https://github.com/mattermost/mattermost-server/pull/5640)
- [Fix success typo in Makefile](https://github.com/mattermost/mattermost-server/pull/5809)
- [Fix broken Cancel button in Edit Webhooks screen](https://github.com/mattermost/mattermost-server/pull/5612)
- [Fix Android app crashing when saving user notification settings](https://github.com/mattermost/mattermost-mobile/pull/364)
- [Fix recent mentions search not working](https://github.com/mattermost/mattermost-server/pull/5878)
**Note:** For pull requests greater than 20 lines of code, a `Help Wanted` ticket should be opened by the core team. This helps ensure that everything going into the project aligns with a unified vision. Core committers who review the PR are entitled to reject it if there isn't a `Help Wanted` ticket and feel it significantly changes behavior or user expectations.
The best way to discuss opening a `Help Wanted` ticket with the core team is by [starting a conversation in Contributors channel](https://community.mattermost.com/core/channels/focalboard) or [opening an issue in the GitHub repository](https://github.com/mattermost/focalboard/issues/new).
================================================
FILE: docs/core-committers.md
================================================
# Core Committers
A core committer is a maintainer on the Focalboard project who has merge access to the repositories. They are responsible for reviewing pull requests, cultivating the developer community, and guiding the technical vision of Focalboard. If you have a question or need some help, these are the people to ask.
## Core Committers
Below is the list of core committers working on Focalboard:
- **<a name="scott.bishel">Scott Bishel</a>**
- @scott.bishel on [community.mattermost.com](https://community.mattermost.com/core/messages/@scott.bishel) and [@sbishel](https://github.com/sbishel) on GitHub
- **<a name="jesús.espino">Jesús Espino</a>**
- @jesus.espino on [community.mattermost.com](https://community.mattermost.com/core/messages/@jesus.espino) and [@jespino](https://github.com/jespino) on GitHub
- **<a name="doug.lauder">Doug Lauder</a>**
- @doug.lauder on [community.mattermost.com](https://community.mattermost.com/core/messages/@doug.lauder) and [@wiggin77](https://github.com/wiggin77) on GitHub
- **<a name="miguel.delacruz">Miguel de la Cruz</a>**
- @miguel.delacruz on [community.mattermost.com](https://community.mattermost.com/core/messages/@miguel.delacruz) and [@mgdelacroix](https://github.com/mgdelacroix) on GitHub
- **<a name="harshil.sharma">Harshil Sharma</a>**
- @harshil.sharma on [community.mattermost.com](https://community.mattermost.com/core/messages/@harshil.sharma) and [@harshilsharma63](https://github.com/harshilsharma63) on GitHub
- **<a name="chen.lim">Chen Lim</a>**
- @chen-i.lim on [community.mattermost.com](https://community.mattermost.com/core/messages/@chen-i.lim) and [@chenilim](https://github.com/chenilim) on GitHub
================================================
FILE: docs/dev-tips.md
================================================
# Developer Tips and Tricks
These tips and tricks apply to developing the standalone Personal Server of Focalboard. For most features, this is the easiest way to get started working against code that ships across editions.
For working with the Focalboard plugin, refer to the [Focalboard Plugin Developer's Guide](focalboard-dev-guide.md).
## Installation prerequisites
Check that you have recent versions of the basic dependencies installed:
* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* On Windows, install [Git for Windows](https://gitforwindows.org/) and use the git-bash terminal shell
* [Go](https://golang.org/doc/install)
* [Node](https://nodejs.org/en/download/) (v10+) and [npm](https://www.npmjs.com/get-npm)
On Windows:
* Install [Mingw64](https://chocolatey.org/packages/mingw) via [Chocolatey](https://chocolatey.org/)
On macOS, to build the Mac app:
* Install [Xcode](https://apps.apple.com/us/app/xcode/id497799835?mt=12) (v12+)
* Install the Xcode commandline tools, via the IDE or run `xcode-select --install`
On Linux, to build the Linux app:
* `sudo apt-get install libgtk-3-dev`
* `sudo apt-get install libwebkit2gtk-4.0-dev`
* `sudo apt-get install autoconf dh-autoreconf`
## Fork and clone the project source code
Fork the [Focalboard GitHub repo](https://github.com/mattermost/focalboard), and clone it locally.
## Build and run from the terminal
Follow the steps in the [main readme file](https://github.com/mattermost/focalboard#building-the-server). In summary, to build and run the server:
```
make prebuild
make
./bin/focalboard-server
```
Then open a browser to `http://localhost:8000` to access it. The port is configured in `config.json`.
Once the server is running, you can rebuild just the webapp with `make webapp` (in a separate terminal window), then reload the browser.
## VSCode setup
Here's a recommended dev-test loop using VSCode:
* Open a bash terminal window to the project folder
* Run `make prebuild` to npm install
* Do this again when dependencies change in `webapp/package.json`
* Run `cd webapp && npm run watchdev`
* This will auto-build the webapp on file changes
* Open VSCode
* Install the [Go](https://marketplace.visualstudio.com/items?itemName=golang.Go) and [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) VSCode extensions if you haven't already
* Hit F5 and select `Go: Launch Server`
* Or, press `Cmd+P` and type `debug <space>` and pick the option
* Open a browser to `http://localhost:8000`
* The port is configured in `config.json`
You can now edit the webapp code and refresh the browser to see your changes.
## Debugging the web app
You can use your favorite browser to debug the webapp code. With Chrome, open the dev tools with `Cmd+Alt+I` (`Ctrl+Alt+I` in Windows).
* `npm run watchdev` builds the dev package, which includes source maps from js to typescript
* In the Chrome devtools source tab, press `Cmd+P` to jump to a source file
As a starting point, add a breakpoint to the `render()` function in `BoardPage.tsx`, then refresh the browser to walk through page rendering.
## Debugging the server
Debug the Go code in VSCode. This is set up automatically when you launch the server from there.
To start, add a breakpoint to `handleGetBlocks()` in `server/api/api.go`, then refresh the browser to see how data is retrieved.
## Localization/Internationalization/Translation
We use `i18n` to localize the web app. Localized string generally use `intl.formatMessage`. When adding or modifying localized strings, run `npm run i18n-extract` in `webapp` to rebuild `webapp/i18n/en.json`.
Translated strings are stored in other json files under `webapp/i18n`, e.g. `es.json` for Spanish.
## Database
By default, data is stored in a sqlite database `focalboard.db`. You can view and edit this directly using `sqlite3 focalboard.db` from bash.
## Unit tests
Before checking-in commits, run: `make ci`, which is simlar to the ci.yml workflow and includes:
* Server unit tests: `make server-test`
* Webapp eslint: `cd webapp; npm run check`
* Webapp unit tests: `make webapp-test`
* Webapp UI tests: `cd webapp; npm run cypress:ci`
## Running into problems or have questions?
If you run into any issues with the steps here, or have any general questions, please don't hesitate to reach out either on [GitHub](https://github.com/mattermost/focalboard) or our [Mattermost community channel](https://community.mattermost.com/core/channels/focalboard).
We welcome everyone, and appreciate any feedback.
glhf! :)
================================================
FILE: docs/focalboard-dev-guide.md
================================================
# Focalboard Plugin Developer's Guide
**Important**: Effective September 15th, 2023, Mattermost Boards transitions to being fully community supported as the Focalboard Plugin. Mattermost will no longer be maintaining this plugin - this includes bug fixes and feature additions. Instead, the plugin is open-sourced and made available indefinitely for community contributions in GitHub.
To build your own version of it:
1. Build [mattermost-plugin](https://github.com/mattermost/focalboard/tree/main/mattermost-plugin) in the [Focalboard repo](https://github.com/mattermost/focalboard)
2. Upload it as a [custom plugin to your Mattermost server](https://developers.mattermost.com/integrate/admin-guide/admin-plugins-beta/#custom-plugins)
Here are the steps in more detail:
### Building the Focalboard plugin
Fork the [Focalboard repo](https://github.com/mattermost/focalboard), clone it locally, and follow the steps in the readme to set up your dev environment.
Install dependencies:
```
# First-time setup dependencies
cd mattermost-plugin/webapp
npm install --no-optional
cd ../..
make prebuild
```
Build the plugin:
```
# Build webapp
make webapp
# Build plugin
cd mattermost-plugin
make dist
```
Refer to the [dev-release.yml](https://github.com/mattermost/focalboard/blob/main/.github/workflows/dev-release.yml#L168) workflow for the up-to-date commands that are run as part of CI.
### Uploading the plugin to your server
You can manually upload the plugin to your Mattermost Server:
1. Enable [custom plugins](https://developers.mattermost.com/integrate/admin-guide/admin-plugins-beta/#custom-plugins) by setting `PluginSettings > EnableUploads` to `true` in the Mattermost `config.json` file
2. Navigate to **System Console > Plugins > Management** and upload the generated `.tar.gz` package in your `mattermost-plugin/dist` directory
3. Enable it (if needed)
Alternatively, you can install Mattermost locally and use `make deploy` to auto-deploy it for you:
First, build and run Mattermost locally:
1. Follow the [Mattermost Developers Guide](https://developers.mattermost.com/contribute/server/developer-setup/) to set up your environment
* In particuler, make sure Docker is set up and running
2. Fork [mattermost-webapp](https://github.com/mattermost/mattermost-webapp), clone it locally, and `make build`
3. Fork [mattermost-server](https://github.com/mattermost/mattermost-server) and clone it locally
3. Run `make config-reset` to generate the `config/config.json` file
4. Edit `config/config.json`:
* Set `ServiceSettings > SiteURL` to `http://localhost:8065` ([docs](https://docs.mattermost.com/configure/configuration-settings.html#site-url))
* Set `ServiceSettings > EnableLocalMode` to `true` ([docs](https://docs.mattermost.com/configure/configuration-settings.html#enable-local-mode))
* Set `PluginSettings > EnableUploads` to `true` ([docs](https://developers.mattermost.com/integrate/admin-guide/admin-plugins-beta/#custom-plugins))
5. Add an ENV var `MM_SERVICESETTINGS_SITEURL` with the same site URL used in the config
6. Run `make run-server` in Mattermost
Now, to build and deploy the plugin:
1. Clone / fork [mattermost/focalboard](https://github.com/mattermost/focalboard)
2. Install the dependencies (see above)
3. Run:
```
make webapp
cd mattermost-plugin
make deploy
```
================================================
FILE: docs/index.md
================================================
# Focalboard Plugin Documentation
Welcome to the Focalboard plugin project! We're very glad you want to check it out and perhaps contribute code to this project in GitHub.
## Install the plugin
Visit the [Mattermost Developer Documentation](https://developers.mattermost.com/integrate/plugins/using-and-managing-plugins/#custom-plugins) for details on how to install and enable the Focalboard plugin in your self-hosted Mattermost instance.
## Enable the plugin
Once you've installed the Focalboard plugin, you can enable the plugin in the Mattermost System Console by going to **Plugins > Plugin Management**, and selecting the **Enable** option for the Focalboard plugin.
## Contribute to the Focalboard plugin project
Follow these simple steps to contribute:
1. [Fork the Focalboard repo](https://github.com/mattermost/focalboard), clone it locally, and follow the steps in the README to build. Read the [Focalboard Developer's Guide](focalboard-dev-guide.md) and the [developer tips & tricks](dev-tips.md) documentation to get started.
2. Find [help wanted tickets that are up for grabs in GitHub](https://github.com/mattermost/focalboard/issues?q=is%3Aopen+is%3Aissue+label%3A%22Up+for+grabs%22). Comment to let everyone know you’re working on it, and to allow a core contributor to assign the issue to you. If there’s no ticket for what you want to work on see [contributions without a ticket](contributions-without-ticket.md).
3. When your changes are ready, run through our [checklist for pull requests](contribution-checklist.md). Note that if it’s your first contribution, there is a standard [CLA](https://www.mattermost.org/mattermost-contributor-agreement/) to sign.
## Just ask if you need help!
You can find us on our [public Focalboard channel](https://community.mattermost.com/core/channels/focalboard) on the Mattermost community server. Also feel free to [file a bug](https://github.com/mattermost/focalboard/issues/new/choose) for any issues you run into, or [start a discussion](https://github.com/mattermost/focalboard/discussions).
We're glad ❤️ you're here! Good luck and have fun!
================================================
FILE: experiments/webext/.gitignore
================================================
.parcel-cache
web-ext-artifacts
================================================
FILE: experiments/webext/.parcelrc
================================================
{
"extends": "@parcel/config-webextension"
}
================================================
FILE: experiments/webext/README.md
================================================
# Focalboard Web Clipper Browser Extension ✂️
This is the Focalboard Web Clipper browser extension. It aims at supporting various use cases around converting web content from your browser directly into Focalboard cards.
⚠️ **Warning:** The extension is currently in an early and experimental state. Use it at your own risk only. Don't expect any eye candy.
## Status
The extension currently is in a proof-of-concept state with minimal functionality. The only supported use case at the time is building a read-later list. Things that work:
- Logging in to the Focalboard server from the extension settings
- Selecting a board to capture cards into from the extension settings
- Saving websites (title & URL) into cards from a page action (like e.g. Pocket does it)
Only Firefox was tested so far but polyfills have already been enabled so there's a good chance that it'll work in Chrome and maybe even Safari, too.
### Next Steps
We're really at the very beginning here so there's a lot to be done. Notable tasks include:
- Improve the React code by extracting components
- Style the options and popup pages to mimic the look and feel of Focalboard
- Replace the logo with something better (the current one was snatched from the Focalboard Windows app)
- Link to the extension's options page from page action error messages
- Clip parts of a website into image attachments on cards
- Extract website content in reader mode into card descriptions
- Optimise the logic for finding the first URL property (currently the whole board subtree has to be requested because there is no other API available)
- Add some tests
- Test the extension on Chrome / Safari and add infrastructure to facilitate this in future (e.g. `.web-ext-config.js`)
- Add an onboarding (displayed after first install) and upboarding (displayed after update) page
- Distribute the extension via the various browser add-on stores (ok, maybe too early 😜)
## Hacking
First, install dependencies with
```
$ npm i
```
You can then compile and bundle the code with
```
$ npm run watchdev
```
This will write output into `dist/dev/` and automatically recompile and bundle on any source change.
To run the extension in a separate Firefox instance, use
```
$ npm run servedev
```
Note that in the above commands you can substitue `dev` with `prod` to build and run the extension with production settings.
## Distribution
To build a distributable ZIP archive, run
```
$ npm run build
```
The archive will be placed into the `web-ext-artifacts` folder.
================================================
FILE: experiments/webext/manifest.json
================================================
{
"manifest_version": 2,
"name": "Focalboard Web Clipper",
"version": "0.1.0",
"description": "Save websites directly into Focalboard",
"icons": {
"48": "icons/48.png",
"96": "icons/96.png"
},
"page_action": {
"browser_style": true,
"default_icon": {
"19": "icons/19.png",
"38": "icons/38.png"
},
"default_title": "Save to Focalboard",
"default_popup": "src/views/popup.html",
"show_matches": ["<all_urls>"]
},
"options_ui": {
"page": "src/views/options.html",
"browser_style": true
},
"web_accessible_resources": [],
"permissions": [
"<all_urls>",
"storage"
],
"browser_specific_settings": {
"gecko": {
"id": "focalboard-web-clipper@mattermost.com"
}
}
}
================================================
FILE: experiments/webext/package.json
================================================
{
"name": "focalboard-web-clipper",
"version": "0.0.0",
"targets": {
"dev": {
"sourceMap": {
"inline": true,
"inlineSources": true
}
},
"prod": {}
},
"scripts": {
"watchdev": "parcel watch manifest.json --target dev",
"servedev": "web-ext run -s dist/dev/",
"watchprod": "parcel watch manifest.json --target prod",
"serveprod": "web-ext run -s dist/prod/",
"build": "parcel build manifest.json --target prod && web-ext build -s dist/prod/"
},
"devDependencies": {
"@parcel/config-webextension": "^2.0.0",
"@parcel/transformer-sass": "^2.0.0",
"@types/react": "^17.0.32",
"@types/react-dom": "^17.0.10",
"parcel": "^2.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"typescript": "^4.4.4",
"web-ext": "^6.4.0",
"webextension-polyfill-ts": "^0.26.0"
}
}
================================================
FILE: experiments/webext/src/utils/Board.ts
================================================
interface BoardFields {
isTemplate: boolean
}
export default interface Board {
id: string
title: string
fields: BoardFields
}
================================================
FILE: experiments/webext/src/utils/networking.ts
================================================
// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Board from "../utils/Board"
declare global {
interface Window {
msCrypto: Crypto
}
}
async function request(method: string, host: string, resource: string, body: any, token: string | null) {
const response = await fetch(`${host}/api/v2/${resource}`, {
'credentials': 'include',
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'Authorization': token ? `Bearer ${token}` : null
} as HeadersInit,
'body': body ? JSON.stringify(body) : null,
'method': method
})
const json = await response.json()
if (json.error) {
throw json.error
}
return json
}
export async function logIn(host: string, username: string, password: string) {
const json = await request('POST', host, 'login', { username: username, password: password, type: 'normal' }, null)
return json.token
}
export async function getBoards(host: string, token: string) {
const json = await request('GET', host, 'workspaces/0/blocks?type=board', null, token) as Board[]
return json.filter(board => !board.isTemplate)
}
export async function findUrlPropertyId(host: string, token: string, boardId: string) {
const json = await request('GET', host, `workspaces/0/blocks/${boardId}/subtree`, null, token)
for (let obj of json) {
if (obj.type === 'board') {
for (let property of obj.fields.cardProperties) {
if (property.type === 'url') {
return property.id
}
}
break // Only one board in subtree, no need to continue
}
}
return null
}
export async function createCard(host: string, token: string, boardId: string, urlPropertyId: string, title: string, url: string) {
let properties = {} as any
if (urlPropertyId) {
properties[urlPropertyId] = url
}
const card = {
id: createGuid(),
schema: 1,
workspaceId: '',
parentId: boardId,
rootId: boardId,
createdBy: '',
modifiedBy: '',
type: 'card',
fields: {
icon: null,
properties: properties,
contentOrder: [],
isTemplate: false
},
title: title,
createAt: Date.now(),
updateAt: Date.now(),
deleteAt: 0
}
await request('POST', host, 'workspaces/0/blocks', [card], token)
}
function createGuid(): string {
const data = randomArray(16)
return '7' + base32encode(data, false)
}
function randomArray(size: number): Uint8Array {
const crypto = window.crypto || window.msCrypto
const rands = new Uint8Array(size)
if (crypto && crypto.getRandomValues) {
crypto.getRandomValues(rands)
} else {
for (let i = 0; i < size; i++) {
rands[i] = Math.floor((Math.random() * 255))
}
}
return rands
}
const base32Alphabet = 'ybndrfg8ejkmcpqxot1uwisza345h769'
function base32encode(data: Int8Array | Uint8Array | Uint8ClampedArray, pad: boolean): string {
const dview = new DataView(data.buffer, data.byteOffset, data.byteLength)
let bits = 0
let value = 0
let output = ''
// adapted from https://github.com/LinusU/base32-encode
for (let i = 0; i < dview.byteLength; i++) {
value = (value << 8) | dview.getUint8(i)
bits += 8
while (bits >= 5) {
output += base32Alphabet[(value >>> (bits - 5)) & 31]
bits -= 5
}
}
if (bits > 0) {
output += base32Alphabet[(value << (5 - bits)) & 31]
}
if (pad) {
while ((output.length % 8) !== 0) {
output += '='
}
}
return output
}
================================================
FILE: experiments/webext/src/utils/settings.ts
================================================
// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import browser from 'webextension-polyfill'
interface Settings {
host: string | null
username: string | null
token: string | null
boardId: string | null
}
export function loadSettings(): Settings {
return browser.storage.sync.get(['host', 'username', 'token', 'boardId'])
}
export function storeSettings(host: string, username: string, token: string | null, boardId: string | null) {
console.log(`storing host ${host}`)
return browser.storage.sync.set({ host: host, username: username, token: token, boardId: boardId })
}
export function storeToken(value: string | null) {
return browser.storage.sync.set({ token: value })
}
export function storeBoardId(value: string | null) {
return browser.storage.sync.set({ boardId: value })
}
================================================
FILE: experiments/webext/src/views/OptionsApp.scss
================================================
/* Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved. */
/* See LICENSE.txt for license information. */
.OptionsApp {
label {
display: block;
font-size: 90%;
font-style: italic;
}
input[type=text], input[type=password], select {
width: 20em;
max-width: 100%;
margin-bottom: 1em;
}
input[type=submit] {
display: block;
}
.status {
margin: 1em 0 1em 0;
.in-progress {
background-color: grey;
padding: 0.5em;
}
.success {
background-color: lightgreen;
padding: 0.5em;
}
.error {
background-color: lightpink;
padding: 0.5em;
}
}
}
================================================
FILE: experiments/webext/src/views/OptionsApp.tsx
================================================
// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, { ChangeEvent, MouseEvent, useEffect, useState } from "react"
import Board from "../utils/Board"
import { getBoards, logIn } from "../utils/networking";
import { loadSettings, storeSettings, storeToken, storeBoardId } from "../utils/settings";
import "./OptionsApp.scss"
export default function OptionsApp() {
const [host, setHost] = useState('')
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [token, setToken] = useState('')
const [boards, setBoards] = useState([] as Board[])
const [boardId, setBoardId] = useState(null as string | null)
const [inProgress, setInProgress] = useState(false)
const [error, setError] = useState(null as string | null)
useEffect(() => {
async function initialiseBoards() {
const settings = await loadSettings()
if (settings.host) {
setHost(settings.host)
}
if (settings.username) {
setUsername(settings.username)
}
if (settings.token) {
setToken(settings.token)
}
if (settings.boardId) {
setBoardId(settings.boardId)
}
if (!settings.host || !settings.username || !settings.token) {
setError('Unauthenticated')
return
}
setInProgress(true)
try {
setBoards(await getBoards(settings.host, settings.token))
} catch (error) {
setError(`${error}`)
} finally {
setInProgress(false)
}
}
initialiseBoards();
}, [])
function onAuthenticateButtonClicked(event: MouseEvent) {
authenticate(host, username, password)
event.preventDefault()
event.stopPropagation()
}
async function authenticate(host: string, username: string, password: string) {
storeSettings(host, username, null, null)
setBoards([])
setBoardId(null)
setInProgress(true)
setError(null)
try {
const token = await logIn(host, username, password)
storeToken(token)
setToken(token)
setBoards(await getBoards(host, token))
const select = document.querySelector('select') as any
select.value = null
} catch (error) {
setError(`${error}`)
} finally {
setInProgress(false)
}
}
function onBoardSelectionChanged(event: ChangeEvent) {
const id = (event.target as HTMLSelectElement).value
storeBoardId(id)
setBoardId(id)
event.preventDefault()
event.stopPropagation()
}
return <div className="OptionsApp">
<label>Focalboard host</label>
<input type="text" value={host} onChange={e => setHost(e.target.value)}/>
<label>Username</label>
<input type="text" value={username} onChange={e => setUsername(e.target.value)}/>
<label>Password</label>
<input type="password" value={password} onChange={e => setPassword(e.target.value)}/>
<input type="submit" value="Authenticate" onClick={onAuthenticateButtonClicked}/>
<div className="status">
{inProgress && <div className="in-progress">
Connecting to Focalboard server...
</div>}
{!inProgress && !error && <div className="success">
Token: <span>{token}</span>
</div>}
{!inProgress && error && <div className="error">{error}</div>}
</div>
<br/>
<br/>
<label>Board</label>
<select onChange={onBoardSelectionChanged}>
{boards.map(board => <option value={board.id} selected={board.id === boardId}>{board.title}</option>)}
</select>
</div>
}
================================================
FILE: experiments/webext/src/views/PopupApp.scss
================================================
/* Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved. */
/* See LICENSE.txt for license information. */
.PopupApp {
.status {
.in-progress {
background-color: grey;
padding: 1em;
}
.success {
background-color: lightgreen;
padding: 1em;
}
.error {
background-color: lightpink;
padding: 1em;
}
}
}
================================================
FILE: experiments/webext/src/views/PopupApp.tsx
================================================
// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, { useEffect, useState } from "react"
import browser from 'webextension-polyfill'
import { createCard, findUrlPropertyId } from "../utils/networking";
import { loadSettings } from "../utils/settings";
import "./PopupApp.scss"
export default function OptionsApp() {
const [board, setBoard] = useState('')
const [inProgress, setInProgress] = useState(false)
const [error, setError] = useState(null as string | null)
useEffect(() => {
async function createCardFromCurrentTab() {
const settings = await loadSettings()
if (!settings.host || !settings.token) {
setError('Looks like you\'re unauthenticated. Please configure the extension\'s settings first.')
return
}
if (!settings.boardId) {
setError('Looks like you haven\'t selected a board to save to yet. Please configure the extension\'s settings first.')
return
}
setInProgress(true)
try {
const tabs = await browser.tabs.query({ active: true, currentWindow: true })
const urlPropertyId = await findUrlPropertyId(settings.host as string, settings.token as string, settings.boardId as string)
await createCard(settings.host as string, settings.token as string, settings.boardId as string, urlPropertyId, tabs[0].title, tabs[0].url)
setBoard(`${settings.host}/${settings.boardId}`)
} catch (error) {
setError(`${error}`)
} finally {
setInProgress(false)
}
}
createCardFromCurrentTab();
}, [])
return <div className="PopupApp">
<div className="status">
{inProgress && <div className="in-progress">
Saving to Focalboard...
</div>}
{!inProgress && !error && <div className="success">
Saved to <a href={board} target="_blank">board</a>
</div>}
{!inProgress && error && <div className="error">{error}</div>}
</div>
</div>
}
================================================
FILE: experiments/webext/src/views/options.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<div id="app"></div>
<script type="module" src="options.tsx"></script>
</body>
</html>
================================================
FILE: experiments/webext/src/views/options.tsx
================================================
// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from "react"
import ReactDOM from "react-dom"
import OptionsApp from "./OptionsApp"
const app = document.getElementById("app")
ReactDOM.render(<OptionsApp/>, app)
================================================
FILE: experiments/webext/src/views/popup.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<div id="app"></div>
<script type="module" src="popup.tsx"></script>
</body>
</html>
================================================
FILE: experiments/webext/src/views/popup.tsx
================================================
// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from "react"
import ReactDOM from "react-dom"
import PopupApp from "./PopupApp"
const app = document.getElementById("app")
ReactDOM.render(<PopupApp/>, app)
================================================
FILE: experiments/webext/tsconfig.json
================================================
{
"compilerOptions": {
"jsx": "react",
"target": "es2019",
"module": "commonjs",
"esModuleInterop": true,
"noImplicitAny": true,
"strict": true,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"allowJs": true,
"resolveJsonModule": true,
"incremental": false,
"outDir": "./dist",
"moduleResolution": "node"
},
"include": [
"."
],
"exclude": [
".git",
"**/node_modules/*",
"dist",
"pack"
]
}
================================================
FILE: import/README.md
================================================
# Import scripts
This subfolder contains scripts to import data from other systems. It is at an early stage. At present, there are examples of basic importing from the following:
* Trello
* Asana
* Notion
* Jira
* Todoist
* Nextcloud Deck
[Contribute code](https://mattermost.github.io/focalboard/) to expand this.
================================================
FILE: import/asana/.eslintrc.json
================================================
{
"extends": [
],
"plugins": [
],
"parser": "@typescript-eslint/parser",
"env": {
"jest": true
},
"settings": {
"import/resolver": "webpack",
"react": {
"pragma": "React",
"version": "detect"
}
},
"rules": {
"no-unused-expressions": 0,
"eol-last": ["error", "always"],
"import/no-unresolved": 2,
"no-undefined": 0,
"react/jsx-filename-extension": 0,
"max-nested-callbacks": ["error", {"max": 5}]
},
"overrides": [
{
"files": ["**/*.tsx", "**/*.ts"],
"extends": [
"plugin:@typescript-eslint/recommended"
],
"rules": {
"import/no-unresolved": 0, // ts handles this better
"camelcase": 0,
"semi": "off",
"@typescript-eslint/naming-convention": [
2,
{
"selector": "function",
"format": ["camelCase", "PascalCase"]
},
{
"selector": "variable",
"format": ["camelCase", "PascalCase", "UPPER_CASE"]
},
{
"selector": "parameter",
"format": ["camelCase", "PascalCase"],
"leadingUnderscore": "allow"
},
{
"selector": "typeLike",
"format": ["PascalCase"]
}
],
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-unused-vars": [
2,
{
"vars": "all",
"args": "after-used"
}
],
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/prefer-interface": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/semi": [2, "never"],
"@typescript-eslint/indent": [
2,
4,
{
"SwitchCase": 0
}
],
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": [
2,
{
"classes": false,
"functions": false,
"variables": false
}
],
"no-useless-constructor": 0,
"@typescript-eslint/no-useless-constructor": 2,
"react/jsx-filename-extension": 0
}
},
{
"files": ["tests/**", "**/*.test.*"],
"env": {
"jest": true
},
"rules": {
"func-names": 0,
"global-require": 0,
"new-cap": 0,
"prefer-arrow-callback": 0,
"no-import-assign": 0
}
}
]
}
================================================
FILE: import/asana/.gitignore
================================================
test
================================================
FILE: import/asana/README.md
================================================
# Asana importer
This node app converts an Asana json archive into a Focalboard archive. To use:
1. From the Asana Board Menu (dropdown next to board title), select `Export / Print`, and `JSON`
2. Save it locally, e.g. to `asana.json`
3. Run `npm install` from within `focalboard/webapp`
4. Run `npm install` from within `focalboard/import/asana`
5. Run `npx ts-node importAsana.ts -i <asana.json> -o archive.boardarchive`
6. In Focalboard, click `Settings`, then `Import archive` and select `archive.boardarchive`
## Import scope
Currently, the script imports all cards from a single board, including their section (column) membership, names, and notes. [Contribute code](https://mattermost.github.io/focalboard/) to expand this.
================================================
FILE: import/asana/asana.ts
================================================
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// Generated by https://quicktype.io
//
// To change quicktype's target language, run command:
//
// "Set quicktype target language"
export interface Asana {
data: Datum[];
}
export interface Datum {
gid: string;
assignee: null;
assignee_status: AssigneeStatus;
completed: boolean;
completed_at: null;
created_at: string;
custom_fields: CustomField[];
due_at: null;
due_on: null;
followers: Workspace[];
hearted: boolean;
hearts: any[];
liked: boolean;
likes: any[];
memberships: Membership[];
modified_at: string;
name: string;
notes: string;
num_hearts: number;
num_likes: number;
parent: Workspace | null;
permalink_url: string;
projects: Workspace[];
resource_type: WorkspaceResourceType;
start_on: null;
subtasks: Datum[];
tags: any[];
resource_subtype: ResourceSubtype;
workspace: Workspace;
}
export enum AssigneeStatus {
Upcoming = "upcoming",
}
export interface CustomField {
gid: string;
enabled: boolean;
enum_options: Enum[];
enum_value: Enum | null;
name: CustomFieldName;
created_by: null;
resource_subtype: Type;
resource_type: CustomFieldResourceType;
type: Type;
}
export interface Enum {
gid: string;
color: Color;
enabled: boolean;
name: EnumOptionName;
resource_type: EnumOptionResourceType;
}
export enum Color {
Blue = "blue",
BlueGreen = "blue-green",
CoolGray = "cool-gray",
Orange = "orange",
Red = "red",
Yellow = "yellow",
YellowOrange = "yellow-orange",
}
export enum EnumOptionName {
Deferred = "Deferred",
Done = "Done",
High = "High",
InProgress = "In Progress",
Low = "Low",
Medium = "Medium",
NotStarted = "Not Started",
Waiting = "Waiting",
}
export enum EnumOptionResourceType {
EnumOption = "enum_option",
}
export enum CustomFieldName {
Priority = "Priority",
TaskProgress = "Task Progress",
}
export enum Type {
Enum = "enum",
}
export enum CustomFieldResourceType {
CustomField = "custom_field",
}
export interface Workspace {
gid: string;
name: string;
resource_type: WorkspaceResourceType;
}
export enum WorkspaceResourceType {
Project = "project",
Section = "section",
Task = "task",
User = "user",
Workspace = "workspace",
}
export interface Membership {
project: Workspace;
section: Workspace;
}
export enum ResourceSubtype {
DefaultTask = "default_task",
}
================================================
FILE: import/asana/importAsana.ts
================================================
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as fs from 'fs'
import minimist from 'minimist'
import {exit} from 'process'
import {ArchiveUtils} from '../util/archive'
import {Block} from '../../webapp/src/blocks/block'
import {Board} from '../../webapp/src/blocks/board'
import {IPropertyOption, IPropertyTemplate, createBoard} from '../../webapp/src/blocks/board'
import {createBoardView} from '../../webapp/src/blocks/boardView'
import {createCard} from '../../webapp/src/blocks/card'
import {createTextBlock} from '../../webapp/src/blocks/textBlock'
import {Asana, Workspace} from './asana'
import {Utils} from './utils'
// HACKHACK: To allow Utils.CreateGuid to work
(global.window as any) = {}
const optionColors = [
// 'propColorDefault',
'propColorGray',
'propColorBrown',
'propColorOrange',
'propColorYellow',
'propColorGreen',
'propColorBlue',
'propColorPurple',
'propColorPink',
'propColorRed',
]
let optionColorIndex = 0
function main() {
const args: minimist.ParsedArgs = minimist(process.argv.slice(2))
const inputFile = args['i']
const outputFile = args['o'] || 'archive.boardarchive'
if (!inputFile) {
showHelp()
}
if (!fs.existsSync(inputFile)) {
console.error(`File not found: ${inputFile}`)
exit(2)
}
// Read input
const inputData = fs.readFileSync(inputFile, 'utf-8')
const input = JSON.parse(inputData) as Asana
// Convert
const [boards, blocks] = convert(input)
// Save output
// TODO: Stream output
const outputData = ArchiveUtils.buildBlockArchive(boards, blocks)
fs.writeFileSync(outputFile, outputData)
console.log(`Exported to ${outputFile}`)
}
function getProjects(input: Asana): Workspace[] {
const projectMap = new Map<string, Workspace>()
input.data.forEach(datum => {
datum.projects.forEach(project => {
if (!projectMap.get(project.gid)) {
projectMap.set(project.gid, project)
}
})
})
return [...projectMap.values()]
}
function getSections(input: Asana, projectId: string): Workspace[] {
const sectionMap = new Map<string, Workspace>()
input.data.forEach(datum => {
const membership = datum.memberships.find(o => o.project.gid === projectId)
if (membership) {
if (!sectionMap.get(membership.section.gid)) {
sectionMap.set(membership.section.gid, membership.section)
}
}
})
return [...sectionMap.values()]
}
function convert(input: Asana): [Board[], Block[]] {
const projects = getProjects(input)
if (projects.length < 1) {
console.error('No projects found')
return [[],[]]
}
// TODO: Handle multiple projects
const project = projects[0]
const boards: Board[] = []
const blocks: Block[] = []
// Board
const board = createBoard()
console.log(`Board: ${project.name}`)
board.title = project.name
// Convert sections (columns) to a Select property
const optionIdMap = new Map<string, string>()
const options: IPropertyOption[] = []
const sections = getSections(input, project.gid)
sections.forEach(section => {
const optionId = Utils.createGuid()
optionIdMap.set(section.gid, optionId)
const color = optionColors[optionColorIndex % optionColors.length]
optionColorIndex += 1
const option: IPropertyOption = {
id: optionId,
value: section.name,
color,
}
options.push(option)
})
const cardProperty: IPropertyTemplate = {
id: Utils.createGuid(),
name: 'Section',
type: 'select',
options
}
board.cardProperties = [cardProperty]
boards.push(board)
// Board view
const view = createBoardView()
view.title = 'Board View'
view.fields.viewType = 'board'
view.parentId = board.id
view.boardId = board.id
blocks.push(view)
// Cards
input.data.forEach(card => {
console.log(`Card: ${card.name}`)
const outCard = createCard()
outCard.title = card.name
outCard.boardId = board.id
outCard.parentId = board.id
// Map lists to Select property options
const membership = card.memberships.find(o => o.project.gid === project.gid)
if (membership) {
const optionId = optionIdMap.get(membership.section.gid)
if (optionId) {
outCard.fields.properties[cardProperty.id] = optionId
} else {
console.warn(`Invalid idList: ${membership.section.gid} for card: ${card.name}`)
}
} else {
console.warn(`Missing idList for card: ${card.name}`)
}
blocks.push(outCard)
if (card.notes) {
// console.log(`\t${card.notes}`)
const text = createTextBlock()
text.title = card.notes
text.parentId = outCard.id
text.boardId = board.id
blocks.push(text)
outCard.fields.contentOrder = [text.id]
}
})
console.log('')
console.log(`Found ${input.data.length} card(s).`)
return [boards, blocks]
}
function showHelp() {
console.log('import -i <input.json> -o [output.boardarchive]')
exit(1)
}
main()
================================================
FILE: import/asana/package.json
================================================
{
"name": "focalboard-asana-importer",
"version": "1.0.0",
"private": true,
"description": "",
"main": "importAsana.js",
"scripts": {
"lint": "eslint --ext .tsx,.ts . --quiet --cache",
"fix": "eslint --ext .tsx,.ts . --quiet --fix --cache",
"test": "ts-node importAsana.ts -i test/asana.json -o test/asana-import.focalboard",
"debug:test": "node --inspect=5858 -r ts-node/register importAsana.ts -i test/asana.json -o test/asana-import.focalboard"
},
"keywords": [],
"author": "",
"devDependencies": {
"@types/minimist": "^1.2.1",
"@types/node": "^14.14.28",
"@typescript-eslint/eslint-plugin": "^4.15.0",
"@typescript-eslint/parser": "^4.15.0",
"eslint": "^7.20.0",
"ts-node": "^9.1.1",
"typescript": "^4.1.5"
},
"dependencies": {
"minimist": "^1.2.6"
}
}
================================================
FILE: import/asana/tsconfig.json
================================================
{
"compilerOptions": {
"jsx": "react",
"target": "es2019",
"module": "commonjs",
"esModuleInterop": true,
"noImplicitAny": true,
"strict": true,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"allowJs": true,
"resolveJsonModule": true,
"incremental": false,
"outDir": "./dist",
"moduleResolution": "node"
},
"include": [
"."
],
"exclude": [
".git",
"**/node_modules/*",
"dist",
"pack"
]
}
================================================
FILE: import/asana/utils.ts
================================================
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as crypto from 'crypto'
class Utils {
static createGuid(): string {
function randomDigit() {
if (crypto && crypto.randomBytes) {
const rands = crypto.randomBytes(1)
return (rands[0] % 16).toString(16)
}
return (Math.floor((Math.random() * 16))).toString(16)
}
return 'xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx'.replace(/x/g, randomDigit)
}
}
export { Utils }
================================================
FILE: import/jira/.gitignore
================================================
test
================================================
FILE: import/jira/README.md
================================================
# Jira importer
This node app converts a Jira xml export into a Focalboard archive. To use:
1. Open Jira advanced search, and search for all the items to export
2. Select `Export`, then `Export XML`
3. Save it locally, e.g. to `jira_export.xml`
4. Run `npm install` from within `focalboard/webapp`
5. Run `npm install` from within `focalboard/import/jira`
6. Run `npx ts-node importJira.ts -i <path-to-jira.xml> -o archive.boardarchive` (also from within `focalboard/import/jira`)
7. In Focalboard, click `Settings`, then `Import archive` and select `archive.boardarchive`
## Import scope and known limitations
Currently, the script imports each item as a card into a single board. Note that Jira XML export is limite
gitextract_a_j2svim/
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── doc_improvement.md
│ │ └── enhancement.md
│ ├── codeql/
│ │ └── codeql-config.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── codeql-analysis.yml
│ ├── dev-release.yml
│ ├── lint-server.yml
│ ├── prod-release.yml
│ └── scorecards-analysis.yml
├── .gitignore
├── .gitlab-ci.yml
├── .gitpod.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile.build
├── LICENSE.txt
├── Makefile
├── NOTICE.txt
├── README.md
├── SECURITY.md
├── app-config.json
├── config.json
├── docker/
│ ├── Dockerfile
│ ├── README.md
│ ├── config.json
│ ├── docker-compose-db-nginx.yml
│ ├── docker-compose.yml
│ └── server_config.json
├── docker-testing/
│ ├── docker-compose-mariadb.yml
│ ├── docker-compose-mysql.yml
│ └── docker-compose-postgres.yml
├── docs/
│ ├── README.md
│ ├── _config.yml
│ ├── code-review.md
│ ├── contribution-checklist.md
│ ├── contributions-without-ticket.md
│ ├── core-committers.md
│ ├── dev-tips.md
│ ├── focalboard-dev-guide.md
│ └── index.md
├── experiments/
│ └── webext/
│ ├── .gitignore
│ ├── .parcelrc
│ ├── README.md
│ ├── manifest.json
│ ├── package.json
│ ├── src/
│ │ ├── utils/
│ │ │ ├── Board.ts
│ │ │ ├── networking.ts
│ │ │ └── settings.ts
│ │ └── views/
│ │ ├── OptionsApp.scss
│ │ ├── OptionsApp.tsx
│ │ ├── PopupApp.scss
│ │ ├── PopupApp.tsx
│ │ ├── options.html
│ │ ├── options.tsx
│ │ ├── popup.html
│ │ └── popup.tsx
│ └── tsconfig.json
├── import/
│ ├── README.md
│ ├── asana/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── asana.ts
│ │ ├── importAsana.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── jira/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importJira.ts
│ │ ├── jiraImporter.test.ts
│ │ ├── jiraImporter.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── nextcloud-deck/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── deck.ts
│ │ ├── importDeck.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── notion/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importNotion.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── todoist/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importTodoist.ts
│ │ ├── package.json
│ │ ├── todoist.ts
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ ├── trello/
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── importTrello.ts
│ │ ├── package.json
│ │ ├── trello.ts
│ │ ├── tsconfig.json
│ │ └── utils.ts
│ └── util/
│ └── archive.ts
├── linux/
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── mac/
│ ├── Focalboard/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AccentColor.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── AutoSaveWindowController.swift
│ │ ├── Base.lproj/
│ │ │ └── Main.storyboard
│ │ ├── CustomWKWebView.swift
│ │ ├── DownloadHandler.swift
│ │ ├── Focalboard.entitlements
│ │ ├── Globals.swift
│ │ ├── Info.plist
│ │ ├── Inherit.entitlements
│ │ ├── PortUtils.swift
│ │ ├── ViewController.swift
│ │ ├── WhatsNewViewController.swift
│ │ └── whatsnew.txt
│ ├── Focalboard.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Focalboard.xcscheme
│ ├── Focalboard.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ ├── FocalboardTests/
│ │ ├── FocalboardTests.swift
│ │ └── Info.plist
│ ├── FocalboardUITests/
│ │ ├── FocalboardUITests.swift
│ │ └── Info.plist
│ ├── README.md
│ └── export.plist
├── modd-servertest.conf
├── modd.conf
├── noticegen/
│ ├── Readme.md
│ └── config.yaml
├── pull_request_template.md
├── responsible_disclosure_policy.md
├── server/
│ ├── .golangci.yml
│ ├── admin-scripts/
│ │ └── reset-password.sh
│ ├── api/
│ │ ├── admin.go
│ │ ├── api.go
│ │ ├── api_test.go
│ │ ├── archive.go
│ │ ├── audit.go
│ │ ├── auth.go
│ │ ├── blocks.go
│ │ ├── boards.go
│ │ ├── boards_and_blocks.go
│ │ ├── cards.go
│ │ ├── categories.go
│ │ ├── channels.go
│ │ ├── compliance.go
│ │ ├── config.go
│ │ ├── content_blocks.go
│ │ ├── context.go
│ │ ├── files.go
│ │ ├── members.go
│ │ ├── onboarding.go
│ │ ├── search.go
│ │ ├── sharing.go
│ │ ├── statistics.go
│ │ ├── subscriptions.go
│ │ ├── system.go
│ │ ├── system_test.go
│ │ ├── teams.go
│ │ ├── templates.go
│ │ └── users.go
│ ├── app/
│ │ ├── app.go
│ │ ├── app_test.go
│ │ ├── auth.go
│ │ ├── auth_test.go
│ │ ├── blocks.go
│ │ ├── blocks_test.go
│ │ ├── boards.go
│ │ ├── boards_and_blocks.go
│ │ ├── boards_test.go
│ │ ├── cards.go
│ │ ├── cards_test.go
│ │ ├── category.go
│ │ ├── category_boards.go
│ │ ├── category_boards_test.go
│ │ ├── category_test.go
│ │ ├── clientConfig.go
│ │ ├── clientConfig_test.go
│ │ ├── compliance.go
│ │ ├── content_blocks.go
│ │ ├── content_blocks_test.go
│ │ ├── export.go
│ │ ├── files.go
│ │ ├── files_test.go
│ │ ├── helper_test.go
│ │ ├── import.go
│ │ ├── import_test.go
│ │ ├── initialize.go
│ │ ├── onboarding.go
│ │ ├── onboarding_test.go
│ │ ├── permissions.go
│ │ ├── server_metadata.go
│ │ ├── server_metadata_test.go
│ │ ├── sharing.go
│ │ ├── sharing_test.go
│ │ ├── statistics.go
│ │ ├── subscriptions.go
│ │ ├── teams.go
│ │ ├── teams_test.go
│ │ ├── templates.go
│ │ ├── templates_test.go
│ │ ├── user.go
│ │ └── user_test.go
│ ├── assets/
│ │ ├── assets.go
│ │ ├── build-template-archive/
│ │ │ └── main.go
│ │ └── templates-boardarchive/
│ │ ├── b7wnw9awd4pnefryhq51apbzb4c/
│ │ │ └── board.jsonl
│ │ ├── bbkpwdj8x17bdpdqd176n8ctoua/
│ │ │ └── board.jsonl
│ │ ├── bbn1888mprfrm5fjw9f1je9x3xo/
│ │ │ └── board.jsonl
│ │ ├── bc41mwxg9ybb69pn9j5zna6d36c/
│ │ │ └── board.jsonl
│ │ ├── bcm39o11e4ib8tye8mt6iyuec9o/
│ │ │ └── board.jsonl
│ │ ├── bd65qbzuqupfztpg31dgwgwm5ga/
│ │ │ └── board.jsonl
│ │ ├── bgi1yqiis8t8xdqxgnet8ebutky/
│ │ │ └── board.jsonl
│ │ ├── bh4pkixqsjift58e1qy6htrgeay/
│ │ │ └── board.jsonl
│ │ ├── bkqk6hpfx7pbsucue7jan5n1o1o/
│ │ │ └── board.jsonl
│ │ ├── brs9cdimfw7fodyi7erqt747rhc/
│ │ │ └── board.jsonl
│ │ ├── bsjd59qtpbf888mqez3ge77domw/
│ │ │ └── board.jsonl
│ │ ├── bui5izho7dtn77xg3thkiqprc9r/
│ │ │ └── board.jsonl
│ │ ├── buixxjic3xjfkieees4iafdrznc/
│ │ │ └── board.jsonl
│ │ └── version.json
│ ├── auth/
│ │ ├── auth.go
│ │ ├── auth_test.go
│ │ └── mocks/
│ │ └── mockauth_interface.go
│ ├── client/
│ │ └── client.go
│ ├── go.mod
│ ├── go.sum
│ ├── go.tools.mod
│ ├── go.tools.sum
│ ├── integrationtests/
│ │ ├── blocks_test.go
│ │ ├── board_test.go
│ │ ├── boards_and_blocks_test.go
│ │ ├── cards_test.go
│ │ ├── clienttestlib.go
│ │ ├── compliance_test.go
│ │ ├── content_blocks_test.go
│ │ ├── export_test.go
│ │ ├── file_test.go
│ │ ├── permissions_test.go
│ │ ├── pluginteststore.go
│ │ ├── sharing_test.go
│ │ ├── sidebar_test.go
│ │ ├── subscriptions_test.go
│ │ ├── teststore.go
│ │ ├── user_test.go
│ │ └── work_template_test.go
│ ├── main/
│ │ ├── doc.go
│ │ └── main.go
│ ├── model/
│ │ ├── auth.go
│ │ ├── block.go
│ │ ├── block_test.go
│ │ ├── blockid.go
│ │ ├── blocktype.go
│ │ ├── board.go
│ │ ├── board_statistics.go
│ │ ├── boards_and_blocks.go
│ │ ├── boards_and_blocks_test.go
│ │ ├── card.go
│ │ ├── card_test.go
│ │ ├── category.go
│ │ ├── category_boards.go
│ │ ├── clientConfig.go
│ │ ├── cloud.go
│ │ ├── compliance.go
│ │ ├── database.go
│ │ ├── error.go
│ │ ├── errorResponse.go
│ │ ├── file.go
│ │ ├── import_export.go
│ │ ├── log_level.go
│ │ ├── mocks/
│ │ │ ├── mockservicesapi.go
│ │ │ └── propValueResolverMock.go
│ │ ├── notification.go
│ │ ├── permission.go
│ │ ├── properties.go
│ │ ├── properties_test.go
│ │ ├── services_api.go
│ │ ├── sharing.go
│ │ ├── subscription.go
│ │ ├── team.go
│ │ ├── user.go
│ │ ├── util.go
│ │ └── version.go
│ ├── server/
│ │ ├── initHandlers.go
│ │ ├── params.go
│ │ └── server.go
│ ├── services/
│ │ ├── audit/
│ │ │ ├── audit.go
│ │ │ ├── record.go
│ │ │ └── record_test.go
│ │ ├── auth/
│ │ │ ├── email.go
│ │ │ ├── password.go
│ │ │ ├── password_test.go
│ │ │ ├── request_parser.go
│ │ │ └── request_parser_test.go
│ │ ├── config/
│ │ │ └── config.go
│ │ ├── metrics/
│ │ │ ├── metrics.go
│ │ │ └── service.go
│ │ ├── notify/
│ │ │ ├── notifylogger/
│ │ │ │ └── logger_backend.go
│ │ │ ├── notifymentions/
│ │ │ │ ├── app_api.go
│ │ │ │ ├── delivery.go
│ │ │ │ ├── extract.go
│ │ │ │ ├── extract_test.go
│ │ │ │ ├── mentions.go
│ │ │ │ ├── mentions_backend.go
│ │ │ │ └── mentions_test.go
│ │ │ ├── notifysubscriptions/
│ │ │ │ ├── app_api.go
│ │ │ │ ├── delivery.go
│ │ │ │ ├── diff.go
│ │ │ │ ├── diff2markdown.go
│ │ │ │ ├── diff2markdown_test.go
│ │ │ │ ├── diff2slackattachments.go
│ │ │ │ ├── notifier.go
│ │ │ │ ├── subscriptions_backend.go
│ │ │ │ └── util.go
│ │ │ ├── plugindelivery/
│ │ │ │ ├── mention_deliver.go
│ │ │ │ ├── message.go
│ │ │ │ ├── plugin_delivery.go
│ │ │ │ ├── subscription_deliver.go
│ │ │ │ ├── user.go
│ │ │ │ └── user_test.go
│ │ │ └── service.go
│ │ ├── permissions/
│ │ │ ├── localpermissions/
│ │ │ │ ├── helpers_test.go
│ │ │ │ ├── localpermissions.go
│ │ │ │ └── localpermissions_test.go
│ │ │ ├── mmpermissions/
│ │ │ │ ├── helpers_test.go
│ │ │ │ ├── mmpermissions.go
│ │ │ │ ├── mmpermissions_test.go
│ │ │ │ └── mocks/
│ │ │ │ └── mockpluginapi.go
│ │ │ ├── mocks/
│ │ │ │ └── mockstore.go
│ │ │ └── permissions.go
│ │ ├── scheduler/
│ │ │ ├── scheduler.go
│ │ │ └── scheduler_test.go
│ │ ├── store/
│ │ │ ├── generators/
│ │ │ │ ├── main.go
│ │ │ │ └── transactional_store.go.tmpl
│ │ │ ├── mattermostauthlayer/
│ │ │ │ ├── mattermostauthlayer.go
│ │ │ │ └── mattermostauthlayer_test.go
│ │ │ ├── mockstore/
│ │ │ │ └── mockstore.go
│ │ │ ├── sqlstore/
│ │ │ │ ├── blocks.go
│ │ │ │ ├── board.go
│ │ │ │ ├── boards_and_blocks.go
│ │ │ │ ├── category.go
│ │ │ │ ├── category_boards.go
│ │ │ │ ├── cloud.go
│ │ │ │ ├── compliance.go
│ │ │ │ ├── data_migrations.go
│ │ │ │ ├── data_migrations_test.go
│ │ │ │ ├── data_retention.go
│ │ │ │ ├── file.go
│ │ │ │ ├── helpers_test.go
│ │ │ │ ├── legacy_blocks.go
│ │ │ │ ├── migrate.go
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 000001_init.down.sql
│ │ │ │ │ ├── 000001_init.up.sql
│ │ │ │ │ ├── 000002_system_settings_table.down.sql
│ │ │ │ │ ├── 000002_system_settings_table.up.sql
│ │ │ │ │ ├── 000003_blocks_rootid.down.sql
│ │ │ │ │ ├── 000003_blocks_rootid.up.sql
│ │ │ │ │ ├── 000004_auth_table.down.sql
│ │ │ │ │ ├── 000004_auth_table.up.sql
│ │ │ │ │ ├── 000005_blocks_modifiedby.down.sql
│ │ │ │ │ ├── 000005_blocks_modifiedby.up.sql
│ │ │ │ │ ├── 000006_sharing_table.down.sql
│ │ │ │ │ ├── 000006_sharing_table.up.sql
│ │ │ │ │ ├── 000007_workspaces_table.down.sql
│ │ │ │ │ ├── 000007_workspaces_table.up.sql
│ │ │ │ │ ├── 000008_teams.down.sql
│ │ │ │ │ ├── 000008_teams.up.sql
│ │ │ │ │ ├── 000009_blocks_history.down.sql
│ │ │ │ │ ├── 000009_blocks_history.up.sql
│ │ │ │ │ ├── 000010_blocks_created_by.down.sql
│ │ │ │ │ ├── 000010_blocks_created_by.up.sql
│ │ │ │ │ ├── 000011_match_collation.down.sql
│ │ │ │ │ ├── 000011_match_collation.up.sql
│ │ │ │ │ ├── 000012_match_column_collation.down.sql
│ │ │ │ │ ├── 000012_match_column_collation.up.sql
│ │ │ │ │ ├── 000013_millisecond_timestamps.down.sql
│ │ │ │ │ ├── 000013_millisecond_timestamps.up.sql
│ │ │ │ │ ├── 000014_add_not_null_constraint.down.sql
│ │ │ │ │ ├── 000014_add_not_null_constraint.up.sql
│ │ │ │ │ ├── 000015_blocks_history_no_nulls.down.sql
│ │ │ │ │ ├── 000015_blocks_history_no_nulls.up.sql
│ │ │ │ │ ├── 000016_subscriptions_table.down.sql
│ │ │ │ │ ├── 000016_subscriptions_table.up.sql
│ │ │ │ │ ├── 000017_add_file_info.down.sql
│ │ │ │ │ ├── 000017_add_file_info.up.sql
│ │ │ │ │ ├── 000018_add_teams_and_boards.down.sql
│ │ │ │ │ ├── 000018_add_teams_and_boards.up.sql
│ │ │ │ │ ├── 000019_populate_categories.down.sql
│ │ │ │ │ ├── 000019_populate_categories.up.sql
│ │ │ │ │ ├── 000020_populate_category_blocks.down.sql
│ │ │ │ │ ├── 000020_populate_category_blocks.up.sql
│ │ │ │ │ ├── 000021_create_boards_members_history.down.sql
│ │ │ │ │ ├── 000021_create_boards_members_history.up.sql
│ │ │ │ │ ├── 000022_create_default_board_role.down.sql
│ │ │ │ │ ├── 000022_create_default_board_role.up.sql
│ │ │ │ │ ├── 000023_persist_category_collapsed_state.down.sql
│ │ │ │ │ ├── 000023_persist_category_collapsed_state.up.sql
│ │ │ │ │ ├── 000024_mark_existsing_categories_collapsed.down.sql
│ │ │ │ │ ├── 000024_mark_existsing_categories_collapsed.up.sql
│ │ │ │ │ ├── 000025_indexes_update.down.sql
│ │ │ │ │ ├── 000025_indexes_update.up.sql
│ │ │ │ │ ├── 000026_create_preferences_table.down.sql
│ │ │ │ │ ├── 000026_create_preferences_table.up.sql
│ │ │ │ │ ├── 000027_migrate_user_props_to_preferences.down.sql
│ │ │ │ │ ├── 000027_migrate_user_props_to_preferences.up.sql
│ │ │ │ │ ├── 000028_remove_template_channel_link.down.sql
│ │ │ │ │ ├── 000028_remove_template_channel_link.up.sql
│ │ │ │ │ ├── 000029_add_category_type_field.down.sql
│ │ │ │ │ ├── 000029_add_category_type_field.up.sql
│ │ │ │ │ ├── 000030_add_category_sort_order.down.sql
│ │ │ │ │ ├── 000030_add_category_sort_order.up.sql
│ │ │ │ │ ├── 000031_add_category_boards_sort_order.down.sql
│ │ │ │ │ ├── 000031_add_category_boards_sort_order.up.sql
│ │ │ │ │ ├── 000032_move_boards_category_to_end.down.sql
│ │ │ │ │ ├── 000032_move_boards_category_to_end.up.sql
│ │ │ │ │ ├── 000033_remove_deleted_category_boards.down.sql
│ │ │ │ │ ├── 000033_remove_deleted_category_boards.up.sql
│ │ │ │ │ ├── 000034_category_boards_remove_unused_delete_at_column.down.sql
│ │ │ │ │ ├── 000034_category_boards_remove_unused_delete_at_column.up.sql
│ │ │ │ │ ├── 000035_add_hidden_board_column.down.sql
│ │ │ │ │ ├── 000035_add_hidden_board_column.up.sql
│ │ │ │ │ ├── 000036_category_board_add_unique_constraint.down.sql
│ │ │ │ │ ├── 000036_category_board_add_unique_constraint.up.sql
│ │ │ │ │ ├── 000037_hidden_boards_from_preferences.down.sql
│ │ │ │ │ ├── 000037_hidden_boards_from_preferences.up.sql
│ │ │ │ │ ├── 000038_delete_hiddenBoardIDs_from_preferences.down.sql
│ │ │ │ │ ├── 000038_delete_hiddenBoardIDs_from_preferences.up.sql
│ │ │ │ │ ├── 000039_add_path_to_file_info.down.sql
│ │ │ │ │ ├── 000039_add_path_to_file_info.up.sql
│ │ │ │ │ ├── 000040_fix_fileinfo_soft_deletes.down.sql
│ │ │ │ │ ├── 000040_fix_fileinfo_soft_deletes.up.sql
│ │ │ │ │ └── README.md
│ │ │ │ ├── migrationstests/
│ │ │ │ │ ├── boards_migrator_test.go
│ │ │ │ │ ├── de_duplicate_category_boards_migration_test.go
│ │ │ │ │ ├── fixtures/
│ │ │ │ │ │ ├── deletedMembershipBoardsMigrationFixtures.sql
│ │ │ │ │ │ ├── test18AddTeamsAndBoardsSQLMigrationFixtures.sql
│ │ │ │ │ │ ├── test27MigrateUserPropsToPreferences.sql
│ │ │ │ │ │ ├── test28RemoveTemplateChannelLink.sql
│ │ │ │ │ │ ├── test33_with_deleted_data.sql
│ │ │ │ │ │ ├── test33_with_no_deleted_data.sql
│ │ │ │ │ │ ├── test34_drop_delete_at_column.sql
│ │ │ │ │ │ ├── test35_add_hidden_column.sql
│ │ │ │ │ │ ├── test36_add_unique_constraint.sql
│ │ │ │ │ │ ├── test37_valid_data.sql
│ │ │ │ │ │ ├── test37_valid_data_no_hidden_boards.sql
│ │ │ │ │ │ ├── test37_valid_data_preference_but_no_hidden_board.sql
│ │ │ │ │ │ ├── test37_valid_data_sqlite.sql
│ │ │ │ │ │ ├── test37_valid_data_sqlite_preference_but_no_hidden_board.sql
│ │ │ │ │ │ ├── test38_add_plugin_preferences.sql
│ │ │ │ │ │ ├── test38_add_standalone_preferences.sql
│ │ │ │ │ │ ├── test40FixFileinfoSoftDeletes.sql
│ │ │ │ │ │ └── testDeDuplicateCategoryBoardsMigration.sql
│ │ │ │ │ ├── helpers_test.go
│ │ │ │ │ ├── migrate_34_test.go
│ │ │ │ │ ├── migration35_test.go
│ │ │ │ │ ├── migration36_test.go
│ │ │ │ │ ├── migration37_test.go
│ │ │ │ │ ├── migration38_test.go
│ │ │ │ │ ├── migration_27_test.go
│ │ │ │ │ ├── migration_28_test.go
│ │ │ │ │ └── migration_33_test.go
│ │ │ │ ├── notificationhints.go
│ │ │ │ ├── params.go
│ │ │ │ ├── public_methods.go
│ │ │ │ ├── schema_table_migration.go
│ │ │ │ ├── schema_table_migration_test.go
│ │ │ │ ├── session.go
│ │ │ │ ├── sharing.go
│ │ │ │ ├── sqlite.go
│ │ │ │ ├── sqlstore.go
│ │ │ │ ├── sqlstore_test.go
│ │ │ │ ├── subscriptions.go
│ │ │ │ ├── system.go
│ │ │ │ ├── team.go
│ │ │ │ ├── templates.go
│ │ │ │ ├── user.go
│ │ │ │ └── util.go
│ │ │ ├── store.go
│ │ │ └── storetests/
│ │ │ ├── blocks.go
│ │ │ ├── boards.go
│ │ │ ├── boards_and_blocks.go
│ │ │ ├── category.go
│ │ │ ├── categoryBoards.go
│ │ │ ├── cloud.go
│ │ │ ├── compliance.go
│ │ │ ├── data_retention.go
│ │ │ ├── files.go
│ │ │ ├── helpers.go
│ │ │ ├── notificationhints.go
│ │ │ ├── session.go
│ │ │ ├── sharing.go
│ │ │ ├── subscriptions.go
│ │ │ ├── system.go
│ │ │ ├── teams.go
│ │ │ ├── users.go
│ │ │ └── util.go
│ │ ├── telemetry/
│ │ │ ├── mocks/
│ │ │ │ └── ServerIface.go
│ │ │ ├── telemetry.go
│ │ │ └── telemetry_test.go
│ │ └── webhook/
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── swagger/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── html/
│ │ │ ├── .openapi-generator/
│ │ │ │ └── VERSION
│ │ │ ├── .openapi-generator-ignore
│ │ │ └── index.html
│ │ └── swagger.yml
│ ├── utils/
│ │ ├── callbackqueue.go
│ │ ├── callbackqueue_test.go
│ │ ├── debug.go
│ │ ├── links.go
│ │ ├── testUtils.go
│ │ └── utils.go
│ ├── web/
│ │ ├── webserver.go
│ │ └── webserver_test.go
│ └── ws/
│ ├── adapter.go
│ ├── common.go
│ ├── helpers_test.go
│ ├── mocks/
│ │ ├── mockpluginapi.go
│ │ └── mockstore.go
│ ├── plugin_adapter.go
│ ├── plugin_adapter_client.go
│ ├── plugin_adapter_cluster.go
│ ├── plugin_adapter_test.go
│ ├── server.go
│ └── server_test.go
├── server-config.json
├── webapp/
│ ├── .eslintignore
│ ├── .eslintrc.json
│ ├── .nvmrc
│ ├── .prettierignore
│ ├── .prettierrc.json
│ ├── .stylelintrc.json
│ ├── NOTICE.txt
│ ├── __mocks__/
│ │ ├── fileMock.js
│ │ └── styleMock.js
│ ├── cypress/
│ │ ├── config.json
│ │ ├── global.d.ts
│ │ ├── integration/
│ │ │ ├── cardBadges.ts
│ │ │ ├── cardURLProperty.ts
│ │ │ ├── createBoard.ts
│ │ │ ├── groupByProperty.ts
│ │ │ ├── loginActions.ts
│ │ │ └── manageGroups.ts
│ │ ├── plugins/
│ │ │ └── index.js
│ │ ├── support/
│ │ │ ├── api_commands.ts
│ │ │ ├── index.ts
│ │ │ └── ui_commands.ts
│ │ └── tsconfig.json
│ ├── cypress.json
│ ├── html-templates/
│ │ ├── deveditor.ejs
│ │ └── page.ejs
│ ├── i18n/
│ │ ├── ar.json
│ │ ├── ars.json
│ │ ├── ca.json
│ │ ├── de.json
│ │ ├── el.json
│ │ ├── en.json
│ │ ├── en_AU.json
│ │ ├── es.json
│ │ ├── et.json
│ │ ├── fa.json
│ │ ├── fr.json
│ │ ├── he.json
│ │ ├── hr.json
│ │ ├── hu.json
│ │ ├── id.json
│ │ ├── it.json
│ │ ├── ja.json
│ │ ├── ka.json
│ │ ├── kab.json
│ │ ├── kk.json
│ │ ├── ko.json
│ │ ├── lt.json
│ │ ├── ml.json
│ │ ├── nb_NO.json
│ │ ├── nl.json
│ │ ├── oc.json
│ │ ├── pl.json
│ │ ├── pt.json
│ │ ├── pt_BR.json
│ │ ├── ru.json
│ │ ├── sk.json
│ │ ├── sl.json
│ │ ├── sv.json
│ │ ├── tr.json
│ │ ├── uk.json
│ │ ├── vi.json
│ │ ├── zh_Hans.json
│ │ └── zh_Hant.json
│ ├── package.json
│ ├── src/
│ │ ├── app.tsx
│ │ ├── archiver.ts
│ │ ├── blockIcons.ts
│ │ ├── blocks/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── block.test.ts.snap
│ │ │ │ └── board.test.ts.snap
│ │ │ ├── attachmentBlock.tsx
│ │ │ ├── block.test.ts
│ │ │ ├── block.ts
│ │ │ ├── board.test.ts
│ │ │ ├── board.ts
│ │ │ ├── boardView.test.ts
│ │ │ ├── boardView.ts
│ │ │ ├── card.ts
│ │ │ ├── checkboxBlock.ts
│ │ │ ├── commentBlock.ts
│ │ │ ├── contentBlock.ts
│ │ │ ├── dividerBlock.ts
│ │ │ ├── filterClause.test.ts
│ │ │ ├── filterClause.ts
│ │ │ ├── filterGroup.ts
│ │ │ ├── h1Block.tsx
│ │ │ ├── h2Block.tsx
│ │ │ ├── h3Block.tsx
│ │ │ ├── imageBlock.ts
│ │ │ ├── sharing.ts
│ │ │ ├── team.ts
│ │ │ ├── textBlock.ts
│ │ │ └── workspace.ts
│ │ ├── boardCloudLimits/
│ │ │ └── index.ts
│ │ ├── boardUtils.ts
│ │ ├── boardsCloudLimits/
│ │ │ └── index.ts
│ │ ├── cardFilter.test.ts
│ │ ├── cardFilter.ts
│ │ ├── components/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── addContentMenuItem.test.tsx.snap
│ │ │ │ ├── blockIconSelector.test.tsx.snap
│ │ │ │ ├── cardBadges.test.tsx.snap
│ │ │ │ ├── cardDialog.test.tsx.snap
│ │ │ │ ├── centerPanel.test.tsx.snap
│ │ │ │ ├── confirmAddUserForNotifications.test.tsx.snap
│ │ │ │ ├── confirmationDialogBox.test.tsx.snap
│ │ │ │ ├── contentBlock.test.tsx.snap
│ │ │ │ ├── dialog.test.tsx.snap
│ │ │ │ ├── flashMessages.test.tsx.snap
│ │ │ │ ├── markdownEditor.test.tsx.snap
│ │ │ │ ├── modal.test.tsx.snap
│ │ │ │ ├── personSelector.test.tsx.snap
│ │ │ │ ├── propertyValueElement.test.tsx.snap
│ │ │ │ ├── rootPortal.test.tsx.snap
│ │ │ │ ├── topBar.test.tsx.snap
│ │ │ │ ├── viewMenu.test.tsx.snap
│ │ │ │ ├── viewTitle.test.tsx.snap
│ │ │ │ └── workspace.test.tsx.snap
│ │ │ ├── addContentMenuItem.test.tsx
│ │ │ ├── addContentMenuItem.tsx
│ │ │ ├── blockIconSelector.test.tsx
│ │ │ ├── blockIconSelector.tsx
│ │ │ ├── blocksEditor/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── blockContent.test.tsx.snap
│ │ │ │ │ ├── blocksEditor.test.tsx.snap
│ │ │ │ │ ├── editor.test.tsx.snap
│ │ │ │ │ └── rootInput.test.tsx.snap
│ │ │ │ ├── blockContent.scss
│ │ │ │ ├── blockContent.test.tsx
│ │ │ │ ├── blockContent.tsx
│ │ │ │ ├── blocks/
│ │ │ │ │ ├── attachment/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── attachment.test.tsx.snap
│ │ │ │ │ │ ├── attachment.scss
│ │ │ │ │ │ ├── attachment.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── checkbox/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── checkbox.test.tsx.snap
│ │ │ │ │ │ ├── checkbox.scss
│ │ │ │ │ │ ├── checkbox.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── divider/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── divider.test.tsx.snap
│ │ │ │ │ │ ├── divider.scss
│ │ │ │ │ │ ├── divider.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── h1/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── h1.test.tsx.snap
│ │ │ │ │ │ ├── h1.scss
│ │ │ │ │ │ ├── h1.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── h2/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── h2.test.tsx.snap
│ │ │ │ │ │ ├── h2.scss
│ │ │ │ │ │ ├── h2.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── h3/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── h3.test.tsx.snap
│ │ │ │ │ │ ├── h3.scss
│ │ │ │ │ │ ├── h3.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── image/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── image.test.tsx.snap
│ │ │ │ │ │ ├── image.scss
│ │ │ │ │ │ ├── image.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── list-item/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── list-item.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── list-item.scss
│ │ │ │ │ │ └── list-item.test.tsx
│ │ │ │ │ ├── quote/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── quote.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── quote.scss
│ │ │ │ │ │ └── quote.test.tsx
│ │ │ │ │ ├── text/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── text.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── text.scss
│ │ │ │ │ │ └── text.test.tsx
│ │ │ │ │ ├── text-dev/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── text.scss
│ │ │ │ │ ├── types.tsx
│ │ │ │ │ └── video/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── video.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── video.scss
│ │ │ │ │ └── video.test.tsx
│ │ │ │ ├── blocksEditor.test.tsx
│ │ │ │ ├── blocksEditor.tsx
│ │ │ │ ├── devmain.scss
│ │ │ │ ├── devmain.tsx
│ │ │ │ ├── editor.scss
│ │ │ │ ├── editor.test.tsx
│ │ │ │ ├── editor.tsx
│ │ │ │ ├── rootInput.test.tsx
│ │ │ │ └── rootInput.tsx
│ │ │ ├── boardIconSelector.tsx
│ │ │ ├── boardTemplateSelector/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── boardTemplateSelector.test.tsx.snap
│ │ │ │ │ ├── boardTemplateSelectorItem.test.tsx.snap
│ │ │ │ │ └── boardTemplateSelectorPreview.test.tsx.snap
│ │ │ │ ├── boardTemplateSelector.scss
│ │ │ │ ├── boardTemplateSelector.test.tsx
│ │ │ │ ├── boardTemplateSelector.tsx
│ │ │ │ ├── boardTemplateSelectorItem.scss
│ │ │ │ ├── boardTemplateSelectorItem.test.tsx
│ │ │ │ ├── boardTemplateSelectorItem.tsx
│ │ │ │ ├── boardTemplateSelectorPreview.scss
│ │ │ │ ├── boardTemplateSelectorPreview.test.tsx
│ │ │ │ └── boardTemplateSelectorPreview.tsx
│ │ │ ├── boardsSwitcher/
│ │ │ │ ├── boardsSwitcher.scss
│ │ │ │ └── boardsSwitcher.tsx
│ │ │ ├── boardsSwitcherDialog/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── boardSwitcherDialog.test.tsx.snap
│ │ │ │ ├── boardSwitcherDialog.scss
│ │ │ │ ├── boardSwitcherDialog.test.tsx
│ │ │ │ └── boardSwitcherDialog.tsx
│ │ │ ├── calculations/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── calculation.test.tsx.snap
│ │ │ │ │ └── options.test.tsx.snap
│ │ │ │ ├── calculation.scss
│ │ │ │ ├── calculation.test.tsx
│ │ │ │ ├── calculation.tsx
│ │ │ │ ├── calculations.test.tsx
│ │ │ │ ├── calculations.ts
│ │ │ │ ├── options.test.tsx
│ │ │ │ └── options.tsx
│ │ │ ├── calendar/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── fullCalendar.test.tsx.snap
│ │ │ │ ├── fullCalendar.test.tsx
│ │ │ │ ├── fullCalendar.tsx
│ │ │ │ └── fullcalendar.scss
│ │ │ ├── cardActionsMenu/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── cardActionsMenu.test.tsx.snap
│ │ │ │ ├── cardActionsMenu.test.tsx
│ │ │ │ ├── cardActionsMenu.tsx
│ │ │ │ ├── cardActionsMenuIcon.scss
│ │ │ │ └── cardActionsMenuIcon.tsx
│ │ │ ├── cardBadges.scss
│ │ │ ├── cardBadges.test.tsx
│ │ │ ├── cardBadges.tsx
│ │ │ ├── cardDetail/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── cardDetail.test.tsx.snap
│ │ │ │ │ ├── cardDetailContents.test.tsx.snap
│ │ │ │ │ ├── cardDetailContentsMenu.test.tsx.snap
│ │ │ │ │ ├── cardDetailProperties.test.tsx.snap
│ │ │ │ │ ├── comment.test.tsx.snap
│ │ │ │ │ └── commentsList.test.tsx.snap
│ │ │ │ ├── attachment.scss
│ │ │ │ ├── attachment.tsx
│ │ │ │ ├── cardDetail.scss
│ │ │ │ ├── cardDetail.test.tsx
│ │ │ │ ├── cardDetail.tsx
│ │ │ │ ├── cardDetailContents.test.tsx
│ │ │ │ ├── cardDetailContents.tsx
│ │ │ │ ├── cardDetailContentsMenu.test.tsx
│ │ │ │ ├── cardDetailContentsMenu.tsx
│ │ │ │ ├── cardDetailContentsUtility.test.ts
│ │ │ │ ├── cardDetailContentsUtility.ts
│ │ │ │ ├── cardDetailContext.tsx
│ │ │ │ ├── cardDetailProperties.test.tsx
│ │ │ │ ├── cardDetailProperties.tsx
│ │ │ │ ├── comment.scss
│ │ │ │ ├── comment.test.tsx
│ │ │ │ ├── comment.tsx
│ │ │ │ ├── commentsList.scss
│ │ │ │ ├── commentsList.test.tsx
│ │ │ │ ├── commentsList.tsx
│ │ │ │ └── imagePaste.tsx
│ │ │ ├── cardDialog.scss
│ │ │ ├── cardDialog.test.tsx
│ │ │ ├── cardDialog.tsx
│ │ │ ├── cardLimitNotification.scss
│ │ │ ├── cardLimitNotification.tsx
│ │ │ ├── centerPanel.scss
│ │ │ ├── centerPanel.test.tsx
│ │ │ ├── centerPanel.tsx
│ │ │ ├── confirmAddUserForNotifications.scss
│ │ │ ├── confirmAddUserForNotifications.test.tsx
│ │ │ ├── confirmAddUserForNotifications.tsx
│ │ │ ├── confirmationDialogBox.scss
│ │ │ ├── confirmationDialogBox.test.tsx
│ │ │ ├── confirmationDialogBox.tsx
│ │ │ ├── content/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── attachmentElement.test.tsx.snap
│ │ │ │ │ ├── checkboxElement.test.tsx.snap
│ │ │ │ │ ├── contentElement.test.tsx.snap
│ │ │ │ │ ├── dividerElement.test.tsx.snap
│ │ │ │ │ ├── imageElement.test.tsx.snap
│ │ │ │ │ └── textElement.test.tsx.snap
│ │ │ │ ├── archivedFile/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── archivedFile.test.tsx.snap
│ │ │ │ │ ├── archivedFile.scss
│ │ │ │ │ ├── archivedFile.test.tsx
│ │ │ │ │ └── archivedFile.tsx
│ │ │ │ ├── attachmentElement.scss
│ │ │ │ ├── attachmentElement.test.tsx
│ │ │ │ ├── attachmentElement.tsx
│ │ │ │ ├── checkboxElement.scss
│ │ │ │ ├── checkboxElement.test.tsx
│ │ │ │ ├── checkboxElement.tsx
│ │ │ │ ├── contentElement.test.tsx
│ │ │ │ ├── contentElement.tsx
│ │ │ │ ├── contentRegistry.test.tsx
│ │ │ │ ├── contentRegistry.tsx
│ │ │ │ ├── dividerElement.scss
│ │ │ │ ├── dividerElement.test.tsx
│ │ │ │ ├── dividerElement.tsx
│ │ │ │ ├── imageElement.test.tsx
│ │ │ │ ├── imageElement.tsx
│ │ │ │ ├── textElement.scss
│ │ │ │ ├── textElement.test.tsx
│ │ │ │ └── textElement.tsx
│ │ │ ├── contentBlock.scss
│ │ │ ├── contentBlock.test.tsx
│ │ │ ├── contentBlock.tsx
│ │ │ ├── createCategory/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── createCategory.test.tsx.snap
│ │ │ │ ├── createCategory.scss
│ │ │ │ ├── createCategory.test.tsx
│ │ │ │ └── createCategory.tsx
│ │ │ ├── dialog.scss
│ │ │ ├── dialog.test.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── flashMessages.scss
│ │ │ ├── flashMessages.test.tsx
│ │ │ ├── flashMessages.tsx
│ │ │ ├── gallery/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── gallery.test.tsx.snap
│ │ │ │ │ └── galleryCard.test.tsx.snap
│ │ │ │ ├── gallery.scss
│ │ │ │ ├── gallery.test.tsx
│ │ │ │ ├── gallery.tsx
│ │ │ │ ├── galleryCard.scss
│ │ │ │ ├── galleryCard.test.tsx
│ │ │ │ └── galleryCard.tsx
│ │ │ ├── globalHeader/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── globalHeader.test.tsx.snap
│ │ │ │ │ └── globalHeaderSettingsMenu.test.tsx.snap
│ │ │ │ ├── globalHeader.scss
│ │ │ │ ├── globalHeader.test.tsx
│ │ │ │ ├── globalHeader.tsx
│ │ │ │ ├── globalHeaderSettingsMenu.scss
│ │ │ │ ├── globalHeaderSettingsMenu.test.tsx
│ │ │ │ └── globalHeaderSettingsMenu.tsx
│ │ │ ├── guestNoBoards.scss
│ │ │ ├── guestNoBoards.tsx
│ │ │ ├── hiddenCardCount/
│ │ │ │ ├── hiddenCardCount.scss
│ │ │ │ └── hiddenCardCount.tsx
│ │ │ ├── iconSelector.scss
│ │ │ ├── iconSelector.tsx
│ │ │ ├── kanban/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── kanban.test.tsx.snap
│ │ │ │ │ ├── kanbanCard.test.tsx.snap
│ │ │ │ │ ├── kanbanColumn.test.tsx.snap
│ │ │ │ │ ├── kanbanColumnHeader.test.tsx.snap
│ │ │ │ │ └── kanbanHiddenColumnItem.test.tsx.snap
│ │ │ │ ├── calculation/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── calculation.test.tsx.snap
│ │ │ │ │ │ ├── calculationOptions.test.tsx.snap
│ │ │ │ │ │ └── kanbanOption.test.tsx.snap
│ │ │ │ │ ├── calculation.scss
│ │ │ │ │ ├── calculation.test.tsx
│ │ │ │ │ ├── calculation.tsx
│ │ │ │ │ ├── calculationOption.scss
│ │ │ │ │ ├── calculationOptions.test.tsx
│ │ │ │ │ ├── calculationOptions.tsx
│ │ │ │ │ ├── kanbanOption.test.tsx
│ │ │ │ │ └── kanbanOption.tsx
│ │ │ │ ├── kanban.scss
│ │ │ │ ├── kanban.test.tsx
│ │ │ │ ├── kanban.tsx
│ │ │ │ ├── kanbanCard.scss
│ │ │ │ ├── kanbanCard.test.tsx
│ │ │ │ ├── kanbanCard.tsx
│ │ │ │ ├── kanbanColumn.scss
│ │ │ │ ├── kanbanColumn.test.tsx
│ │ │ │ ├── kanbanColumn.tsx
│ │ │ │ ├── kanbanColumnHeader.test.tsx
│ │ │ │ ├── kanbanColumnHeader.tsx
│ │ │ │ ├── kanbanHiddenColumnItem.test.tsx
│ │ │ │ └── kanbanHiddenColumnItem.tsx
│ │ │ ├── live-markdown-plugin/
│ │ │ │ ├── block-types/
│ │ │ │ │ ├── codeBlockStrategy.ts
│ │ │ │ │ └── headingBlockStrategy.ts
│ │ │ │ ├── inline-styles/
│ │ │ │ │ ├── boldStyleStrategy.ts
│ │ │ │ │ ├── headingDelimiterStyleStrategy.ts
│ │ │ │ │ ├── inlineCodeStyleStrategy.ts
│ │ │ │ │ ├── italicStyleStrategy.ts
│ │ │ │ │ ├── olDelimiterStyleStrategy.ts
│ │ │ │ │ ├── quoteStyleStrategy.ts
│ │ │ │ │ ├── strikethroughStyleStrategy.ts
│ │ │ │ │ └── ulDelimiterStyleStrategy.ts
│ │ │ │ ├── liveMarkdownPlugin.ts
│ │ │ │ ├── pluginStrategy.ts
│ │ │ │ └── utils/
│ │ │ │ └── findRangesWithRegex.ts
│ │ │ ├── markdownEditor.scss
│ │ │ ├── markdownEditor.test.tsx
│ │ │ ├── markdownEditor.tsx
│ │ │ ├── markdownEditorInput/
│ │ │ │ ├── entryComponent/
│ │ │ │ │ ├── entryComponent.scss
│ │ │ │ │ └── entryComponent.tsx
│ │ │ │ ├── markdownEditorInput.scss
│ │ │ │ └── markdownEditorInput.tsx
│ │ │ ├── messages/
│ │ │ │ ├── versionMessage.scss
│ │ │ │ ├── versionMessage.test.tsx
│ │ │ │ └── versionMessage.tsx
│ │ │ ├── modal.scss
│ │ │ ├── modal.test.tsx
│ │ │ ├── modal.tsx
│ │ │ ├── modalWrapper.scss
│ │ │ ├── modalWrapper.tsx
│ │ │ ├── newVersionBanner.scss
│ │ │ ├── newVersionBanner.tsx
│ │ │ ├── onboardingTour/
│ │ │ │ ├── addComments/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addComments.test.tsx.snap
│ │ │ │ │ ├── addComments.test.tsx
│ │ │ │ │ ├── addComments.tsx
│ │ │ │ │ └── add_comments.scss
│ │ │ │ ├── addDescription/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addDescription.test.tsx.snap
│ │ │ │ │ ├── addDescription.test.tsx
│ │ │ │ │ ├── add_description.scss
│ │ │ │ │ └── add_description.tsx
│ │ │ │ ├── addProperties/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addProperties.test.tsx.snap
│ │ │ │ │ ├── addProperties.test.tsx
│ │ │ │ │ ├── add_properties.scss
│ │ │ │ │ └── add_properties.tsx
│ │ │ │ ├── addView/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── addView.test.tsx.snap
│ │ │ │ │ ├── addView.test.tsx
│ │ │ │ │ ├── add_view.scss
│ │ │ │ │ └── add_view.tsx
│ │ │ │ ├── copyLink/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── copyLink.test.tsx.snap
│ │ │ │ │ ├── copyLink.test.tsx
│ │ │ │ │ ├── copy_link.scss
│ │ │ │ │ └── copy_link.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── manageCategories/
│ │ │ │ │ ├── manageCategories.scss
│ │ │ │ │ └── manageCategories.tsx
│ │ │ │ ├── openCard/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── openCard.test.tsx.snap
│ │ │ │ │ ├── openCard.test.tsx
│ │ │ │ │ ├── open_card.scss
│ │ │ │ │ └── open_card.tsx
│ │ │ │ ├── searchForBoards/
│ │ │ │ │ ├── searchForBoards.scss
│ │ │ │ │ └── searchForBoards.tsx
│ │ │ │ ├── shareBoard/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── shareBoard.test.tsx.snap
│ │ │ │ │ ├── shareBoard.scss
│ │ │ │ │ ├── shareBoard.test.tsx
│ │ │ │ │ └── shareBoard.tsx
│ │ │ │ ├── sidebarCategories/
│ │ │ │ │ ├── sidebarCategories.scss
│ │ │ │ │ └── sidebarCategories.tsx
│ │ │ │ └── tourTipRenderer/
│ │ │ │ └── tourTipRenderer.tsx
│ │ │ ├── permissions/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── boardPermissionGate.test.tsx.snap
│ │ │ │ ├── boardPermissionGate.test.tsx
│ │ │ │ └── boardPermissionGate.tsx
│ │ │ ├── personSelector.scss
│ │ │ ├── personSelector.test.tsx
│ │ │ ├── personSelector.tsx
│ │ │ ├── propertyValueElement.test.tsx
│ │ │ ├── propertyValueElement.tsx
│ │ │ ├── pulsating_dot/
│ │ │ │ ├── index.tsx
│ │ │ │ └── pulsating_dot.scss
│ │ │ ├── rootPortal.test.tsx
│ │ │ ├── rootPortal.tsx
│ │ │ ├── searchDialog/
│ │ │ │ ├── searchDialog.scss
│ │ │ │ └── searchDialog.tsx
│ │ │ ├── shareBoard/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── shareBoard.test.tsx.snap
│ │ │ │ │ ├── shareBoardButton.test.tsx.snap
│ │ │ │ │ ├── shareBoardLoginButton.test.tsx.snap
│ │ │ │ │ ├── teamPermissionsRow.test.tsx.snap
│ │ │ │ │ └── userPermissionsRow.test.tsx.snap
│ │ │ │ ├── shareBoard.scss
│ │ │ │ ├── shareBoard.test.tsx
│ │ │ │ ├── shareBoard.tsx
│ │ │ │ ├── shareBoardButton.scss
│ │ │ │ ├── shareBoardButton.test.tsx
│ │ │ │ ├── shareBoardButton.tsx
│ │ │ │ ├── shareBoardLoginButton.scss
│ │ │ │ ├── shareBoardLoginButton.test.tsx
│ │ │ │ ├── shareBoardLoginButton.tsx
│ │ │ │ ├── teamPermissionsRow.test.tsx
│ │ │ │ ├── teamPermissionsRow.tsx
│ │ │ │ ├── userPermissionsRow.test.tsx
│ │ │ │ └── userPermissionsRow.tsx
│ │ │ ├── sidebar/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── deleteBoardDialog.test.tsx.snap
│ │ │ │ │ ├── registrationLink.test.tsx.snap
│ │ │ │ │ ├── sidebar.test.tsx.snap
│ │ │ │ │ ├── sidebarBoardItem.test.tsx.snap
│ │ │ │ │ ├── sidebarCategory.test.tsx.snap
│ │ │ │ │ └── sidebarSettingsMenu.test.tsx.snap
│ │ │ │ ├── deleteBoardDialog.scss
│ │ │ │ ├── deleteBoardDialog.test.tsx
│ │ │ │ ├── deleteBoardDialog.tsx
│ │ │ │ ├── registrationLink.scss
│ │ │ │ ├── registrationLink.test.tsx
│ │ │ │ ├── registrationLink.tsx
│ │ │ │ ├── sidebar.scss
│ │ │ │ ├── sidebar.test.tsx
│ │ │ │ ├── sidebar.tsx
│ │ │ │ ├── sidebarBoardItem.scss
│ │ │ │ ├── sidebarBoardItem.test.tsx
│ │ │ │ ├── sidebarBoardItem.tsx
│ │ │ │ ├── sidebarCategory.scss
│ │ │ │ ├── sidebarCategory.test.tsx
│ │ │ │ ├── sidebarCategory.tsx
│ │ │ │ ├── sidebarSettingsMenu.scss
│ │ │ │ ├── sidebarSettingsMenu.test.tsx
│ │ │ │ ├── sidebarSettingsMenu.tsx
│ │ │ │ ├── sidebarUserMenu.scss
│ │ │ │ └── sidebarUserMenu.tsx
│ │ │ ├── table/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── table.test.tsx.snap
│ │ │ │ │ ├── tableGroupHeaderRow.test.tsx.snap
│ │ │ │ │ ├── tableHeader.test.tsx.snap
│ │ │ │ │ ├── tableHeaderMenu.test.tsx.snap
│ │ │ │ │ ├── tableHeaders.test.tsx.snap
│ │ │ │ │ ├── tableRow.test.tsx.snap
│ │ │ │ │ └── tableRows.test.tsx.snap
│ │ │ │ ├── calculation/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── calculationRow.test.tsx.snap
│ │ │ │ │ ├── calculationRow.scss
│ │ │ │ │ ├── calculationRow.test.tsx
│ │ │ │ │ ├── calculationRow.tsx
│ │ │ │ │ └── tableCalculationOptions.tsx
│ │ │ │ ├── horizontalGrip.scss
│ │ │ │ ├── horizontalGrip.tsx
│ │ │ │ ├── table.scss
│ │ │ │ ├── table.test.tsx
│ │ │ │ ├── table.tsx
│ │ │ │ ├── tableColumnResizeContext.tsx
│ │ │ │ ├── tableGroup.tsx
│ │ │ │ ├── tableGroupHeaderRow.test.tsx
│ │ │ │ ├── tableGroupHeaderRow.tsx
│ │ │ │ ├── tableHeader.test.tsx
│ │ │ │ ├── tableHeader.tsx
│ │ │ │ ├── tableHeaderMenu.test.tsx
│ │ │ │ ├── tableHeaderMenu.tsx
│ │ │ │ ├── tableHeaders.test.tsx
│ │ │ │ ├── tableHeaders.tsx
│ │ │ │ ├── tableRow.scss
│ │ │ │ ├── tableRow.test.tsx
│ │ │ │ ├── tableRow.tsx
│ │ │ │ ├── tableRows.test.tsx
│ │ │ │ └── tableRows.tsx
│ │ │ ├── topBar.scss
│ │ │ ├── topBar.test.tsx
│ │ │ ├── topBar.tsx
│ │ │ ├── tutorial_tour_tip/
│ │ │ │ ├── hooks.ts
│ │ │ │ ├── tutorial_tour_tip.scss
│ │ │ │ ├── tutorial_tour_tip.tsx
│ │ │ │ ├── tutorial_tour_tip_backdrop.tsx
│ │ │ │ ├── tutorial_tour_tip_manager.tsx
│ │ │ │ └── useElementAvailable.ts
│ │ │ ├── viewHeader/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── dateFilter.test.tsx.snap
│ │ │ │ │ ├── emptyCardButton.test.tsx.snap
│ │ │ │ │ ├── filterComponent.test.tsx.snap
│ │ │ │ │ ├── filterEntry.test.tsx.snap
│ │ │ │ │ ├── filterValue.test.tsx.snap
│ │ │ │ │ ├── newCardButton.test.tsx.snap
│ │ │ │ │ ├── newCardButtonTemplateItem.test.tsx.snap
│ │ │ │ │ ├── viewHeader.test.tsx.snap
│ │ │ │ │ ├── viewHeaderActionsMenu.test.tsx.snap
│ │ │ │ │ ├── viewHeaderGroupByMenu.test.tsx.snap
│ │ │ │ │ ├── viewHeaderPropertiesMenu.test.tsx.snap
│ │ │ │ │ ├── viewHeaderSearch.test.tsx.snap
│ │ │ │ │ └── viewHeaderSortMenu.test.tsx.snap
│ │ │ │ ├── dateFilter.scss
│ │ │ │ ├── dateFilter.test.tsx
│ │ │ │ ├── dateFilter.tsx
│ │ │ │ ├── emptyCardButton.test.tsx
│ │ │ │ ├── emptyCardButton.tsx
│ │ │ │ ├── filterComponent.scss
│ │ │ │ ├── filterComponent.test.tsx
│ │ │ │ ├── filterComponent.tsx
│ │ │ │ ├── filterEntry.scss
│ │ │ │ ├── filterEntry.test.tsx
│ │ │ │ ├── filterEntry.tsx
│ │ │ │ ├── filterValue.scss
│ │ │ │ ├── filterValue.test.tsx
│ │ │ │ ├── filterValue.tsx
│ │ │ │ ├── multiperson.scss
│ │ │ │ ├── multipersonFilterValue.tsx
│ │ │ │ ├── newCardButton.test.tsx
│ │ │ │ ├── newCardButton.tsx
│ │ │ │ ├── newCardButtonTemplateItem.test.tsx
│ │ │ │ ├── newCardButtonTemplateItem.tsx
│ │ │ │ ├── viewHeader.scss
│ │ │ │ ├── viewHeader.test.tsx
│ │ │ │ ├── viewHeader.tsx
│ │ │ │ ├── viewHeaderActionsMenu.test.tsx
│ │ │ │ ├── viewHeaderActionsMenu.tsx
│ │ │ │ ├── viewHeaderDisplayByMenu.tsx
│ │ │ │ ├── viewHeaderGroupByMenu.test.tsx
│ │ │ │ ├── viewHeaderGroupByMenu.tsx
│ │ │ │ ├── viewHeaderPropertiesMenu.test.tsx
│ │ │ │ ├── viewHeaderPropertiesMenu.tsx
│ │ │ │ ├── viewHeaderSearch.test.tsx
│ │ │ │ ├── viewHeaderSearch.tsx
│ │ │ │ ├── viewHeaderSortMenu.test.tsx
│ │ │ │ └── viewHeaderSortMenu.tsx
│ │ │ ├── viewMenu.scss
│ │ │ ├── viewMenu.test.tsx
│ │ │ ├── viewMenu.tsx
│ │ │ ├── viewTitle.scss
│ │ │ ├── viewTitle.test.tsx
│ │ │ ├── viewTitle.tsx
│ │ │ ├── withWebSockets.tsx
│ │ │ ├── workspace.scss
│ │ │ ├── workspace.test.tsx
│ │ │ └── workspace.tsx
│ │ ├── config/
│ │ │ └── clientConfig.ts
│ │ ├── constants.ts
│ │ ├── csvExporter.ts
│ │ ├── emojiList.ts
│ │ ├── errors.ts
│ │ ├── file.ts
│ │ ├── fileIcons.ts
│ │ ├── hooks/
│ │ │ ├── permissions.tsx
│ │ │ ├── sortable.tsx
│ │ │ ├── useGetAllTemplates.ts
│ │ │ └── websockets.tsx
│ │ ├── i18n.tsx
│ │ ├── insights/
│ │ │ └── index.ts
│ │ ├── main.tsx
│ │ ├── mutator.test.ts
│ │ ├── mutator.ts
│ │ ├── nativeApp.ts
│ │ ├── octoClient.test.ts
│ │ ├── octoClient.ts
│ │ ├── octoUtils.test.ts
│ │ ├── octoUtils.tsx
│ │ ├── onboardingTour/
│ │ │ └── index.ts
│ │ ├── pages/
│ │ │ ├── boardPage/
│ │ │ │ ├── backwardCompatibilityQueryParamsRedirect.tsx
│ │ │ │ ├── boardPage.scss
│ │ │ │ ├── boardPage.tsx
│ │ │ │ ├── setWindowTitleAndIcon.tsx
│ │ │ │ ├── teamToBoardAndViewRedirect.tsx
│ │ │ │ ├── undoRedoHotKeys.tsx
│ │ │ │ └── websocketConnection.tsx
│ │ │ ├── changePasswordPage.scss
│ │ │ ├── changePasswordPage.tsx
│ │ │ ├── errorPage.scss
│ │ │ ├── errorPage.tsx
│ │ │ ├── loginPage.scss
│ │ │ ├── loginPage.tsx
│ │ │ ├── registerPage.scss
│ │ │ ├── registerPage.tsx
│ │ │ └── welcome/
│ │ │ ├── __snapshots__/
│ │ │ │ └── welcomePage.test.tsx.snap
│ │ │ ├── welcomePage.scss
│ │ │ ├── welcomePage.test.tsx
│ │ │ └── welcomePage.tsx
│ │ ├── properties/
│ │ │ ├── baseTextEditor.tsx
│ │ │ ├── checkbox/
│ │ │ │ ├── checkbox.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── createdBy/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── createdBy.test.tsx.snap
│ │ │ │ ├── createdBy.test.tsx
│ │ │ │ ├── createdBy.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── createdTime/
│ │ │ │ ├── createdTime.scss
│ │ │ │ ├── createdTime.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── date/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── date.test.tsx.snap
│ │ │ │ ├── date.scss
│ │ │ │ ├── date.test.tsx
│ │ │ │ ├── date.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── email/
│ │ │ │ ├── email.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── index.tsx
│ │ │ ├── multiperson/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── multiperson.test.tsx.snap
│ │ │ │ ├── multiperson.test.tsx
│ │ │ │ ├── multiperson.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── multiselect/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── multiselect.test.tsx.snap
│ │ │ │ ├── multiselect.test.tsx
│ │ │ │ ├── multiselect.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── number/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── number.test.tsx.snap
│ │ │ │ ├── number.test.tsx
│ │ │ │ ├── number.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── person/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── confirmPerson.test.tsx.snap
│ │ │ │ │ └── person.test.tsx.snap
│ │ │ │ ├── confirmPerson.test.tsx
│ │ │ │ ├── confirmPerson.tsx
│ │ │ │ ├── person.test.tsx
│ │ │ │ ├── person.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── phone/
│ │ │ │ ├── phone.tsx
│ │ │ │ └── property.tsx
│ │ │ ├── select/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── select.test.tsx.snap
│ │ │ │ ├── property.tsx
│ │ │ │ ├── select.test.tsx
│ │ │ │ └── select.tsx
│ │ │ ├── text/
│ │ │ │ ├── property.tsx
│ │ │ │ └── text.tsx
│ │ │ ├── types.tsx
│ │ │ ├── unknown/
│ │ │ │ └── property.tsx
│ │ │ ├── updatedBy/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── updatedBy.test.tsx.snap
│ │ │ │ ├── property.tsx
│ │ │ │ ├── updatedBy.scss
│ │ │ │ ├── updatedBy.test.tsx
│ │ │ │ └── updatedBy.tsx
│ │ │ ├── updatedTime/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── updatedTime.test.tsx.snap
│ │ │ │ ├── property.tsx
│ │ │ │ ├── updatedTime.scss
│ │ │ │ ├── updatedTime.test.tsx
│ │ │ │ └── updatedTime.tsx
│ │ │ └── url/
│ │ │ ├── __snapshots__/
│ │ │ │ └── url.test.tsx.snap
│ │ │ ├── property.tsx
│ │ │ ├── url.scss
│ │ │ ├── url.test.tsx
│ │ │ └── url.tsx
│ │ ├── route.tsx
│ │ ├── router.tsx
│ │ ├── statistics/
│ │ │ └── index.ts
│ │ ├── store/
│ │ │ ├── attachments.ts
│ │ │ ├── boards.ts
│ │ │ ├── cards.ts
│ │ │ ├── channels.ts
│ │ │ ├── clientConfig.ts
│ │ │ ├── comments.ts
│ │ │ ├── contents.ts
│ │ │ ├── globalError.ts
│ │ │ ├── globalTemplates.ts
│ │ │ ├── hooks.ts
│ │ │ ├── index.ts
│ │ │ ├── initialLoad.ts
│ │ │ ├── language.ts
│ │ │ ├── limits.ts
│ │ │ ├── searchText.ts
│ │ │ ├── sidebar.ts
│ │ │ ├── teams.ts
│ │ │ ├── users.ts
│ │ │ └── views.ts
│ │ ├── styles/
│ │ │ ├── _markdown.scss
│ │ │ ├── _modifiers.scss
│ │ │ ├── _typography.scss
│ │ │ ├── _z-index.scss
│ │ │ ├── focalboard-variables.scss
│ │ │ ├── labels.scss
│ │ │ ├── main.scss
│ │ │ ├── shared-variables.scss
│ │ │ └── variables.scss
│ │ ├── svg/
│ │ │ ├── card-skeleton.tsx
│ │ │ ├── error-illustration.tsx
│ │ │ └── search-illustration.tsx
│ │ ├── telemetry/
│ │ │ ├── telemetry.ts
│ │ │ ├── telemetryClient.test.ts
│ │ │ └── telemetryClient.ts
│ │ ├── test/
│ │ │ ├── fetchMock.ts
│ │ │ └── testBlockFactory.ts
│ │ ├── testUtils.tsx
│ │ ├── theme.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── images.d.ts
│ │ │ └── index.d.ts
│ │ ├── undoManager.test.ts
│ │ ├── undomanager.ts
│ │ ├── user.tsx
│ │ ├── userSettings.ts
│ │ ├── utils.test.ts
│ │ ├── utils.ts
│ │ ├── widgets/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── guestBadge.test.tsx.snap
│ │ │ │ └── propertyMenu.test.tsx.snap
│ │ │ ├── adminBadge/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── adminBadge.test.tsx.snap
│ │ │ │ ├── adminBadge.scss
│ │ │ │ ├── adminBadge.test.tsx
│ │ │ │ └── adminBadge.tsx
│ │ │ ├── buttons/
│ │ │ │ ├── button.scss
│ │ │ │ ├── button.tsx
│ │ │ │ ├── buttonWithMenu.scss
│ │ │ │ ├── buttonWithMenu.tsx
│ │ │ │ ├── iconButton.scss
│ │ │ │ └── iconButton.tsx
│ │ │ ├── editable.scss
│ │ │ ├── editable.tsx
│ │ │ ├── editableArea.scss
│ │ │ ├── editableArea.tsx
│ │ │ ├── editableDayPicker.scss
│ │ │ ├── editableDayPicker.tsx
│ │ │ ├── emojiPicker.scss
│ │ │ ├── emojiPicker.tsx
│ │ │ ├── guestBadge.scss
│ │ │ ├── guestBadge.test.tsx
│ │ │ ├── guestBadge.tsx
│ │ │ ├── icons/
│ │ │ │ ├── HandRight.tsx
│ │ │ │ ├── Link.tsx
│ │ │ │ ├── add.scss
│ │ │ │ ├── add.tsx
│ │ │ │ ├── alert.tsx
│ │ │ │ ├── apps.tsx
│ │ │ │ ├── board.scss
│ │ │ │ ├── board.tsx
│ │ │ │ ├── brokenFile.tsx
│ │ │ │ ├── calendar.scss
│ │ │ │ ├── calendar.tsx
│ │ │ │ ├── card.scss
│ │ │ │ ├── card.tsx
│ │ │ │ ├── check.scss
│ │ │ │ ├── check.tsx
│ │ │ │ ├── checkIcon.tsx
│ │ │ │ ├── chevronDown.tsx
│ │ │ │ ├── chevronRight.tsx
│ │ │ │ ├── chevronUp.tsx
│ │ │ │ ├── close.tsx
│ │ │ │ ├── closeCircle.tsx
│ │ │ │ ├── compassIcon.tsx
│ │ │ │ ├── delete.scss
│ │ │ │ ├── delete.tsx
│ │ │ │ ├── disclosureTriangle.scss
│ │ │ │ ├── disclosureTriangle.tsx
│ │ │ │ ├── divider.scss
│ │ │ │ ├── divider.tsx
│ │ │ │ ├── dot.scss
│ │ │ │ ├── dot.tsx
│ │ │ │ ├── dropdown.scss
│ │ │ │ ├── dropdown.tsx
│ │ │ │ ├── duplicate.scss
│ │ │ │ ├── duplicate.tsx
│ │ │ │ ├── edit.tsx
│ │ │ │ ├── emoji.scss
│ │ │ │ ├── emoji.tsx
│ │ │ │ ├── focalboard_logo.scss
│ │ │ │ ├── focalboard_logo.tsx
│ │ │ │ ├── folder.tsx
│ │ │ │ ├── gallery.scss
│ │ │ │ ├── gallery.tsx
│ │ │ │ ├── globe.tsx
│ │ │ │ ├── grip.scss
│ │ │ │ ├── grip.tsx
│ │ │ │ ├── hamburger.scss
│ │ │ │ ├── hamburger.tsx
│ │ │ │ ├── help.scss
│ │ │ │ ├── help.tsx
│ │ │ │ ├── hide.scss
│ │ │ │ ├── hide.tsx
│ │ │ │ ├── hideSidebar.scss
│ │ │ │ ├── hideSidebar.tsx
│ │ │ │ ├── image.scss
│ │ │ │ ├── image.tsx
│ │ │ │ ├── link.scss
│ │ │ │ ├── lockOutline.tsx
│ │ │ │ ├── logo.scss
│ │ │ │ ├── logo.tsx
│ │ │ │ ├── logoWithName.scss
│ │ │ │ ├── logoWithName.tsx
│ │ │ │ ├── logoWithNameWhite.scss
│ │ │ │ ├── logoWithNameWhite.tsx
│ │ │ │ ├── message.tsx
│ │ │ │ ├── newFolder.tsx
│ │ │ │ ├── options.scss
│ │ │ │ ├── options.tsx
│ │ │ │ ├── random.tsx
│ │ │ │ ├── search.tsx
│ │ │ │ ├── settings.scss
│ │ │ │ ├── settings.tsx
│ │ │ │ ├── show.scss
│ │ │ │ ├── show.tsx
│ │ │ │ ├── showSidebar.scss
│ │ │ │ ├── showSidebar.tsx
│ │ │ │ ├── sortDown.scss
│ │ │ │ ├── sortDown.tsx
│ │ │ │ ├── sortUp.scss
│ │ │ │ ├── sortUp.tsx
│ │ │ │ ├── submenuTriangle.scss
│ │ │ │ ├── submenuTriangle.tsx
│ │ │ │ ├── table.scss
│ │ │ │ ├── table.tsx
│ │ │ │ ├── text.scss
│ │ │ │ ├── text.tsx
│ │ │ │ └── update.tsx
│ │ │ ├── label.scss
│ │ │ ├── label.tsx
│ │ │ ├── menu/
│ │ │ │ ├── colorOption.scss
│ │ │ │ ├── colorOption.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── labelOption.scss
│ │ │ │ ├── labelOption.tsx
│ │ │ │ ├── menu.scss
│ │ │ │ ├── menu.tsx
│ │ │ │ ├── menuItem.tsx
│ │ │ │ ├── menuUtil.ts
│ │ │ │ ├── separatorOption.scss
│ │ │ │ ├── separatorOption.tsx
│ │ │ │ ├── subMenuOption.scss
│ │ │ │ ├── subMenuOption.tsx
│ │ │ │ ├── switchOption.tsx
│ │ │ │ ├── textInputOption.tsx
│ │ │ │ └── textOption.tsx
│ │ │ ├── menuWrapper.scss
│ │ │ ├── menuWrapper.tsx
│ │ │ ├── notificationBox/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── notificationBox.test.tsx.snap
│ │ │ │ ├── notificationBox.scss
│ │ │ │ ├── notificationBox.test.tsx
│ │ │ │ └── notificationBox.tsx
│ │ │ ├── propertyMenu.scss
│ │ │ ├── propertyMenu.test.tsx
│ │ │ ├── propertyMenu.tsx
│ │ │ ├── switch.scss
│ │ │ ├── switch.tsx
│ │ │ ├── tooltip.scss
│ │ │ ├── tooltip.tsx
│ │ │ ├── valueSelector.scss
│ │ │ └── valueSelector.tsx
│ │ └── wsclient.ts
│ ├── tsconfig.json
│ ├── tslint.json
│ ├── webpack.common.js
│ ├── webpack.dev.js
│ ├── webpack.editor.js
│ └── webpack.prod.js
├── website/
│ ├── .editorconfig
│ ├── .gitignore
│ ├── Makefile
│ ├── README.md
│ └── site/
│ ├── archetypes/
│ │ └── default.md
│ ├── config.toml
│ ├── content/
│ │ ├── blog/
│ │ │ ├── 2021-1-7-hello.md
│ │ │ ├── 2021-4-21-Focalboard v0.6.5 release.md
│ │ │ ├── 2021-4-27-Mattermost-Focalboard-early-preview.md
│ │ │ ├── 2021-5-07-meeting-agenda-template.md
│ │ │ ├── 2021-5-13-Focalboard-the-road-to-v1.md
│ │ │ └── 2021-6-18-Mattermost-Focalboard-release.md
│ │ ├── docs/
│ │ │ └── personal-edition/
│ │ │ ├── _index.md
│ │ │ ├── desktop.md
│ │ │ ├── docker.md
│ │ │ ├── ubuntu-upgrade.md
│ │ │ └── ubuntu.md
│ │ ├── download/
│ │ │ └── index.html
│ │ ├── feedback/
│ │ │ └── _index.md
│ │ ├── fwlink/
│ │ │ ├── doc-boards.html
│ │ │ ├── feedback-boards.html
│ │ │ ├── feedback-focalboard.html
│ │ │ ├── plugin-setup.html
│ │ │ ├── setup-536.html
│ │ │ ├── v1-focalboard.html
│ │ │ └── websocket-connect-error.html
│ │ └── guide/
│ │ ├── admin/
│ │ │ └── _index.md
│ │ ├── server-setup/
│ │ │ └── _index.md
│ │ ├── user/
│ │ │ └── _index.md
│ │ └── websocket-errors/
│ │ └── _index.md
│ ├── layouts/
│ │ ├── 404.html
│ │ ├── _default/
│ │ │ ├── _markup/
│ │ │ │ └── render-link.html
│ │ │ ├── list.html
│ │ │ ├── page.html
│ │ │ ├── single.html
│ │ │ └── taxonomy.html
│ │ ├── blog/
│ │ │ ├── li.html
│ │ │ ├── list.html
│ │ │ ├── single.html
│ │ │ └── summary.html
│ │ ├── index.html
│ │ ├── indexes/
│ │ │ └── tag.html
│ │ ├── partials/
│ │ │ ├── blogauthor.html
│ │ │ ├── footer.html
│ │ │ ├── hanchor.html
│ │ │ ├── head.html
│ │ │ ├── hero.html
│ │ │ ├── intro.html
│ │ │ ├── mailinglist.html
│ │ │ ├── nav.html
│ │ │ ├── notification.html
│ │ │ ├── page-edit.html
│ │ │ ├── series_link.html
│ │ │ └── sidebar.html
│ │ └── shortcodes/
│ │ ├── baseurl.html
│ │ ├── bignumber.html
│ │ ├── blogurl.html
│ │ ├── content.html
│ │ ├── md.html
│ │ └── note.html
│ ├── static/
│ │ ├── css/
│ │ │ ├── bar.css
│ │ │ ├── code.css
│ │ │ ├── markdown.css
│ │ │ ├── note.css
│ │ │ ├── partials/
│ │ │ │ ├── banners.css
│ │ │ │ ├── base.css
│ │ │ │ ├── blog.css
│ │ │ │ ├── buttons.css
│ │ │ │ ├── fontawesome.css
│ │ │ │ ├── footer.css
│ │ │ │ ├── header.css
│ │ │ │ ├── homepage.css
│ │ │ │ ├── root.css
│ │ │ │ ├── sidebar.css
│ │ │ │ └── template-picker.css
│ │ │ ├── styles.css
│ │ │ └── tabs.css
│ │ ├── fonts/
│ │ │ └── FontAwesome.otf
│ │ ├── js/
│ │ │ ├── main.js
│ │ │ └── tabs.js
│ │ ├── lottie/
│ │ │ └── intro-section.json
│ │ └── robots.txt
│ └── themes/
│ ├── archetypes/
│ │ └── default.md
│ ├── config.toml
│ ├── content/
│ │ └── contribute/
│ │ └── _index.md
│ └── layouts/
│ ├── 404.html
│ ├── _default/
│ │ ├── list.html
│ │ └── single.html
│ ├── index.html
│ └── partials/
│ ├── about.html
│ ├── contact.html
│ ├── counters.html
│ ├── footer.html
│ ├── head.html
│ ├── hero.html
│ ├── intro.html
│ ├── js.html
│ ├── nav.html
│ ├── nav2.html
│ ├── services.html
│ ├── testimonials.html
│ └── work.html
└── win-wpf/
├── .gitignore
├── AppxManifest.xml
├── Focalboard/
│ ├── App.config
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Focalboard.csproj
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── Properties/
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── Utils.cs
│ ├── Webview2Installer.cs
│ └── packages.config
├── Focalboard.sln
├── README.md
├── build.bat
├── package-zip.bat
└── package.bat
Showing preview only (437K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4318 symbols across 607 files)
FILE: experiments/webext/src/utils/Board.ts
type BoardFields (line 1) | interface BoardFields {
type Board (line 5) | interface Board {
FILE: experiments/webext/src/utils/networking.ts
type Window (line 7) | interface Window {
function request (line 12) | async function request(method: string, host: string, resource: string, b...
function logIn (line 34) | async function logIn(host: string, username: string, password: string) {
function getBoards (line 39) | async function getBoards(host: string, token: string) {
function findUrlPropertyId (line 44) | async function findUrlPropertyId(host: string, token: string, boardId: s...
function createCard (line 59) | async function createCard(host: string, token: string, boardId: string, ...
function createGuid (line 87) | function createGuid(): string {
function randomArray (line 92) | function randomArray(size: number): Uint8Array {
function base32encode (line 107) | function base32encode(data: Int8Array | Uint8Array | Uint8ClampedArray, ...
FILE: experiments/webext/src/utils/settings.ts
type Settings (line 6) | interface Settings {
function loadSettings (line 13) | function loadSettings(): Settings {
function storeSettings (line 17) | function storeSettings(host: string, username: string, token: string | n...
function storeToken (line 22) | function storeToken(value: string | null) {
function storeBoardId (line 26) | function storeBoardId(value: string | null) {
FILE: experiments/webext/src/views/OptionsApp.tsx
function OptionsApp (line 12) | function OptionsApp() {
FILE: experiments/webext/src/views/PopupApp.tsx
function OptionsApp (line 13) | function OptionsApp() {
FILE: import/asana/asana.ts
type Asana (line 9) | interface Asana {
type Datum (line 13) | interface Datum {
type AssigneeStatus (line 45) | enum AssigneeStatus {
type CustomField (line 49) | interface CustomField {
type Enum (line 61) | interface Enum {
type Color (line 69) | enum Color {
type EnumOptionName (line 79) | enum EnumOptionName {
type EnumOptionResourceType (line 90) | enum EnumOptionResourceType {
type CustomFieldName (line 94) | enum CustomFieldName {
type Type (line 99) | enum Type {
type CustomFieldResourceType (line 103) | enum CustomFieldResourceType {
type Workspace (line 107) | interface Workspace {
type WorkspaceResourceType (line 113) | enum WorkspaceResourceType {
type Membership (line 121) | interface Membership {
type ResourceSubtype (line 126) | enum ResourceSubtype {
FILE: import/asana/importAsana.ts
function main (line 33) | function main() {
function getProjects (line 63) | function getProjects(input: Asana): Workspace[] {
function getSections (line 77) | function getSections(input: Asana, projectId: string): Workspace[] {
function convert (line 92) | function convert(input: Asana): [Board[], Block[]] {
function showHelp (line 186) | function showHelp() {
FILE: import/asana/utils.ts
class Utils (line 5) | class Utils {
method createGuid (line 6) | static createGuid(): string {
FILE: import/jira/importJira.ts
function main (line 7) | async function main() {
FILE: import/jira/jiraImporter.ts
function run (line 34) | async function run(inputFile: string, outputFile: string): Promise<numbe...
function convert (line 85) | function convert(items: any[]): [Board[], Block[]] {
function buildCardPropertyFromValues (line 186) | function buildCardPropertyFromValues(propertyName: string, allValues: st...
function setSelectProperty (line 218) | function setSelectProperty(card: Card, cardProperty: IPropertyTemplate, ...
function setProperty (line 225) | function setProperty(card: Card, cardPropertyId: string, propertyValue: ...
function optionForPropertyValue (line 229) | function optionForPropertyValue(cardProperty: IPropertyTemplate, propert...
function showHelp (line 239) | function showHelp() {
FILE: import/jira/utils.ts
class Utils (line 5) | class Utils {
method createGuid (line 6) | static createGuid(): string {
FILE: import/nextcloud-deck/deck.ts
type Board (line 14) | interface Board {
type Stack (line 34) | interface Stack {
type Card (line 44) | interface Card {
type CommentResponse (line 67) | interface CommentResponse {
type Comment (line 78) | interface Comment {
type Label (line 96) | interface Label {
type User (line 103) | interface User {
type NextcloudDeckClientConfig (line 109) | interface NextcloudDeckClientConfig {
type Auth (line 114) | interface Auth {
class NextcloudDeckClient (line 127) | class NextcloudDeckClient {
method constructor (line 134) | constructor(config: NextcloudDeckClientConfig) {
method fetchWrapper (line 138) | async fetchWrapper(path: string): Promise<any> {
method fetchWrapperOCS (line 152) | async fetchWrapperOCS(path: string): Promise<any> {
method getBoards (line 167) | async getBoards(): Promise<Board[]> {
method getBoardDetails (line 171) | async getBoardDetails(boardId: number): Promise<Board> {
method getStacks (line 176) | async getStacks(boardId: number): Promise<Stack[]> {
method getStacksArchived (line 181) | async getStacksArchived(boardId: number): Promise<Stack[]> {
method getStackDetails (line 186) | async getStackDetails(boardId: number, stackId: number): Promise<Stack> {
method getCardDetails (line 191) | async getCardDetails(boardId: number, stackId: number, cardId: number)...
method getComments (line 196) | async getComments(cardId: number): Promise<Comment[]> {
FILE: import/nextcloud-deck/importDeck.ts
function main (line 35) | async function main() {
function selectBoard (line 82) | async function selectBoard(deckClient: NextcloudDeckClient): Promise<num...
function convert (line 89) | function convert(deckBoard: Board, stacks: Stack[]): [FBBoard[], Block[]] {
function showHelp (line 217) | function showHelp() {
FILE: import/nextcloud-deck/utils.ts
class Utils (line 5) | class Utils {
method createGuid (line 6) | static createGuid(): string {
FILE: import/notion/importNotion.ts
function main (line 34) | async function main() {
function getCsvFilePath (line 84) | function getCsvFilePath(inputFolder: string): string | undefined {
function getMarkdown (line 91) | function getMarkdown(cardTitle: string): string | undefined {
function getColumns (line 114) | function getColumns(input: any[]) {
function convert (line 121) | function convert(input: any[], title: string): [Board[], Block[]] {
function showHelp (line 219) | function showHelp() {
FILE: import/notion/utils.ts
class Utils (line 3) | class Utils {
method createGuid (line 4) | static createGuid(): string {
FILE: import/todoist/importTodoist.ts
function main (line 41) | function main() {
function convert (line 77) | function convert(input: Todoist, project: Project): [Board[], Block[]] {
function getProjectColumns (line 165) | function getProjectColumns(input: Todoist, project: Project): Array<Sect...
function getProjectCards (line 175) | function getProjectCards(input: Todoist, project: Project): Array<Item> {
function getCardDescription (line 179) | function getCardDescription(input: Todoist, item: Item): Array<string> {
function showHelp (line 195) | function showHelp() {
FILE: import/todoist/todoist.ts
type Todoist (line 6) | interface Todoist {
type DayOrders (line 36) | interface DayOrders {
type Filter (line 39) | interface Filter {
type Item (line 49) | interface Item {
type Due (line 74) | interface Due {
type Note (line 82) | interface Note {
type FileAttachment (line 95) | interface FileAttachment {
type Project (line 107) | interface Project {
type Section (line 123) | interface Section {
type Stats (line 137) | interface Stats {
type DaysItem (line 143) | interface DaysItem {
type WeekItem (line 148) | interface WeekItem {
type Tooltips (line 154) | interface Tooltips {
type User (line 159) | interface User {
type Features (line 196) | interface Features {
type TzInfo (line 206) | interface TzInfo {
type UserPlanLimits (line 214) | interface UserPlanLimits {
type Current (line 219) | interface Current {
type UserSettings (line 246) | interface UserSettings {
FILE: import/todoist/utils.ts
class Utils (line 5) | class Utils {
method createGuid (line 6) | static createGuid(): string {
FILE: import/trello/importTrello.ts
function main (line 34) | function main() {
function convert (line 64) | function convert(input: Trello): [Board[], Block[]] {
function showHelp (line 171) | function showHelp() {
FILE: import/trello/trello.ts
type Trello (line 10) | interface Trello {
type Action (line 50) | interface Action {
type AppCreator (line 62) | interface AppCreator {
type Icon (line 68) | interface Icon {
type Data (line 72) | interface Data {
type Board (line 92) | interface Board {
type IDBoardEnum (line 99) | enum IDBoardEnum {
type BoardName (line 104) | enum BoardName {
type ShortLink (line 109) | enum ShortLink {
type BoardSource (line 114) | interface BoardSource {
type DataCard (line 118) | interface DataCard {
type OldCover (line 131) | interface OldCover {
type Brightness (line 140) | enum Brightness {
type IDUploadedBackground (line 145) | enum IDUploadedBackground {
type MemberType (line 151) | enum MemberType {
type IDMemberCreator (line 156) | enum IDMemberCreator {
type DataCheckItem (line 166) | interface DataCheckItem {
type ListClass (line 172) | interface ListClass {
type FullNameEnum (line 177) | enum FullNameEnum {
type DataCustomField (line 187) | interface DataCustomField {
type IDCustomFieldEnum (line 193) | enum IDCustomFieldEnum {
type CustomFieldItem (line 198) | interface CustomFieldItem {
type ModelType (line 206) | enum ModelType {
type CustomFieldItemValue (line 210) | interface CustomFieldItemValue {
type Old (line 215) | interface Old {
type OldValue (line 226) | interface OldValue {
type ActionLimits (line 230) | interface ActionLimits {
type Reactions (line 234) | interface Reactions {
type PerBoard (line 239) | interface PerBoard {
type Status (line 245) | enum Status {
type MemberCreatorClass (line 249) | interface MemberCreatorClass {
type AvatarHash (line 262) | enum AvatarHash {
type Initials (line 266) | enum Initials {
type NonPublic (line 270) | interface NonPublic {
type Username (line 276) | enum Username {
type CardElement (line 280) | interface CardElement {
type Attachment (line 322) | interface Attachment {
type Scaled (line 337) | interface Scaled {
type Badges (line 347) | interface Badges {
type AttachmentsByType (line 365) | interface AttachmentsByType {
type TrelloClass (line 369) | interface TrelloClass {
type PurpleCover (line 374) | interface PurpleCover {
type DescDataClass (line 386) | interface DescDataClass {
type Emoji (line 390) | interface Emoji {
type Label (line 393) | interface Label {
type CardLimits (line 400) | interface CardLimits {
type Stickers (line 406) | interface Stickers {
type ChecklistElement (line 410) | interface ChecklistElement {
type CheckItemElement (line 421) | interface CheckItemElement {
type ChecklistLimits (line 432) | interface ChecklistLimits {
type CheckItems (line 436) | interface CheckItems {
type CustomFieldElement (line 440) | interface CustomFieldElement {
type Display (line 452) | interface Display {
type LabelNames (line 456) | interface LabelNames {
type TrelloLimits (line 469) | interface TrelloLimits {
type Attachments (line 483) | interface Attachments {
type Boards (line 488) | interface Boards {
type PurpleCards (line 492) | interface PurpleCards {
type CustomFieldOptions (line 499) | interface CustomFieldOptions {
type CustomFields (line 503) | interface CustomFields {
type Lists (line 507) | interface Lists {
type List (line 512) | interface List {
type ListLimits (line 524) | interface ListLimits {
type FluffyCards (line 528) | interface FluffyCards {
type MemberElement (line 533) | interface MemberElement {
type Membership (line 556) | interface Membership {
type PluginDatum (line 564) | interface PluginDatum {
type Prefs (line 573) | interface Prefs {
type BackgroundImageScaled (line 598) | interface BackgroundImageScaled {
FILE: import/trello/utils.ts
class Utils (line 5) | class Utils {
method createGuid (line 6) | static createGuid(): string {
FILE: import/util/archive.ts
type ArchiveHeader (line 6) | interface ArchiveHeader {
type ArchiveLine (line 12) | interface ArchiveLine {
type BlockArchiveLine (line 17) | interface BlockArchiveLine extends ArchiveLine {
type BoardArchiveLine (line 22) | interface BoardArchiveLine extends ArchiveLine {
class ArchiveUtils (line 27) | class ArchiveUtils {
method buildBlockArchive (line 28) | static buildBlockArchive(boards: readonly Board[], blocks: readonly Bl...
method parseBlockArchive (line 60) | static parseBlockArchive(contents: string): Block[] {
FILE: linux/main.go
function getFreePort (line 24) | func getFreePort() (int, error) {
function runServer (line 38) | func runServer(port int) (*server.Server, error) {
function openBrowser (line 97) | func openBrowser(url string) {
function main (line 115) | func main() {
FILE: server/api/admin.go
type AdminSetPasswordData (line 16) | type AdminSetPasswordData struct
method handleAdminSetPassword (line 20) | func (a *API) handleAdminSetPassword(w http.ResponseWriter, r *http.Requ...
FILE: server/api/api.go
constant HeaderRequestedWith (line 20) | HeaderRequestedWith = "X-Requested-With"
constant HeaderRequestedWithXML (line 21) | HeaderRequestedWithXML = "XMLHttpRequest"
constant UploadFormFileKey (line 22) | UploadFormFileKey = "file"
constant True (line 23) | True = "true"
constant ErrorNoTeamCode (line 25) | ErrorNoTeamCode = 1000
constant ErrorNoTeamMessage (line 26) | ErrorNoTeamMessage = "No team"
type API (line 36) | type API struct
method RegisterRoutes (line 64) | func (a *API) RegisterRoutes(r *mux.Router) {
method RegisterAdminRoutes (line 104) | func (a *API) RegisterAdminRoutes(r *mux.Router) {
method panicHandler (line 117) | func (a *API) panicHandler(next http.Handler) http.Handler {
method requireCSRFToken (line 134) | func (a *API) requireCSRFToken(next http.Handler) http.Handler {
method checkCSRFToken (line 146) | func (a *API) checkCSRFToken(r *http.Request) bool {
method hasValidReadTokenForBoard (line 151) | func (a *API) hasValidReadTokenForBoard(r *http.Request, boardID strin...
method userIsGuest (line 168) | func (a *API) userIsGuest(userID string) (bool, error) {
method errorResponse (line 177) | func (a *API) errorResponse(w http.ResponseWriter, r *http.Request, er...
function NewAPI (line 46) | func NewAPI(
function getUserID (line 108) | func getUserID(r *http.Request) string {
function stringResponse (line 214) | func stringResponse(w http.ResponseWriter, message string) {
function jsonStringResponse (line 219) | func jsonStringResponse(w http.ResponseWriter, code int, message string)...
function jsonBytesResponse (line 225) | func jsonBytesResponse(w http.ResponseWriter, code int, json []byte) { /...
function setResponseHeader (line 231) | func setResponseHeader(w http.ResponseWriter, key string, value string) ...
FILE: server/api/api_test.go
function TestErrorResponse (line 16) | func TestErrorResponse(t *testing.T) {
FILE: server/api/archive.go
constant archiveExtension (line 17) | archiveExtension = ".boardarchive"
method registerAchivesRoutes (line 20) | func (a *API) registerAchivesRoutes(r *mux.Router) {
method handleArchiveExportBoard (line 27) | func (a *API) handleArchiveExportBoard(w http.ResponseWriter, r *http.Re...
method handleArchiveImport (line 97) | func (a *API) handleArchiveImport(w http.ResponseWriter, r *http.Request) {
method handleArchiveExportTeam (line 180) | func (a *API) handleArchiveExportTeam(w http.ResponseWriter, r *http.Req...
FILE: server/api/audit.go
method makeAuditRecord (line 11) | func (a *API) makeAuditRecord(r *http.Request, event string, initialStat...
FILE: server/api/auth.go
method registerAuthRoutes (line 20) | func (a *API) registerAuthRoutes(r *mux.Router) {
method handleLogin (line 29) | func (a *API) handleLogin(w http.ResponseWriter, r *http.Request) {
method handleLogout (line 106) | func (a *API) handleLogout(w http.ResponseWriter, r *http.Request) {
method handleRegister (line 153) | func (a *API) handleRegister(w http.ResponseWriter, r *http.Request) {
method handleChangePassword (line 247) | func (a *API) handleChangePassword(w http.ResponseWriter, r *http.Reques...
method sessionRequired (line 323) | func (a *API) sessionRequired(handler func(w http.ResponseWriter, r *htt...
method attachSession (line 327) | func (a *API) attachSession(handler func(w http.ResponseWriter, r *http....
method adminRequired (line 399) | func (a *API) adminRequired(handler func(w http.ResponseWriter, r *http....
FILE: server/api/blocks.go
method registerBlocksRoutes (line 17) | func (a *API) registerBlocksRoutes(r *mux.Router) {
method handleGetBlocks (line 28) | func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
method handlePostBlocks (line 174) | func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
method handleDeleteBlock (line 328) | func (a *API) handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
method handleUndeleteBlock (line 405) | func (a *API) handleUndeleteBlock(w http.ResponseWriter, r *http.Request) {
method handlePatchBlock (line 491) | func (a *API) handlePatchBlock(w http.ResponseWriter, r *http.Request) {
method handlePatchBlocks (line 586) | func (a *API) handlePatchBlocks(w http.ResponseWriter, r *http.Request) {
method handleDuplicateBlock (line 675) | func (a *API) handleDuplicateBlock(w http.ResponseWriter, r *http.Reques...
FILE: server/api/boards.go
method registerBoardsRoutes (line 15) | func (a *API) registerBoardsRoutes(r *mux.Router) {
method handleGetBoards (line 26) | func (a *API) handleGetBoards(w http.ResponseWriter, r *http.Request) {
method handleCreateBoard (line 97) | func (a *API) handleCreateBoard(w http.ResponseWriter, r *http.Request) {
method handleGetBoard (line 196) | func (a *API) handleGetBoard(w http.ResponseWriter, r *http.Request) {
method handlePatchBoard (line 286) | func (a *API) handlePatchBoard(w http.ResponseWriter, r *http.Request) {
method handleDeleteBoard (line 392) | func (a *API) handleDeleteBoard(w http.ResponseWriter, r *http.Request) {
method handleDuplicateBoard (line 447) | func (a *API) handleDuplicateBoard(w http.ResponseWriter, r *http.Reques...
method handleUndeleteBoard (line 554) | func (a *API) handleUndeleteBoard(w http.ResponseWriter, r *http.Request) {
method handleGetBoardMetadata (line 606) | func (a *API) handleGetBoardMetadata(w http.ResponseWriter, r *http.Requ...
FILE: server/api/boards_and_blocks.go
method registerBoardsAndBlocksRoutes (line 16) | func (a *API) registerBoardsAndBlocksRoutes(r *mux.Router) {
method handleCreateBoardsAndBlocks (line 23) | func (a *API) handleCreateBoardsAndBlocks(w http.ResponseWriter, r *http...
method handlePatchBoardsAndBlocks (line 173) | func (a *API) handlePatchBoardsAndBlocks(w http.ResponseWriter, r *http....
method handleDeleteBoardsAndBlocks (line 303) | func (a *API) handleDeleteBoardsAndBlocks(w http.ResponseWriter, r *http...
FILE: server/api/cards.go
constant defaultPage (line 18) | defaultPage = "0"
constant defaultPerPage (line 19) | defaultPerPage = "100"
method registerCardsRoutes (line 22) | func (a *API) registerCardsRoutes(r *mux.Router) {
method handleCreateCard (line 30) | func (a *API) handleCreateCard(w http.ResponseWriter, r *http.Request) {
method handleGetCards (line 130) | func (a *API) handleGetCards(w http.ResponseWriter, r *http.Request) {
method handlePatchCard (line 230) | func (a *API) handlePatchCard(w http.ResponseWriter, r *http.Request) {
method handleGetCard (line 327) | func (a *API) handleGetCard(w http.ResponseWriter, r *http.Request) {
FILE: server/api/categories.go
method registerCategoriesRoutes (line 14) | func (a *API) registerCategoriesRoutes(r *mux.Router) {
method handleCreateCategory (line 27) | func (a *API) handleCreateCategory(w http.ResponseWriter, r *http.Reques...
method handleUpdateCategory (line 116) | func (a *API) handleUpdateCategory(w http.ResponseWriter, r *http.Reques...
method handleDeleteCategory (line 213) | func (a *API) handleDeleteCategory(w http.ResponseWriter, r *http.Reques...
method handleGetUserCategoryBoards (line 274) | func (a *API) handleGetUserCategoryBoards(w http.ResponseWriter, r *http...
method handleUpdateCategoryBoard (line 333) | func (a *API) handleUpdateCategoryBoard(w http.ResponseWriter, r *http.R...
method handleReorderCategories (line 395) | func (a *API) handleReorderCategories(w http.ResponseWriter, r *http.Req...
method handleReorderCategoryBoards (line 467) | func (a *API) handleReorderCategoryBoards(w http.ResponseWriter, r *http...
method handleHideBoard (line 552) | func (a *API) handleHideBoard(w http.ResponseWriter, r *http.Request) {
method handleUnhideBoard (line 614) | func (a *API) handleUnhideBoard(w http.ResponseWriter, r *http.Request) {
FILE: server/api/channels.go
method registerChannelsRoutes (line 16) | func (a *API) registerChannelsRoutes(r *mux.Router) {
method handleGetChannel (line 20) | func (a *API) handleGetChannel(w http.ResponseWriter, r *http.Request) {
FILE: server/api/compliance.go
constant complianceDefaultPage (line 17) | complianceDefaultPage = "0"
constant complianceDefaultPerPage (line 18) | complianceDefaultPerPage = "60"
method registerComplianceRoutes (line 21) | func (a *API) registerComplianceRoutes(r *mux.Router) {
method handleGetBoardsForCompliance (line 28) | func (a *API) handleGetBoardsForCompliance(w http.ResponseWriter, r *htt...
method handleGetBoardsComplianceHistory (line 146) | func (a *API) handleGetBoardsComplianceHistory(w http.ResponseWriter, r ...
method handleGetBlocksComplianceHistory (line 289) | func (a *API) handleGetBlocksComplianceHistory(w http.ResponseWriter, r ...
FILE: server/api/config.go
method registerConfigRoutes (line 10) | func (a *API) registerConfigRoutes(r *mux.Router) {
method getClientConfig (line 15) | func (a *API) getClientConfig(w http.ResponseWriter, r *http.Request) {
FILE: server/api/content_blocks.go
method registerContentBlocksRoutes (line 11) | func (a *API) registerContentBlocksRoutes(r *mux.Router) {
method handleMoveBlockTo (line 16) | func (a *API) handleMoveBlockTo(w http.ResponseWriter, r *http.Request) {
FILE: server/api/context.go
type contextKey (line 9) | type contextKey
constant httpConnContextKey (line 12) | httpConnContextKey contextKey = iota
constant sessionContextKey (line 13) | sessionContextKey
function SetContextConn (line 17) | func SetContextConn(ctx context.Context, c net.Conn) context.Context {
function GetContextConn (line 22) | func GetContextConn(r *http.Request) net.Conn {
FILE: server/api/files.go
type FileUploadResponse (line 52) | type FileUploadResponse struct
function FileUploadResponseFromJSON (line 58) | func FileUploadResponseFromJSON(data io.Reader) (*FileUploadResponse, er...
function FileInfoResponseFromJSON (line 67) | func FileInfoResponseFromJSON(data io.Reader) (*mmModel.FileInfo, error) {
method registerFilesRoutes (line 76) | func (a *API) registerFilesRoutes(r *mux.Router) {
method handleServeFile (line 83) | func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
function writeFileResponse (line 189) | func writeFileResponse(filename string, contentType string, contentSize ...
method getFileInfo (line 247) | func (a *API) getFileInfo(w http.ResponseWriter, r *http.Request) {
method handleUploadFile (line 321) | func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
FILE: server/api/members.go
method registerMembersRoutes (line 14) | func (a *API) registerMembersRoutes(r *mux.Router) {
method handleGetMembersForBoard (line 24) | func (a *API) handleGetMembersForBoard(w http.ResponseWriter, r *http.Re...
method handleAddMember (line 87) | func (a *API) handleAddMember(w http.ResponseWriter, r *http.Request) {
method handleJoinBoard (line 195) | func (a *API) handleJoinBoard(w http.ResponseWriter, r *http.Request) {
method handleLeaveBoard (line 307) | func (a *API) handleLeaveBoard(w http.ResponseWriter, r *http.Request) {
method handleUpdateMember (line 375) | func (a *API) handleUpdateMember(w http.ResponseWriter, r *http.Request) {
method handleDeleteMember (line 480) | func (a *API) handleDeleteMember(w http.ResponseWriter, r *http.Request) {
FILE: server/api/onboarding.go
method registerOnboardingRoutes (line 11) | func (a *API) registerOnboardingRoutes(r *mux.Router) {
method handleOnboard (line 16) | func (a *API) handleOnboard(w http.ResponseWriter, r *http.Request) {
FILE: server/api/search.go
method registerSearchRoutes (line 14) | func (a *API) registerSearchRoutes(r *mux.Router) {
method handleSearchMyChannels (line 21) | func (a *API) handleSearchMyChannels(w http.ResponseWriter, r *http.Requ...
method handleSearchBoards (line 98) | func (a *API) handleSearchBoards(w http.ResponseWriter, r *http.Request) {
method handleSearchLinkableBoards (line 195) | func (a *API) handleSearchLinkableBoards(w http.ResponseWriter, r *http....
method handleSearchAllBoards (line 284) | func (a *API) handleSearchAllBoards(w http.ResponseWriter, r *http.Reque...
FILE: server/api/sharing.go
method registerSharingRoutes (line 18) | func (a *API) registerSharingRoutes(r *mux.Router) {
method handleGetSharing (line 24) | func (a *API) handleGetSharing(w http.ResponseWriter, r *http.Request) {
method handlePostSharing (line 89) | func (a *API) handlePostSharing(w http.ResponseWriter, r *http.Request) {
FILE: server/api/statistics.go
method registerStatisticsRoutes (line 12) | func (a *API) registerStatisticsRoutes(r *mux.Router) {
method handleStatistics (line 17) | func (a *API) handleStatistics(w http.ResponseWriter, r *http.Request) {
FILE: server/api/subscriptions.go
method registerSubscriptionsRoutes (line 16) | func (a *API) registerSubscriptionsRoutes(r *mux.Router) {
method handleCreateSubscription (line 25) | func (a *API) handleCreateSubscription(w http.ResponseWriter, r *http.Re...
method handleDeleteSubscription (line 113) | func (a *API) handleDeleteSubscription(w http.ResponseWriter, r *http.Re...
method handleGetSubscriptions (line 174) | func (a *API) handleGetSubscriptions(w http.ResponseWriter, r *http.Requ...
FILE: server/api/system.go
method registerSystemRoutes (line 10) | func (a *API) registerSystemRoutes(r *mux.Router) {
method handleHello (line 16) | func (a *API) handleHello(w http.ResponseWriter, r *http.Request) {
method handlePing (line 30) | func (a *API) handlePing(w http.ResponseWriter, r *http.Request) {
FILE: server/api/system_test.go
function TestHello (line 15) | func TestHello(t *testing.T) {
function TestPing (line 37) | func TestPing(t *testing.T) {
FILE: server/api/teams.go
method registerTeamsRoutes (line 14) | func (a *API) registerTeamsRoutes(r *mux.Router) {
method handleGetTeams (line 23) | func (a *API) handleGetTeams(w http.ResponseWriter, r *http.Request) {
method handleGetTeam (line 66) | func (a *API) handleGetTeam(w http.ResponseWriter, r *http.Request) {
method handlePostTeamRegenerateSignupToken (line 134) | func (a *API) handlePostTeamRegenerateSignupToken(w http.ResponseWriter,...
method handleGetTeamUsers (line 182) | func (a *API) handleGetTeamUsers(w http.ResponseWriter, r *http.Request) {
method handleGetTeamUsersByID (line 263) | func (a *API) handleGetTeamUsersByID(w http.ResponseWriter, r *http.Requ...
FILE: server/api/templates.go
method registerTemplatesRoutes (line 14) | func (a *API) registerTemplatesRoutes(r *mux.Router) {
method handleGetTemplates (line 18) | func (a *API) handleGetTemplates(w http.ResponseWriter, r *http.Request) {
FILE: server/api/users.go
method registerUsersRoutes (line 14) | func (a *API) registerUsersRoutes(r *mux.Router) {
method handleGetUsersList (line 24) | func (a *API) handleGetUsersList(w http.ResponseWriter, r *http.Request) {
method handleGetMe (line 124) | func (a *API) handleGetMe(w http.ResponseWriter, r *http.Request) {
method handleGetMyMemberships (line 207) | func (a *API) handleGetMyMemberships(w http.ResponseWriter, r *http.Requ...
method handleGetUser (line 252) | func (a *API) handleGetUser(w http.ResponseWriter, r *http.Request) {
method handleUpdateUserConfig (line 320) | func (a *API) handleUpdateUserConfig(w http.ResponseWriter, r *http.Requ...
method handleGetUserPreferences (line 394) | func (a *API) handleGetUserPreferences(w http.ResponseWriter, r *http.Re...
FILE: server/app/app.go
constant blockChangeNotifierQueueSize (line 24) | blockChangeNotifierQueueSize = 1000
constant blockChangeNotifierPoolSize (line 25) | blockChangeNotifierPoolSize = 10
constant blockChangeNotifierShutdownTimeout (line 26) | blockChangeNotifierShutdownTimeout = time.Second * 10
type servicesAPI (line 29) | type servicesAPI interface
type fileBackend (line 35) | type fileBackend interface
type Services (line 44) | type Services struct
type App (line 57) | type App struct
method SetConfig (line 75) | func (a *App) SetConfig(config *config.Configuration) {
method GetConfig (line 79) | func (a *App) GetConfig() *config.Configuration {
method CardLimit (line 102) | func (a *App) CardLimit() int {
method SetCardLimit (line 108) | func (a *App) SetCardLimit(cardLimit int) {
method GetLicense (line 114) | func (a *App) GetLicense() *mm_model.License {
function New (line 83) | func New(config *config.Configuration, wsAdapter ws.Adapter, services Se...
FILE: server/app/app_test.go
function TestSetConfig (line 10) | func TestSetConfig(t *testing.T) {
FILE: server/app/auth.go
constant DaysPerMonth (line 14) | DaysPerMonth = 30
constant DaysPerWeek (line 15) | DaysPerWeek = 7
constant HoursPerDay (line 16) | HoursPerDay = 24
constant MinutesPerHour (line 17) | MinutesPerHour = 60
constant SecondsPerMinute (line 18) | SecondsPerMinute = 60
method GetSession (line 22) | func (a *App) GetSession(token string) (*model.Session, error) {
method IsValidReadToken (line 27) | func (a *App) IsValidReadToken(boardID string, readToken string) (bool, ...
method GetRegisteredUserCount (line 32) | func (a *App) GetRegisteredUserCount() (int, error) {
method GetDailyActiveUsers (line 37) | func (a *App) GetDailyActiveUsers() (int, error) {
method GetWeeklyActiveUsers (line 43) | func (a *App) GetWeeklyActiveUsers() (int, error) {
method GetMonthlyActiveUsers (line 49) | func (a *App) GetMonthlyActiveUsers() (int, error) {
method GetUser (line 55) | func (a *App) GetUser(id string) (*model.User, error) {
method GetUsersList (line 67) | func (a *App) GetUsersList(userIDs []string) ([]*model.User, error) {
method Login (line 80) | func (a *App) Login(username, email, password, mfaToken string) (string,...
method Logout (line 135) | func (a *App) Logout(sessionID string) error {
method RegisterUser (line 147) | func (a *App) RegisterUser(username, email, password string) error {
method UpdateUserPassword (line 197) | func (a *App) UpdateUserPassword(username, password string) error {
method ChangePassword (line 206) | func (a *App) ChangePassword(userID, oldPassword, newPassword string) er...
FILE: server/app/auth_test.go
function TestLogin (line 21) | func TestLogin(t *testing.T) {
function TestGetUser (line 60) | func TestGetUser(t *testing.T) {
function TestRegisterUser (line 90) | func TestRegisterUser(t *testing.T) {
function TestUpdateUserPassword (line 126) | func TestUpdateUserPassword(t *testing.T) {
function TestChangePassword (line 157) | func TestChangePassword(t *testing.T) {
FILE: server/app/blocks.go
method GetBlocks (line 15) | func (a *App) GetBlocks(boardID, parentID string, blockType string) ([]*...
method DuplicateBlock (line 31) | func (a *App) DuplicateBlock(boardID string, blockID string, userID stri...
method PatchBlock (line 60) | func (a *App) PatchBlock(blockID string, blockPatch *model.BlockPatch, m...
method PatchBlockAndNotify (line 64) | func (a *App) PatchBlockAndNotify(blockID string, blockPatch *model.Bloc...
method PatchBlocks (line 101) | func (a *App) PatchBlocks(teamID string, blockPatches *model.BlockPatchB...
method PatchBlocksAndNotify (line 105) | func (a *App) PatchBlocksAndNotify(teamID string, blockPatches *model.Bl...
method InsertBlock (line 133) | func (a *App) InsertBlock(block *model.Block, modifiedByID string) error {
method InsertBlockAndNotify (line 137) | func (a *App) InsertBlockAndNotify(block *model.Block, modifiedByID stri...
method InsertBlocks (line 159) | func (a *App) InsertBlocks(blocks []*model.Block, modifiedByID string) (...
method InsertBlocksAndNotify (line 163) | func (a *App) InsertBlocksAndNotify(blocks []*model.Block, modifiedByID ...
method GetBlockByID (line 207) | func (a *App) GetBlockByID(blockID string) (*model.Block, error) {
method DeleteBlock (line 211) | func (a *App) DeleteBlock(blockID string, modifiedBy string) error {
method DeleteBlockAndNotify (line 215) | func (a *App) DeleteBlockAndNotify(blockID string, modifiedBy string, di...
method GetLastBlockHistoryEntry (line 248) | func (a *App) GetLastBlockHistoryEntry(blockID string) (*model.Block, er...
method UndeleteBlock (line 259) | func (a *App) UndeleteBlock(blockID string, modifiedBy string) (*model.B...
method GetBlockCountsByType (line 301) | func (a *App) GetBlockCountsByType() (map[string]int64, error) {
method GetBlocksForBoard (line 305) | func (a *App) GetBlocksForBoard(boardID string) ([]*model.Block, error) {
method notifyBlockChanged (line 309) | func (a *App) notifyBlockChanged(action notify.Action, block *model.Bloc...
constant maxSearchDepth (line 344) | maxSearchDepth = 50
method getBoardAndCard (line 349) | func (a *App) getBoardAndCard(block *model.Block) (board *model.Board, c...
FILE: server/app/blocks_test.go
type blockError (line 15) | type blockError struct
method Error (line 19) | func (be blockError) Error() string {
function TestInsertBlock (line 23) | func TestInsertBlock(t *testing.T) {
function TestPatchBlocks (line 49) | func TestPatchBlocks(t *testing.T) {
function TestDeleteBlock (line 116) | func TestDeleteBlock(t *testing.T) {
function TestUndeleteBlock (line 150) | func TestUndeleteBlock(t *testing.T) {
function TestInsertBlocks (line 187) | func TestInsertBlocks(t *testing.T) {
FILE: server/app/boards.go
constant linkBoardMessage (line 21) | linkBoardMessage = "@%s linked the board [%s](%s) with this channel"
constant unlinkBoardMessage (line 22) | unlinkBoardMessage = "@%s unlinked the board [%s](%s) with this channel"
method GetBoard (line 26) | func (a *App) GetBoard(boardID string) (*model.Board, error) {
method GetBoardCount (line 34) | func (a *App) GetBoardCount() (int64, error) {
method GetBoardMetadata (line 38) | func (a *App) GetBoardMetadata(boardID string) (*model.Board, *model.Boa...
method getBoardForBlock (line 77) | func (a *App) getBoardForBlock(blockID string) (*model.Board, error) {
method getBoardHistory (line 91) | func (a *App) getBoardHistory(boardID string, latest bool) (*model.Board...
method getBoardDescendantModifiedInfo (line 107) | func (a *App) getBoardDescendantModifiedInfo(boardID string, latest bool...
method setBoardCategoryFromSource (line 147) | func (a *App) setBoardCategoryFromSource(sourceBoardID, destinationBoard...
method DuplicateBoard (line 181) | func (a *App) DuplicateBoard(boardID, userID, toTeam string, asTemplate ...
method GetBoardsForUserAndTeam (line 225) | func (a *App) GetBoardsForUserAndTeam(userID, teamID string, includePubl...
method GetTemplateBoards (line 229) | func (a *App) GetTemplateBoards(teamID, userID string) ([]*model.Board, ...
method CreateBoard (line 233) | func (a *App) CreateBoard(board *model.Board, userID string, addMember b...
method addBoardsToDefaultCategory (line 278) | func (a *App) addBoardsToDefaultCategory(userID, teamID string, boards [...
method PatchBoard (line 308) | func (a *App) PatchBoard(patch *model.BoardPatch, boardID, userID string...
method postChannelMessage (line 411) | func (a *App) postChannelMessage(message, channelID string) {
method broadcastTeamUsers (line 420) | func (a *App) broadcastTeamUsers(teamID, boardID string, boardType model...
method DeleteBoard (line 443) | func (a *App) DeleteBoard(boardID, userID string) error {
method GetMembersForBoard (line 464) | func (a *App) GetMembersForBoard(boardID string) ([]*model.BoardMember, ...
method GetMembersForUser (line 486) | func (a *App) GetMembersForUser(userID string) ([]*model.BoardMember, er...
method GetMemberForBoard (line 509) | func (a *App) GetMemberForBoard(boardID string, userID string) (*model.B...
method AddMemberToBoard (line 513) | func (a *App) AddMemberToBoard(member *model.BoardMember) (*model.BoardM...
method UpdateBoardMember (line 558) | func (a *App) UpdateBoardMember(member *model.BoardMember) (*model.Board...
method isLastAdmin (line 600) | func (a *App) isLastAdmin(userID, boardID string) (bool, error) {
method DeleteBoardMember (line 614) | func (a *App) DeleteBoardMember(boardID, userID string) error {
method SearchBoardsForUser (line 659) | func (a *App) SearchBoardsForUser(term string, searchField model.BoardSe...
method SearchBoardsForUserInTeam (line 663) | func (a *App) SearchBoardsForUserInTeam(teamID, term, userID string) ([]...
method UndeleteBoard (line 667) | func (a *App) UndeleteBoard(boardID string, modifiedBy string) error {
FILE: server/app/boards_and_blocks.go
method CreateBoardsAndBlocks (line 10) | func (a *App) CreateBoardsAndBlocks(bab *model.BoardsAndBlocks, userID s...
method PatchBoardsAndBlocks (line 58) | func (a *App) PatchBoardsAndBlocks(pbab *model.PatchBoardsAndBlocks, use...
method DeleteBoardsAndBlocks (line 100) | func (a *App) DeleteBoardsAndBlocks(dbab *model.DeleteBoardsAndBlocks, u...
FILE: server/app/boards_test.go
function TestAddMemberToBoard (line 15) | func TestAddMemberToBoard(t *testing.T) {
function TestPatchBoard (line 138) | func TestPatchBoard(t *testing.T) {
function TestGetBoardCount (line 503) | func TestGetBoardCount(t *testing.T) {
function TestBoardCategory (line 517) | func TestBoardCategory(t *testing.T) {
function TestDuplicateBoard (line 590) | func TestDuplicateBoard(t *testing.T) {
function TestGetMembersForBoard (line 677) | func TestGetMembersForBoard(t *testing.T) {
function TestGetMembersForUser (line 725) | func TestGetMembersForUser(t *testing.T) {
FILE: server/app/cards.go
method CreateCard (line 13) | func (a *App) CreateCard(card *model.Card, boardID string, userID string...
method GetCardsForBoard (line 40) | func (a *App) GetCardsForBoard(boardID string, page int, perPage int) ([...
method PatchCard (line 65) | func (a *App) PatchCard(cardPatch *model.CardPatch, cardID string, userI...
method GetCardByID (line 84) | func (a *App) GetCardByID(cardID string) (*model.Card, error) {
FILE: server/app/cards_test.go
function TestCreateCard (line 15) | func TestCreateCard(t *testing.T) {
function TestGetCards (line 61) | func TestGetCards(t *testing.T) {
function TestPatchCard (line 112) | func TestPatchCard(t *testing.T) {
function TestGetCard (line 175) | func TestGetCard(t *testing.T) {
function reverse (line 236) | func reverse(src []string) []string {
function makeProps (line 244) | func makeProps(count int) map[string]any {
function copyProps (line 252) | func copyProps(m map[string]any) map[string]any {
function modifyProps (line 260) | func modifyProps(m map[string]any) map[string]any {
FILE: server/app/category.go
method GetCategory (line 16) | func (a *App) GetCategory(categoryID string) (*model.Category, error) {
method CreateCategory (line 20) | func (a *App) CreateCategory(category *model.Category) (*model.Category,...
method UpdateCategory (line 42) | func (a *App) UpdateCategory(category *model.Category) (*model.Category,...
method DeleteCategory (line 96) | func (a *App) DeleteCategory(categoryID, userID, teamID string) (*model....
method moveBoardsToDefaultCategory (line 142) | func (a *App) moveBoardsToDefaultCategory(userID, teamID, sourceCategory...
method ReorderCategories (line 193) | func (a *App) ReorderCategories(userID, teamID string, newCategoryOrder ...
method verifyNewCategoriesMatchExisting (line 210) | func (a *App) verifyNewCategoriesMatchExisting(userID, teamID string, ne...
FILE: server/app/category_boards.go
constant defaultCategoryBoards (line 10) | defaultCategoryBoards = "Boards"
method GetUserCategoryBoards (line 16) | func (a *App) GetUserCategoryBoards(userID, teamID string) ([]model.Cate...
method createDefaultCategoriesIfRequired (line 31) | func (a *App) createDefaultCategoriesIfRequired(existingCategoryBoards [...
method createBoardsCategory (line 53) | func (a *App) createBoardsCategory(userID, teamID string, existingCatego...
method AddUpdateUserCategoryBoard (line 145) | func (a *App) AddUpdateUserCategoryBoard(teamID, userID, categoryID stri...
method ReorderCategoryBoards (line 195) | func (a *App) ReorderCategoryBoards(userID, teamID, categoryID string, n...
method verifyNewCategoryBoardsMatchExisting (line 212) | func (a *App) verifyNewCategoryBoardsMatchExisting(userID, teamID, categ...
method SetBoardVisibility (line 265) | func (a *App) SetBoardVisibility(teamID, userID, categoryID, boardID str...
FILE: server/app/category_boards_test.go
function TestGetUserCategoryBoards (line 12) | func TestGetUserCategoryBoards(t *testing.T) {
function TestCreateBoardsCategory (line 111) | func TestCreateBoardsCategory(t *testing.T) {
function TestReorderCategoryBoards (line 276) | func TestReorderCategoryBoards(t *testing.T) {
FILE: server/app/category_test.go
function TestCreateCategory (line 11) | func TestCreateCategory(t *testing.T) {
function TestUpdateCategory (line 63) | func TestUpdateCategory(t *testing.T) {
function TestDeleteCategory (line 252) | func TestDeleteCategory(t *testing.T) {
function TestMoveBoardsToDefaultCategory (line 330) | func TestMoveBoardsToDefaultCategory(t *testing.T) {
function TestReorderCategories (line 381) | func TestReorderCategories(t *testing.T) {
function TestVerifyNewCategoriesMatchExisting (line 437) | func TestVerifyNewCategoriesMatchExisting(t *testing.T) {
FILE: server/app/clientConfig.go
method GetClientConfig (line 7) | func (a *App) GetClientConfig() *model.ClientConfig {
FILE: server/app/clientConfig_test.go
function TestGetClientConfig (line 10) | func TestGetClientConfig(t *testing.T) {
FILE: server/app/compliance.go
method GetBoardsForCompliance (line 5) | func (a *App) GetBoardsForCompliance(opts model.QueryBoardsForCompliance...
method GetBoardsComplianceHistory (line 9) | func (a *App) GetBoardsComplianceHistory(opts model.QueryBoardsComplianc...
method GetBlocksComplianceHistory (line 13) | func (a *App) GetBlocksComplianceHistory(opts model.QueryBlocksComplianc...
FILE: server/app/content_blocks.go
method MoveContentBlock (line 10) | func (a *App) MoveContentBlock(block *model.Block, dstBlock *model.Block...
FILE: server/app/content_blocks_test.go
type contentOrderMatcher (line 14) | type contentOrderMatcher struct
method Matches (line 22) | func (com contentOrderMatcher) Matches(x interface{}) bool {
method String (line 50) | func (com contentOrderMatcher) String() string {
function NewContentOrderMatcher (line 18) | func NewContentOrderMatcher(contentOrder []string) contentOrderMatcher {
function TestMoveContentBlock (line 54) | func TestMoveContentBlock(t *testing.T) {
FILE: server/app/export.go
method ExportArchive (line 19) | func (a *App) ExportArchive(w io.Writer, opt model.ExportArchiveOptions)...
method writeArchiveVersion (line 51) | func (a *App) writeArchiveVersion(zw *zip.Writer) error {
method writeArchiveBoard (line 70) | func (a *App) writeArchiveBoard(zw *zip.Writer, board model.Board, opt m...
method writeArchiveBoardMemberLine (line 124) | func (a *App) writeArchiveBoardMemberLine(w io.Writer, boardMember *mode...
method writeArchiveBlockLine (line 149) | func (a *App) writeArchiveBlockLine(w io.Writer, block *model.Block) err...
method writeArchiveBoardLine (line 175) | func (a *App) writeArchiveBoardLine(w io.Writer, board model.Board) error {
method writeArchiveFile (line 201) | func (a *App) writeArchiveFile(zw *zip.Writer, filename string, boardID ...
method getBoardsForArchive (line 227) | func (a *App) getBoardsForArchive(boardIDs []string) ([]model.Board, err...
function extractFilename (line 241) | func extractFilename(block *model.Block) (string, error) {
FILE: server/app/files.go
constant emptyString (line 18) | emptyString = "empty"
method SaveFile (line 23) | func (a *App) SaveFile(reader io.Reader, teamID, boardID, filename strin...
method GetFileInfo (line 55) | func (a *App) GetFileInfo(filename string) (*mm_model.FileInfo, error) {
method GetFile (line 73) | func (a *App) GetFile(teamID, rootID, fileName string) (*mm_model.FileIn...
method GetFilePath (line 99) | func (a *App) GetFilePath(teamID, rootID, fileName string) (*mm_model.Fi...
function getDestinationFilePath (line 116) | func getDestinationFilePath(isTemplate bool, teamID, boardID, filename s...
function getFileInfoID (line 126) | func getFileInfoID(fileName string) string {
method GetFileReader (line 132) | func (a *App) GetFileReader(teamID, rootID, filename string) (filestore....
method MoveFile (line 171) | func (a *App) MoveFile(channelID, teamID, boardID, filename string) error {
method CopyAndUpdateCardFiles (line 185) | func (a *App) CopyAndUpdateCardFiles(boardID, userID string, blocks []*m...
method CopyCardFiles (line 222) | func (a *App) CopyCardFiles(sourceBoardID string, copiedBlocks []*model....
FILE: server/app/files_test.go
constant testFileName (line 23) | testFileName = "temp-file-name"
constant testBoardID (line 24) | testBoardID = "test-board-id"
constant testPath (line 25) | testPath = "/path/to/file/fileName.txt"
type TestError (line 30) | type TestError struct
method Error (line 32) | func (err *TestError) Error() string { return "Mocked File backend err...
function TestGetFileReader (line 34) | func TestGetFileReader(t *testing.T) {
function TestSaveFile (line 190) | func TestSaveFile(t *testing.T) {
function TestGetFileInfo (line 266) | func TestGetFileInfo(t *testing.T) {
function TestGetFile (line 311) | func TestGetFile(t *testing.T) {
function TestGetFilePath (line 380) | func TestGetFilePath(t *testing.T) {
function TestCopyCard (line 417) | func TestCopyCard(t *testing.T) {
function TestCopyAndUpdateCardFiles (line 517) | func TestCopyAndUpdateCardFiles(t *testing.T) {
FILE: server/app/helper_test.go
type TestHelper (line 24) | type TestHelper struct
function SetupTestHelper (line 32) | func SetupTestHelper(t *testing.T) (*TestHelper, func()) {
FILE: server/app/import.go
constant archiveVersion (line 23) | archiveVersion = 2
constant legacyFileBegin (line 24) | legacyFileBegin = "{\"version\":1"
constant importMaxFileSize (line 25) | importMaxFileSize = 1024 * 1024 * 70
method ImportArchive (line 38) | func (a *App) ImportArchive(r io.Reader, opt model.ImportArchiveOptions)...
method fixImagesAttachments (line 110) | func (a *App) fixImagesAttachments(boardMap map[string]*model.Board, fil...
method ImportBoardJSONL (line 151) | func (a *App) ImportBoardJSONL(r io.Reader, opt model.ImportArchiveOptio...
method fixBoardsandBlocks (line 307) | func (a *App) fixBoardsandBlocks(boardsAndBlocks *model.BoardsAndBlocks,...
method blockToBoard (line 344) | func (a *App) blockToBoard(block *model.Block, opt model.ImportArchiveOp...
function stringValue (line 387) | func stringValue(m map[string]interface{}, key string) (string, bool) {
function boolValue (line 399) | func boolValue(m map[string]interface{}, key string) (bool, bool) {
function intValue (line 411) | func intValue(m map[string]interface{}, key string) (int, bool) {
function mapValue (line 423) | func mapValue(m map[string]interface{}, key string) (map[string]interfac...
function arrayMapsValue (line 435) | func arrayMapsValue(m map[string]interface{}, key string) ([]map[string]...
function parseVersionFile (line 456) | func parseVersionFile(r io.Reader) (int, error) {
FILE: server/app/import_test.go
function TestApp_ImportArchive (line 14) | func TestApp_ImportArchive(t *testing.T) {
constant asana (line 211) | asana = `{"version":1,"date":1614714686842}
constant boardArchive (line 226) | boardArchive = `{"type":"board","data":{"id":"bfoi6yy6pa3yzika53spj7pq9e...
FILE: server/app/initialize.go
method initialize (line 10) | func (a *App) initialize(skipTemplateInit bool) {
method Shutdown (line 18) | func (a *App) Shutdown() {
FILE: server/app/onboarding.go
constant KeyOnboardingTourStarted (line 10) | KeyOnboardingTourStarted = "onboardingTourStarted"
constant KeyOnboardingTourCategory (line 11) | KeyOnboardingTourCategory = "tourCategory"
constant KeyOnboardingTourStep (line 12) | KeyOnboardingTourStep = "onboardingTourStep"
constant ValueOnboardingFirstStep (line 14) | ValueOnboardingFirstStep = "0"
constant ValueTourCategoryOnboarding (line 15) | ValueTourCategoryOnboarding = "onboarding"
constant WelcomeBoardTitle (line 17) | WelcomeBoardTitle = "Welcome to Boards!"
method PrepareOnboardingTour (line 25) | func (a *App) PrepareOnboardingTour(userID string, teamID string) (strin...
method getOnboardingBoardID (line 47) | func (a *App) getOnboardingBoardID() (string, error) {
method createWelcomeBoard (line 68) | func (a *App) createWelcomeBoard(userID, teamID string) (string, error) {
FILE: server/app/onboarding_test.go
constant testTeamID (line 13) | testTeamID = "team_id"
function TestPrepareOnboardingTour (line 16) | func TestPrepareOnboardingTour(t *testing.T) {
function TestCreateWelcomeBoard (line 90) | func TestCreateWelcomeBoard(t *testing.T) {
function TestGetOnboardingBoardID (line 154) | func TestGetOnboardingBoardID(t *testing.T) {
FILE: server/app/permissions.go
method HasPermissionToBoard (line 7) | func (a *App) HasPermissionToBoard(userID, boardID string, permission *m...
FILE: server/app/server_metadata.go
type ServerMetadata (line 9) | type ServerMetadata struct
method GetServerMetadata (line 22) | func (a *App) GetServerMetadata() *ServerMetadata {
FILE: server/app/server_metadata_test.go
function TestGetServerMetadata (line 11) | func TestGetServerMetadata(t *testing.T) {
FILE: server/app/sharing.go
method GetSharing (line 7) | func (a *App) GetSharing(boardID string) (*model.Sharing, error) {
method UpsertSharing (line 15) | func (a *App) UpsertSharing(sharing model.Sharing) error {
FILE: server/app/sharing_test.go
function TestGetSharing (line 13) | func TestGetSharing(t *testing.T) {
function TestUpsertSharing (line 58) | func TestUpsertSharing(t *testing.T) {
FILE: server/app/statistics.go
method GetUsedCardsCount (line 6) | func (a *App) GetUsedCardsCount() (int, error) {
FILE: server/app/subscriptions.go
method CreateSubscription (line 10) | func (a *App) CreateSubscription(sub *model.Subscription) (*model.Subscr...
method DeleteSubscription (line 20) | func (a *App) DeleteSubscription(blockID string, subscriberID string) (*...
method GetSubscriptions (line 34) | func (a *App) GetSubscriptions(subscriberID string) ([]*model.Subscripti...
method notifySubscriptionChanged (line 38) | func (a *App) notifySubscriptionChanged(subscription *model.Subscription) {
FILE: server/app/teams.go
method GetRootTeam (line 10) | func (a *App) GetRootTeam() (*model.Team, error) {
method GetTeam (line 36) | func (a *App) GetTeam(id string) (*model.Team, error) {
method GetTeamsForUser (line 47) | func (a *App) GetTeamsForUser(userID string) ([]*model.Team, error) {
method DoesUserHaveTeamAccess (line 51) | func (a *App) DoesUserHaveTeamAccess(userID string, teamID string) bool {
method UpsertTeamSettings (line 55) | func (a *App) UpsertTeamSettings(team model.Team) error {
method UpsertTeamSignupToken (line 59) | func (a *App) UpsertTeamSignupToken(team model.Team) error {
method GetTeamCount (line 63) | func (a *App) GetTeamCount() (int64, error) {
FILE: server/app/teams_test.go
function TestGetRootTeam (line 23) | func TestGetRootTeam(t *testing.T) {
function TestGetTeam (line 87) | func TestGetTeam(t *testing.T) {
function TestTeamOperations (line 137) | func TestTeamOperations(t *testing.T) {
FILE: server/app/templates.go
constant defaultTemplateVersion (line 15) | defaultTemplateVersion = 6
method InitTemplates (line 18) | func (a *App) InitTemplates() error {
method initializeTemplates (line 24) | func (a *App) initializeTemplates() (bool, error) {
method isInitializationNeeded (line 64) | func (a *App) isInitializationNeeded(boards []*model.Board) (bool, strin...
function fixTemplateBlock (line 83) | func fixTemplateBlock(block *model.Block, cache map[string]interface{}) ...
function fixTemplateBoard (line 98) | func fixTemplateBoard(board *model.Board, cache map[string]interface{}) ...
FILE: server/app/templates_test.go
function TestApp_initializeTemplates (line 14) | func TestApp_initializeTemplates(t *testing.T) {
FILE: server/app/user.go
method GetTeamUsers (line 8) | func (a *App) GetTeamUsers(teamID string, asGuestID string) ([]*model.Us...
method SearchTeamUsers (line 12) | func (a *App) SearchTeamUsers(teamID string, searchQuery string, asGuest...
method UpdateUserConfig (line 29) | func (a *App) UpdateUserConfig(userID string, patch model.UserPreference...
method GetUserPreferences (line 38) | func (a *App) GetUserPreferences(userID string) ([]mmModel.Preference, e...
method UserIsGuest (line 42) | func (a *App) UserIsGuest(userID string) (bool, error) {
method CanSeeUser (line 50) | func (a *App) CanSeeUser(seerUser string, seenUser string) (bool, error) {
method SearchUserChannels (line 65) | func (a *App) SearchUserChannels(teamID string, userID string, query str...
method GetChannel (line 80) | func (a *App) GetChannel(teamID string, channelID string) (*mmModel.Chan...
method SanitizeProfile (line 84) | func (a *App) SanitizeProfile(user *model.User, isAdmin bool) {
FILE: server/app/user_test.go
function TestSearchUsers (line 11) | func TestSearchUsers(t *testing.T) {
FILE: server/assets/build-template-archive/main.go
constant defArchiveFilename (line 14) | defArchiveFilename = "templates.boardarchive"
constant versionFilename (line 15) | versionFilename = "version.json"
constant boardFilename (line 16) | boardFilename = "board.jsonl"
constant minArchiveVersion (line 17) | minArchiveVersion = 2
constant maxArchiveVersion (line 18) | maxArchiveVersion = 2
type archiveVersion (line 21) | type archiveVersion struct
type appConfig (line 26) | type appConfig struct
function main (line 32) | func main() {
function build (line 56) | func build(cfg appConfig) (err error) {
function getVersionFile (line 109) | func getVersionFile(cfg appConfig) ([]byte, error) {
function writeBoard (line 128) | func writeBoard(w *zip.Writer, boardID string, cfg appConfig) error {
function writeFile (line 161) | func writeFile(w *zip.Writer, srcPath string, destPath string, cfg appCo...
type errUnsupportedVersion (line 184) | type errUnsupportedVersion struct
method Error (line 190) | func (e errUnsupportedVersion) Error() string {
FILE: server/auth/auth.go
type AuthInterface (line 13) | type AuthInterface interface
type Auth (line 20) | type Auth struct
method GetSession (line 32) | func (a *Auth) GetSession(token string) (*model.Session, error) {
method IsValidReadToken (line 48) | func (a *Auth) IsValidReadToken(boardID string, readToken string) (boo...
method DoesUserHaveTeamAccess (line 68) | func (a *Auth) DoesUserHaveTeamAccess(userID string, teamID string) bo...
function New (line 27) | func New(config *config.Configuration, store store.Store, permissions pe...
FILE: server/auth/auth_test.go
type TestHelper (line 19) | type TestHelper struct
function setupTestHelper (line 33) | func setupTestHelper(t *testing.T) *TestHelper {
function TestGetSession (line 55) | func TestGetSession(t *testing.T) {
function TestIsValidReadToken (line 90) | func TestIsValidReadToken(t *testing.T) {
FILE: server/auth/mocks/mockauth_interface.go
type MockAuthInterface (line 15) | type MockAuthInterface struct
method EXPECT (line 33) | func (m *MockAuthInterface) EXPECT() *MockAuthInterfaceMockRecorder {
method DoesUserHaveTeamAccess (line 38) | func (m *MockAuthInterface) DoesUserHaveTeamAccess(arg0, arg1 string) ...
method GetSession (line 52) | func (m *MockAuthInterface) GetSession(arg0 string) (*model.Session, e...
method IsValidReadToken (line 67) | func (m *MockAuthInterface) IsValidReadToken(arg0, arg1 string) (bool,...
type MockAuthInterfaceMockRecorder (line 21) | type MockAuthInterfaceMockRecorder struct
method DoesUserHaveTeamAccess (line 46) | func (mr *MockAuthInterfaceMockRecorder) DoesUserHaveTeamAccess(arg0, ...
method GetSession (line 61) | func (mr *MockAuthInterfaceMockRecorder) GetSession(arg0 interface{}) ...
method IsValidReadToken (line 76) | func (mr *MockAuthInterfaceMockRecorder) IsValidReadToken(arg0, arg1 i...
function NewMockAuthInterface (line 26) | func NewMockAuthInterface(ctrl *gomock.Controller) *MockAuthInterface {
FILE: server/client/client.go
constant APIURLSuffix (line 19) | APIURLSuffix = "/api/v2"
type RequestReaderError (line 22) | type RequestReaderError struct
method Error (line 26) | func (rre RequestReaderError) Error() string {
type Response (line 30) | type Response struct
function BuildResponse (line 36) | func BuildResponse(r *http.Response) *Response {
function BuildErrorResponse (line 43) | func BuildErrorResponse(r *http.Response, err error) *Response {
function closeBody (line 58) | func closeBody(r *http.Response) {
function toJSON (line 65) | func toJSON(v interface{}) string {
type Client (line 70) | type Client struct
method DoAPIGet (line 89) | func (c *Client) DoAPIGet(url, etag string) (*http.Response, error) {
method DoAPIPost (line 93) | func (c *Client) DoAPIPost(url, data string) (*http.Response, error) {
method DoAPIPatch (line 97) | func (c *Client) DoAPIPatch(url, data string) (*http.Response, error) {
method DoAPIPut (line 101) | func (c *Client) DoAPIPut(url, data string) (*http.Response, error) {
method DoAPIDelete (line 105) | func (c *Client) DoAPIDelete(url string, data string) (*http.Response,...
method DoAPIRequest (line 109) | func (c *Client) DoAPIRequest(method, url, data, etag string) (*http.R...
method doAPIRequestReader (line 115) | func (c *Client) doAPIRequestReader(method, url string, data io.Reader...
method GetTeamRoute (line 156) | func (c *Client) GetTeamRoute(teamID string) string {
method GetTeamsRoute (line 160) | func (c *Client) GetTeamsRoute() string {
method GetBlockRoute (line 164) | func (c *Client) GetBlockRoute(boardID, blockID string) string {
method GetBoardsRoute (line 168) | func (c *Client) GetBoardsRoute() string {
method GetBoardRoute (line 172) | func (c *Client) GetBoardRoute(boardID string) string {
method GetBoardMetadataRoute (line 176) | func (c *Client) GetBoardMetadataRoute(boardID string) string {
method GetJoinBoardRoute (line 180) | func (c *Client) GetJoinBoardRoute(boardID string) string {
method GetLeaveBoardRoute (line 184) | func (c *Client) GetLeaveBoardRoute(boardID string) string {
method GetBlocksRoute (line 188) | func (c *Client) GetBlocksRoute(boardID string) string {
method GetAllBlocksRoute (line 192) | func (c *Client) GetAllBlocksRoute(boardID string) string {
method GetBoardsAndBlocksRoute (line 196) | func (c *Client) GetBoardsAndBlocksRoute() string {
method GetCardsRoute (line 200) | func (c *Client) GetCardsRoute() string {
method GetCardRoute (line 204) | func (c *Client) GetCardRoute(cardID string) string {
method GetTeam (line 208) | func (c *Client) GetTeam(teamID string) (*model.Team, *Response) {
method GetBlocksForBoard (line 218) | func (c *Client) GetBlocksForBoard(boardID string) ([]*model.Block, *R...
method GetAllBlocksForBoard (line 228) | func (c *Client) GetAllBlocksForBoard(boardID string) ([]*model.Block,...
method PatchBlock (line 240) | func (c *Client) PatchBlock(boardID, blockID string, blockPatch *model...
method DuplicateBoard (line 254) | func (c *Client) DuplicateBoard(boardID string, asTemplate bool, teamI...
method DuplicateBlock (line 271) | func (c *Client) DuplicateBlock(boardID, blockID string, asTemplate bo...
method UndeleteBlock (line 285) | func (c *Client) UndeleteBlock(boardID, blockID string) (bool, *Respon...
method InsertBlocks (line 295) | func (c *Client) InsertBlocks(boardID string, blocks []*model.Block, d...
method DeleteBlock (line 309) | func (c *Client) DeleteBlock(boardID, blockID string, disableNotify bo...
method CreateCard (line 327) | func (c *Client) CreateCard(boardID string, card *model.Card, disableN...
method GetCards (line 346) | func (c *Client) GetCards(boardID string, page int, perPage int) ([]*m...
method PatchCard (line 363) | func (c *Client) PatchCard(cardID string, cardPatch *model.CardPatch, ...
method GetCard (line 383) | func (c *Client) GetCard(cardID string) (*model.Card, *Response) {
method CreateBoardsAndBlocks (line 403) | func (c *Client) CreateBoardsAndBlocks(bab *model.BoardsAndBlocks) (*m...
method CreateCategory (line 413) | func (c *Client) CreateCategory(category model.Category) (*model.Categ...
method DeleteCategory (line 423) | func (c *Client) DeleteCategory(teamID, categoryID string) *Response {
method UpdateCategoryBoard (line 433) | func (c *Client) UpdateCategoryBoard(teamID, categoryID, boardID strin...
method GetUserCategoryBoards (line 443) | func (c *Client) GetUserCategoryBoards(teamID string) ([]model.Categor...
method ReorderCategories (line 455) | func (c *Client) ReorderCategories(teamID string, newOrder []string) (...
method ReorderCategoryBoards (line 467) | func (c *Client) ReorderCategoryBoards(teamID, categoryID string, newO...
method PatchBoardsAndBlocks (line 479) | func (c *Client) PatchBoardsAndBlocks(pbab *model.PatchBoardsAndBlocks...
method DeleteBoardsAndBlocks (line 489) | func (c *Client) DeleteBoardsAndBlocks(dbab *model.DeleteBoardsAndBloc...
method GetSharingRoute (line 501) | func (c *Client) GetSharingRoute(boardID string) string {
method GetSharing (line 505) | func (c *Client) GetSharing(boardID string) (*model.Sharing, *Response) {
method PostSharing (line 516) | func (c *Client) PostSharing(sharing *model.Sharing) (bool, *Response) {
method GetRegisterRoute (line 526) | func (c *Client) GetRegisterRoute() string {
method Register (line 530) | func (c *Client) Register(request *model.RegisterRequest) (bool, *Resp...
method GetLoginRoute (line 540) | func (c *Client) GetLoginRoute() string {
method Login (line 544) | func (c *Client) Login(request *model.LoginRequest) (*model.LoginRespo...
method GetMeRoute (line 563) | func (c *Client) GetMeRoute() string {
method GetMe (line 567) | func (c *Client) GetMe() (*model.User, *Response) {
method GetUserID (line 581) | func (c *Client) GetUserID() string {
method GetUserRoute (line 589) | func (c *Client) GetUserRoute(id string) string {
method GetUser (line 593) | func (c *Client) GetUser(id string) (*model.User, *Response) {
method GetUserList (line 607) | func (c *Client) GetUserList(ids []string) ([]model.User, *Response) {
method GetUserChangePasswordRoute (line 627) | func (c *Client) GetUserChangePasswordRoute(id string) string {
method UserChangePassword (line 631) | func (c *Client) UserChangePassword(id string, data *model.ChangePassw...
method CreateBoard (line 641) | func (c *Client) CreateBoard(board *model.Board) (*model.Board, *Respo...
method PatchBoard (line 651) | func (c *Client) PatchBoard(boardID string, patch *model.BoardPatch) (...
method DeleteBoard (line 661) | func (c *Client) DeleteBoard(boardID string) (bool, *Response) {
method UndeleteBoard (line 671) | func (c *Client) UndeleteBoard(boardID string) (bool, *Response) {
method GetBoard (line 681) | func (c *Client) GetBoard(boardID, readToken string) (*model.Board, *R...
method GetBoardMetadata (line 696) | func (c *Client) GetBoardMetadata(boardID, readToken string) (*model.B...
method GetBoardsForTeam (line 711) | func (c *Client) GetBoardsForTeam(teamID string) ([]*model.Board, *Res...
method SearchBoardsForUser (line 721) | func (c *Client) SearchBoardsForUser(teamID, term string, field model....
method SearchBoardsForTeam (line 732) | func (c *Client) SearchBoardsForTeam(teamID, term string) ([]*model.Bo...
method GetMembersForBoard (line 742) | func (c *Client) GetMembersForBoard(boardID string) ([]*model.BoardMem...
method AddMemberToBoard (line 752) | func (c *Client) AddMemberToBoard(member *model.BoardMember) (*model.B...
method JoinBoard (line 762) | func (c *Client) JoinBoard(boardID string) (*model.BoardMember, *Respo...
method LeaveBoard (line 772) | func (c *Client) LeaveBoard(boardID string) (*model.BoardMember, *Resp...
method UpdateBoardMember (line 782) | func (c *Client) UpdateBoardMember(member *model.BoardMember) (*model....
method DeleteBoardMember (line 792) | func (c *Client) DeleteBoardMember(member *model.BoardMember) (bool, *...
method GetTeamUploadFileRoute (line 802) | func (c *Client) GetTeamUploadFileRoute(teamID, boardID string) string {
method TeamUploadFile (line 806) | func (c *Client) TeamUploadFile(teamID, boardID string, data io.Reader...
method TeamUploadFileInfo (line 836) | func (c *Client) TeamUploadFileInfo(teamID, boardID string, fileName s...
method GetSubscriptionsRoute (line 849) | func (c *Client) GetSubscriptionsRoute() string {
method CreateSubscription (line 853) | func (c *Client) CreateSubscription(sub *model.Subscription) (*model.S...
method DeleteSubscription (line 867) | func (c *Client) DeleteSubscription(blockID string, subscriberID strin...
method GetSubscriptions (line 879) | func (c *Client) GetSubscriptions(subscriberID string) ([]*model.Subsc...
method GetTemplatesForTeam (line 897) | func (c *Client) GetTemplatesForTeam(teamID string) ([]*model.Board, *...
method ExportBoardArchive (line 907) | func (c *Client) ExportBoardArchive(boardID string) ([]byte, *Response) {
method ImportArchive (line 921) | func (c *Client) ImportArchive(teamID string, data io.Reader) *Response {
method MoveContentBlock (line 946) | func (c *Client) MoveContentBlock(srcBlockID string, dstBlockID string...
method GetBoardsForCompliance (line 956) | func (c *Client) GetBoardsForCompliance(teamID string, page, perPage i...
method GetBoardsComplianceHistory (line 973) | func (c *Client) GetBoardsComplianceHistory(
method GetBlocksComplianceHistory (line 992) | func (c *Client) GetBlocksComplianceHistory(
method HideBoard (line 1011) | func (c *Client) HideBoard(teamID, categoryID, boardID string) *Respon...
method UnhideBoard (line 1021) | func (c *Client) UnhideBoard(teamID, categoryID, boardID string) *Resp...
function NewClient (line 79) | func NewClient(url, sessionToken string) *Client {
type requestOption (line 113) | type requestOption
constant disableNotifyQueryParam (line 238) | disableNotifyQueryParam = "disable_notify=true"
FILE: server/integrationtests/blocks_test.go
function TestGetBlocks (line 13) | func TestGetBlocks(t *testing.T) {
function TestPostBlock (line 55) | func TestPostBlock(t *testing.T) {
function TestPatchBlock (line 164) | func TestPatchBlock(t *testing.T) {
function TestDeleteBlock (line 262) | func TestDeleteBlock(t *testing.T) {
function TestUndeleteBlock (line 313) | func TestUndeleteBlock(t *testing.T) {
FILE: server/integrationtests/board_test.go
function TestGetBoards (line 16) | func TestGetBoards(t *testing.T) {
function TestCreateBoard (line 116) | func TestCreateBoard(t *testing.T) {
function TestCreateBoardTemplate (line 298) | func TestCreateBoardTemplate(t *testing.T) {
function TestGetAllBlocksForBoard (line 412) | func TestGetAllBlocksForBoard(t *testing.T) {
function TestSearchBoards (line 474) | func TestSearchBoards(t *testing.T) {
function TestGetBoard (line 586) | func TestGetBoard(t *testing.T) {
function TestGetBoardMetadata (line 701) | func TestGetBoardMetadata(t *testing.T) {
function TestPatchBoard (line 880) | func TestPatchBoard(t *testing.T) {
function TestDeleteBoard (line 995) | func TestDeleteBoard(t *testing.T) {
function TestUndeleteBoard (line 1073) | func TestUndeleteBoard(t *testing.T) {
function TestGetMembersForBoard (line 1198) | func TestGetMembersForBoard(t *testing.T) {
function TestAddMember (line 1267) | func TestAddMember(t *testing.T) {
function TestUpdateMember (line 1472) | func TestUpdateMember(t *testing.T) {
function TestDeleteMember (line 1648) | func TestDeleteMember(t *testing.T) {
function TestGetTemplates (line 1867) | func TestGetTemplates(t *testing.T) {
function TestDuplicateBoard (line 1920) | func TestDuplicateBoard(t *testing.T) {
function TestJoinBoard (line 2091) | func TestJoinBoard(t *testing.T) {
FILE: server/integrationtests/boards_and_blocks_test.go
function TestCreateBoardsAndBlocks (line 11) | func TestCreateBoardsAndBlocks(t *testing.T) {
function TestPatchBoardsAndBlocks (line 166) | func TestPatchBoardsAndBlocks(t *testing.T) {
function TestDeleteBoardsAndBlocks (line 659) | func TestDeleteBoardsAndBlocks(t *testing.T) {
FILE: server/integrationtests/cards_test.go
function TestCreateCard (line 14) | func TestCreateCard(t *testing.T) {
function TestGetCards (line 71) | func TestGetCards(t *testing.T) {
function TestPatchCard (line 168) | func TestPatchCard(t *testing.T) {
function TestGetCard (line 238) | func TestGetCard(t *testing.T) {
function reverse (line 273) | func reverse(src []string) []string {
function modifyCardProps (line 281) | func modifyCardProps(m map[string]any) map[string]any {
FILE: server/integrationtests/clienttestlib.go
constant user1Username (line 29) | user1Username = "user1"
constant user2Username (line 30) | user2Username = "user2"
constant password (line 31) | password = "Pa$$word"
constant testTeamID (line 32) | testTeamID = "team-id"
constant userAnon (line 36) | userAnon string = "anon"
constant userNoTeamMember (line 37) | userNoTeamMember string = "no-team-member"
constant userTeamMember (line 38) | userTeamMember string = "team-member"
constant userViewer (line 39) | userViewer string = "viewer"
constant userCommenter (line 40) | userCommenter string = "commenter"
constant userEditor (line 41) | userEditor string = "editor"
constant userAdmin (line 42) | userAdmin string = "admin"
constant userGuest (line 43) | userGuest string = "guest"
type LicenseType (line 57) | type LicenseType
constant LicenseNone (line 60) | LicenseNone LicenseType = iota
constant LicenseProfessional (line 61) | LicenseProfessional
constant LicenseEnterprise (line 62) | LicenseEnterprise
type TestHelper (line 65) | type TestHelper struct
method Start (line 330) | func (th *TestHelper) Start() *TestHelper {
method InitBasic (line 365) | func (th *TestHelper) InitBasic() *TestHelper {
method TearDown (line 388) | func (th *TestHelper) TearDown() {
method RegisterAndLogin (line 409) | func (th *TestHelper) RegisterAndLogin(client *client.Client, username...
method Login (line 424) | func (th *TestHelper) Login(client *client.Client, username, password ...
method Login1 (line 435) | func (th *TestHelper) Login1() {
method Login2 (line 439) | func (th *TestHelper) Login2() {
method Logout (line 443) | func (th *TestHelper) Logout(client *client.Client) {
method Me (line 447) | func (th *TestHelper) Me(client *client.Client) *model.User {
method CreateBoard (line 454) | func (th *TestHelper) CreateBoard(teamID string, boardType model.Board...
method CreateBoards (line 464) | func (th *TestHelper) CreateBoards(teamID string, boardType model.Boar...
method CreateCategory (line 474) | func (th *TestHelper) CreateCategory(category model.Category) *model.C...
method UpdateCategoryBoard (line 480) | func (th *TestHelper) UpdateCategoryBoard(teamID, categoryID, boardID ...
method CreateBoardAndCards (line 485) | func (th *TestHelper) CreateBoardAndCards(teamdID string, boardType mo...
method MakeCardProps (line 502) | func (th *TestHelper) MakeCardProps(count int) map[string]any {
method GetUserCategoryBoards (line 510) | func (th *TestHelper) GetUserCategoryBoards(teamID string) []model.Cat...
method DeleteCategory (line 516) | func (th *TestHelper) DeleteCategory(teamID, categoryID string) {
method GetUser1 (line 521) | func (th *TestHelper) GetUser1() *model.User {
method GetUser2 (line 525) | func (th *TestHelper) GetUser2() *model.User {
method CheckOK (line 529) | func (th *TestHelper) CheckOK(r *client.Response) {
method CheckBadRequest (line 534) | func (th *TestHelper) CheckBadRequest(r *client.Response) {
method CheckNotFound (line 539) | func (th *TestHelper) CheckNotFound(r *client.Response) {
method CheckUnauthorized (line 544) | func (th *TestHelper) CheckUnauthorized(r *client.Response) {
method CheckForbidden (line 549) | func (th *TestHelper) CheckForbidden(r *client.Response) {
method CheckRequestEntityTooLarge (line 554) | func (th *TestHelper) CheckRequestEntityTooLarge(r *client.Response) {
method CheckNotImplemented (line 559) | func (th *TestHelper) CheckNotImplemented(r *client.Response) {
type FakePermissionPluginAPI (line 74) | type FakePermissionPluginAPI struct
method HasPermissionTo (line 76) | func (*FakePermissionPluginAPI) HasPermissionTo(userID string, permiss...
method HasPermissionToTeam (line 80) | func (*FakePermissionPluginAPI) HasPermissionToTeam(userID string, tea...
method HasPermissionToChannel (line 93) | func (*FakePermissionPluginAPI) HasPermissionToChannel(userID string, ...
function getTestConfig (line 97) | func getTestConfig() (*config.Configuration, error) {
function newTestServer (line 140) | func newTestServer(singleUserToken string) *server.Server {
function newTestServerWithLicense (line 144) | func newTestServerWithLicense(singleUserToken string, licenseType Licens...
function NewTestServerPluginMode (line 191) | func NewTestServerPluginMode() *server.Server {
function newTestServerLocalMode (line 227) | func newTestServerLocalMode() *server.Server {
function SetupTestHelperWithToken (line 264) | func SetupTestHelperWithToken(t *testing.T) *TestHelper {
function SetupTestHelper (line 281) | func SetupTestHelper(t *testing.T) *TestHelper {
function SetupTestHelperPluginMode (line 285) | func SetupTestHelperPluginMode(t *testing.T) *TestHelper {
function SetupTestHelperLocalMode (line 299) | func SetupTestHelperLocalMode(t *testing.T) *TestHelper {
function SetupTestHelperWithLicense (line 313) | func SetupTestHelperWithLicense(t *testing.T, licenseType LicenseType) *...
FILE: server/integrationtests/compliance_test.go
function setupTestHelperForCompliance (line 20) | func setupTestHelperForCompliance(t *testing.T, complianceLicense bool) ...
function TestGetBoardsForCompliance (line 32) | func TestGetBoardsForCompliance(t *testing.T) {
function TestGetBoardsComplianceHistory (line 119) | func TestGetBoardsComplianceHistory(t *testing.T) {
function TestGetBlocksComplianceHistory (line 235) | func TestGetBlocksComplianceHistory(t *testing.T) {
FILE: server/integrationtests/content_blocks_test.go
function TestMoveContentBlock (line 13) | func TestMoveContentBlock(t *testing.T) {
FILE: server/integrationtests/export_test.go
function TestExportBoard (line 12) | func TestExportBoard(t *testing.T) {
FILE: server/integrationtests/file_test.go
function TestUploadFile (line 12) | func TestUploadFile(t *testing.T) {
function TestFileInfo (line 73) | func TestFileInfo(t *testing.T) {
FILE: server/integrationtests/permissions_test.go
type Clients (line 18) | type Clients struct
constant methodPost (line 30) | methodPost = "POST"
constant methodGet (line 31) | methodGet = "GET"
constant methodPut (line 32) | methodPut = "PUT"
constant methodDelete (line 33) | methodDelete = "DELETE"
constant methodPatch (line 34) | methodPatch = "PATCH"
type TestCase (line 37) | type TestCase struct
method identifier (line 46) | func (tt TestCase) identifier() string {
function setupClients (line 58) | func setupClients(th *TestHelper) Clients {
function setupLocalClients (line 92) | func setupLocalClients(th *TestHelper) Clients {
function toJSON (line 134) | func toJSON(t *testing.T, obj interface{}) string {
type TestData (line 140) | type TestData struct
function setupData (line 147) | func setupData(t *testing.T, th *TestHelper) TestData {
function runTestCases (line 247) | func runTestCases(t *testing.T, ttCases []TestCase, testData TestData, c...
function TestPermissionsGetTeamBoards (line 339) | func TestPermissionsGetTeamBoards(t *testing.T) {
function TestPermissionsSearchTeamBoards (line 369) | func TestPermissionsSearchTeamBoards(t *testing.T) {
function TestPermissionsSearchTeamLinkableBoards (line 399) | func TestPermissionsSearchTeamLinkableBoards(t *testing.T) {
function TestPermissionsGetTeamTemplates (line 436) | func TestPermissionsGetTeamTemplates(t *testing.T) {
function TestPermissionsCreateBoard (line 484) | func TestPermissionsCreateBoard(t *testing.T) {
function TestPermissionsGetBoard (line 521) | func TestPermissionsGetBoard(t *testing.T) {
function TestPermissionsGetBoardPublic (line 584) | func TestPermissionsGetBoardPublic(t *testing.T) {
function TestPermissionsPatchBoard (line 613) | func TestPermissionsPatchBoard(t *testing.T) {
function TestPermissionsPatchBoardType (line 668) | func TestPermissionsPatchBoardType(t *testing.T) {
function TestPermissionsPatchBoardMinimumRole (line 719) | func TestPermissionsPatchBoardMinimumRole(t *testing.T) {
function TestPermissionsPatchBoardChannelId (line 771) | func TestPermissionsPatchBoardChannelId(t *testing.T) {
function TestPermissionsDeleteBoard (line 823) | func TestPermissionsDeleteBoard(t *testing.T) {
function TestPermissionsDuplicateBoard (line 878) | func TestPermissionsDuplicateBoard(t *testing.T) {
function TestPermissionsGetBoardBlocks (line 1036) | func TestPermissionsGetBoardBlocks(t *testing.T) {
function TestPermissionsCreateBoardBlocks (line 1097) | func TestPermissionsCreateBoardBlocks(t *testing.T) {
function TestPermissionsCreateBoardComments (line 1169) | func TestPermissionsCreateBoardComments(t *testing.T) {
function TestPermissionsPatchBoardBlocks (line 1237) | func TestPermissionsPatchBoardBlocks(t *testing.T) {
function TestPermissionsPatchBoardBlock (line 1302) | func TestPermissionsPatchBoardBlock(t *testing.T) {
function TestPermissionsDeleteBoardBlock (line 1363) | func TestPermissionsDeleteBoardBlock(t *testing.T) {
function TestPermissionsUndeleteBoardBlock (line 1434) | func TestPermissionsUndeleteBoardBlock(t *testing.T) {
function TestPermissionsMoveContentBlock (line 1521) | func TestPermissionsMoveContentBlock(t *testing.T) {
function TestPermissionsUndeleteBoard (line 1608) | func TestPermissionsUndeleteBoard(t *testing.T) {
function TestPermissionsDuplicateBoardBlock (line 1676) | func TestPermissionsDuplicateBoardBlock(t *testing.T) {
function TestPermissionsGetBoardMembers (line 1747) | func TestPermissionsGetBoardMembers(t *testing.T) {
function TestPermissionsCreateBoardMembers (line 1802) | func TestPermissionsCreateBoardMembers(t *testing.T) {
function TestPermissionsUpdateBoardMember (line 1869) | func TestPermissionsUpdateBoardMember(t *testing.T) {
function TestPermissionsDeleteBoardMember (line 1946) | func TestPermissionsDeleteBoardMember(t *testing.T) {
function TestPermissionsJoinBoardAsMember (line 2023) | func TestPermissionsJoinBoardAsMember(t *testing.T) {
function TestPermissionsLeaveBoardAsMember (line 2084) | func TestPermissionsLeaveBoardAsMember(t *testing.T) {
function TestPermissionsShareBoard (line 2192) | func TestPermissionsShareBoard(t *testing.T) {
function TestPermissionsGetSharedBoardInfo (line 2249) | func TestPermissionsGetSharedBoardInfo(t *testing.T) {
function TestPermissionsListTeams (line 2316) | func TestPermissionsListTeams(t *testing.T) {
function TestPermissionsGetTeam (line 2348) | func TestPermissionsGetTeam(t *testing.T) {
function TestPermissionsRegenerateSignupToken (line 2394) | func TestPermissionsRegenerateSignupToken(t *testing.T) {
function TestPermissionsGetTeamUsers (line 2425) | func TestPermissionsGetTeamUsers(t *testing.T) {
function TestPermissionsTeamArchiveExport (line 2471) | func TestPermissionsTeamArchiveExport(t *testing.T) {
function TestPermissionsUploadFile (line 2503) | func TestPermissionsUploadFile(t *testing.T) {
function TestPermissionsGetMe (line 2558) | func TestPermissionsGetMe(t *testing.T) {
function TestPermissionsGetMyMemberships (line 2586) | func TestPermissionsGetMyMemberships(t *testing.T) {
function TestPermissionsGetUser (line 2614) | func TestPermissionsGetUser(t *testing.T) {
function TestPermissionsUserChangePassword (line 2660) | func TestPermissionsUserChangePassword(t *testing.T) {
function TestPermissionsUpdateUserConfig (line 2690) | func TestPermissionsUpdateUserConfig(t *testing.T) {
function TestPermissionsCreateBoardsAndBlocks (line 2719) | func TestPermissionsCreateBoardsAndBlocks(t *testing.T) {
function TestPermissionsUpdateBoardsAndBlocks (line 2756) | func TestPermissionsUpdateBoardsAndBlocks(t *testing.T) {
function TestPermissionsDeleteBoardsAndBlocks (line 2836) | func TestPermissionsDeleteBoardsAndBlocks(t *testing.T) {
function TestPermissionsLogin (line 2876) | func TestPermissionsLogin(t *testing.T) {
function TestPermissionsLogout (line 2909) | func TestPermissionsLogout(t *testing.T) {
function TestPermissionsRegister (line 2934) | func TestPermissionsRegister(t *testing.T) {
function TestPermissionsClientConfig (line 2971) | func TestPermissionsClientConfig(t *testing.T) {
function TestPermissionsGetCategories (line 2993) | func TestPermissionsGetCategories(t *testing.T) {
function TestPermissionsCreateCategory (line 3023) | func TestPermissionsCreateCategory(t *testing.T) {
function TestPermissionsUpdateCategory (line 3084) | func TestPermissionsUpdateCategory(t *testing.T) {
function TestPermissionsDeleteCategory (line 3190) | func TestPermissionsDeleteCategory(t *testing.T) {
function TestPermissionsUpdateCategoryBoard (line 3277) | func TestPermissionsUpdateCategoryBoard(t *testing.T) {
function TestPermissionsGetFile (line 3353) | func TestPermissionsGetFile(t *testing.T) {
function TestPermissionsCreateSubscription (line 3404) | func TestPermissionsCreateSubscription(t *testing.T) {
function TestPermissionsGetSubscriptions (line 3443) | func TestPermissionsGetSubscriptions(t *testing.T) {
function TestPermissionsDeleteSubscription (line 3479) | func TestPermissionsDeleteSubscription(t *testing.T) {
function TestPermissionsOnboard (line 3552) | func TestPermissionsOnboard(t *testing.T) {
function TestPermissionsBoardArchiveExport (line 3590) | func TestPermissionsBoardArchiveExport(t *testing.T) {
function TestPermissionsBoardArchiveImport (line 3645) | func TestPermissionsBoardArchiveImport(t *testing.T) {
function TestPermissionsMinimumRolesApplied (line 3675) | func TestPermissionsMinimumRolesApplied(t *testing.T) {
function TestPermissionsChannels (line 3839) | func TestPermissionsChannels(t *testing.T) {
function TestPermissionsChannel (line 3874) | func TestPermissionsChannel(t *testing.T) {
function TestPermissionsGetStatistics (line 3917) | func TestPermissionsGetStatistics(t *testing.T) {
FILE: server/integrationtests/pluginteststore.go
type PluginTestStore (line 17) | type PluginTestStore struct
method GetTeam (line 88) | func (s *PluginTestStore) GetTeam(id string) (*model.Team, error) {
method GetTeamsForUser (line 102) | func (s *PluginTestStore) GetTeamsForUser(userID string) ([]*model.Tea...
method GetUserByID (line 122) | func (s *PluginTestStore) GetUserByID(userID string) (*model.User, err...
method GetUsersList (line 130) | func (s *PluginTestStore) GetUsersList(userIDs []string, showEmail, sh...
method GetUserByEmail (line 141) | func (s *PluginTestStore) GetUserByEmail(email string) (*model.User, e...
method GetUserByUsername (line 150) | func (s *PluginTestStore) GetUserByUsername(username string) (*model.U...
method GetUserPreferences (line 159) | func (s *PluginTestStore) GetUserPreferences(userID string) (mmModel.P...
method GetUsersByTeam (line 172) | func (s *PluginTestStore) GetUsersByTeam(teamID string, asGuestID stri...
method SearchUsersByTeam (line 207) | func (s *PluginTestStore) SearchUsersByTeam(teamID string, searchQuery...
method CanSeeUser (line 225) | func (s *PluginTestStore) CanSeeUser(seerID string, seenID string) (bo...
method SearchUserChannels (line 251) | func (s *PluginTestStore) SearchUserChannels(teamID, userID, query str...
method GetChannel (line 268) | func (s *PluginTestStore) GetChannel(teamID, channel string) (*mmModel...
method SearchBoardsForUser (line 287) | func (s *PluginTestStore) SearchBoardsForUser(term string, field model...
method GetLicense (line 310) | func (s *PluginTestStore) GetLicense() *mmModel.License {
function NewPluginTestStore (line 26) | func NewPluginTestStore(innerStore store.Store) *PluginTestStore {
FILE: server/integrationtests/sharing_test.go
function TestSharing (line 11) | func TestSharing(t *testing.T) {
FILE: server/integrationtests/sidebar_test.go
function TestSidebar (line 10) | func TestSidebar(t *testing.T) {
function TestHideUnhideBoard (line 56) | func TestHideUnhideBoard(t *testing.T) {
FILE: server/integrationtests/subscriptions_test.go
function createTestSubscriptions (line 14) | func createTestSubscriptions(client *client.Client, num int) ([]*model.S...
function TestCreateSubscription (line 64) | func TestCreateSubscription(t *testing.T) {
function TestGetSubscriptions (line 100) | func TestGetSubscriptions(t *testing.T) {
function TestDeleteSubscription (line 123) | func TestDeleteSubscription(t *testing.T) {
FILE: server/integrationtests/teststore.go
type TestStore (line 9) | type TestStore struct
method GetLicense (line 108) | func (s *TestStore) GetLicense() *mmModel.License {
function NewTestEnterpriseStore (line 14) | func NewTestEnterpriseStore(store store.Store) *TestStore {
function NewTestProfessionalStore (line 61) | func NewTestProfessionalStore(store store.Store) *TestStore {
FILE: server/integrationtests/user_test.go
constant fakeUsername (line 14) | fakeUsername = "fakeUsername"
constant fakeEmail (line 15) | fakeEmail = "mock@test.com"
function TestUserRegister (line 18) | func TestUserRegister(t *testing.T) {
function TestUserLogin (line 38) | func TestUserLogin(t *testing.T) {
function TestGetMe (line 80) | func TestGetMe(t *testing.T) {
function TestGetUser (line 122) | func TestGetUser(t *testing.T) {
function TestGetUserList (line 167) | func TestGetUserList(t *testing.T) {
function TestUserChangePassword (line 240) | func TestUserChangePassword(t *testing.T) {
function randomBytes (line 279) | func randomBytes(t *testing.T, n int) []byte {
function TestTeamUploadFile (line 286) | func TestTeamUploadFile(t *testing.T) {
FILE: server/integrationtests/work_template_test.go
function TestGetTemplatesForWorkTemplate (line 12) | func TestGetTemplatesForWorkTemplate(t *testing.T) {
FILE: server/main/main.go
constant timeBetweenPidMonitoringChecks (line 26) | timeBetweenPidMonitoringChecks = 2 * time.Second
function isProcessRunning (line 29) | func isProcessRunning(pid int) bool {
function monitorPid (line 41) | func monitorPid(pid int, logger *mlog.Logger) {
function main (line 56) | func main() {
function StartServer (line 171) | func StartServer(webPath *C.char, filesPath *C.char, port int, singleUse...
function StopServer (line 185) | func StopServer() {
function startServer (line 189) | func startServer(webPath string, filesPath string, port int, singleUserT...
function stopServer (line 253) | func stopServer() {
function defaultLoggingConfig (line 271) | func defaultLoggingConfig() string {
FILE: server/model/auth.go
constant MinimumPasswordLength (line 13) | MinimumPasswordLength = 8
function NewErrAuthParam (line 16) | func NewErrAuthParam(msg string) *ErrAuthParam {
type ErrAuthParam (line 22) | type ErrAuthParam struct
method Error (line 26) | func (pe *ErrAuthParam) Error() string {
type LoginRequest (line 32) | type LoginRequest struct
type LoginResponse (line 57) | type LoginResponse struct
function LoginResponseFromJSON (line 63) | func LoginResponseFromJSON(data io.Reader) (*LoginResponse, error) {
type RegisterRequest (line 73) | type RegisterRequest struct
method IsValid (line 91) | func (rd *RegisterRequest) IsValid() error {
type ChangePasswordRequest (line 109) | type ChangePasswordRequest struct
method IsValid (line 120) | func (rd *ChangePasswordRequest) IsValid() error {
function isValidPassword (line 130) | func isValidPassword(password string) error {
FILE: server/model/block.go
constant BlockTitleMaxBytes (line 14) | BlockTitleMaxBytes = 65535
constant BlockTitleMaxRunes (line 15) | BlockTitleMaxRunes = BlockTitleMaxBytes / 4
constant BlockFieldsMaxRunes (line 16) | BlockFieldsMaxRunes = 800000
type Block (line 27) | type Block struct
method IsValid (line 143) | func (b *Block) IsValid() error {
method LogClone (line 165) | func (b *Block) LogClone() interface{} {
method ShouldBeLimited (line 263) | func (b *Block) ShouldBeLimited(cardLimitTimestamp int64) bool {
method GetLimited (line 270) | func (b *Block) GetLimited() *Block {
type BlockPatch (line 87) | type BlockPatch struct
method Patch (line 180) | func (p *BlockPatch) Patch(block *Block) *Block {
type BlockPatchBatch (line 115) | type BlockPatchBatch struct
type BoardModifier (line 127) | type BoardModifier
type BlockModifier (line 133) | type BlockModifier
function BlocksFromJSON (line 135) | func BlocksFromJSON(data io.Reader) []*Block {
type QueryBlocksOptions (line 208) | type QueryBlocksOptions struct
type QuerySubtreeOptions (line 217) | type QuerySubtreeOptions struct
type QueryBlockHistoryOptions (line 224) | type QueryBlockHistoryOptions struct
type QueryBoardHistoryOptions (line 232) | type QueryBoardHistoryOptions struct
type QueryBlockHistoryChildOptions (line 240) | type QueryBlockHistoryChildOptions struct
function StampModificationMetadata (line 247) | func StampModificationMetadata(userID string, blocks []*Block, auditRec ...
FILE: server/model/block_test.go
function TestGenerateBlockIDs (line 15) | func TestGenerateBlockIDs(t *testing.T) {
function TestStampModificationMetadata (line 298) | func TestStampModificationMetadata(t *testing.T) {
FILE: server/model/blockid.go
function GenerateBlockIDs (line 15) | func GenerateBlockIDs(blocks []*Block, logger mlog.LoggerIFace) []*Block {
function fixFieldIDs (line 132) | func fixFieldIDs(block *Block, fieldName string, getExistingOrOldID func...
FILE: server/model/blocktype.go
type BlockType (line 14) | type BlockType
method String (line 29) | func (bt BlockType) String() string {
constant TypeUnknown (line 17) | TypeUnknown = "unknown"
constant TypeBoard (line 18) | TypeBoard = "board"
constant TypeCard (line 19) | TypeCard = "card"
constant TypeView (line 20) | TypeView = "view"
constant TypeText (line 21) | TypeText = "text"
constant TypeCheckbox (line 22) | TypeCheckbox = "checkbox"
constant TypeComment (line 23) | TypeComment = "comment"
constant TypeImage (line 24) | TypeImage = "image"
constant TypeAttachment (line 25) | TypeAttachment = "attachment"
constant TypeDivider (line 26) | TypeDivider = "divider"
function BlockTypeFromString (line 34) | func BlockTypeFromString(s string) (BlockType, error) {
function BlockType2IDType (line 59) | func BlockType2IDType(blockType BlockType) utils.IDType {
type ErrInvalidBlockType (line 76) | type ErrInvalidBlockType struct
method Error (line 80) | func (e ErrInvalidBlockType) Error() string {
function IsErrInvalidBlockType (line 85) | func IsErrInvalidBlockType(err error) bool {
FILE: server/model/board.go
type BoardType (line 9) | type BoardType
type BoardRole (line 10) | type BoardRole
type BoardSearchField (line 11) | type BoardSearchField
constant BoardTypeOpen (line 14) | BoardTypeOpen BoardType = "O"
constant BoardTypePrivate (line 15) | BoardTypePrivate BoardType = "P"
constant BoardRoleNone (line 19) | BoardRoleNone BoardRole = ""
constant BoardRoleViewer (line 20) | BoardRoleViewer BoardRole = "viewer"
constant BoardRoleCommenter (line 21) | BoardRoleCommenter BoardRole = "commenter"
constant BoardRoleEditor (line 22) | BoardRoleEditor BoardRole = "editor"
constant BoardRoleAdmin (line 23) | BoardRoleAdmin BoardRole = "admin"
constant BoardSearchFieldNone (line 27) | BoardSearchFieldNone BoardSearchField = ""
constant BoardSearchFieldTitle (line 28) | BoardSearchFieldTitle BoardSearchField = "title"
constant BoardSearchFieldPropertyName (line 29) | BoardSearchFieldPropertyName BoardSearchField = "property_name"
type Board (line 34) | type Board struct
method GetPropertyString (line 110) | func (b *Board) GetPropertyString(propName string) (string, error) {
method IsValid (line 382) | func (b *Board) IsValid() error {
type BoardPatch (line 125) | type BoardPatch struct
method Patch (line 266) | func (p *BoardPatch) Patch(board *Board) *Board {
method IsValid (line 362) | func (p *BoardPatch) IsValid() error {
type BoardMember (line 173) | type BoardMember struct
type BoardMetadata (line 213) | type BoardMetadata struct
function BoardFromJSON (line 235) | func BoardFromJSON(data io.Reader) *Board {
function BoardsFromJSON (line 241) | func BoardsFromJSON(data io.Reader) []*Board {
function BoardMemberFromJSON (line 247) | func BoardMemberFromJSON(data io.Reader) *BoardMember {
function BoardMembersFromJSON (line 253) | func BoardMembersFromJSON(data io.Reader) []*BoardMember {
function BoardMetadataFromJSON (line 259) | func BoardMetadataFromJSON(data io.Reader) *BoardMetadata {
function IsBoardTypeValid (line 354) | func IsBoardTypeValid(t BoardType) bool {
function IsBoardMinimumRoleValid (line 358) | func IsBoardMinimumRoleValid(r BoardRole) bool {
type InvalidBoardErr (line 374) | type InvalidBoardErr struct
method Error (line 378) | func (ibe InvalidBoardErr) Error() string {
type BoardMemberHistoryEntry (line 400) | type BoardMemberHistoryEntry struct
function BoardSearchFieldFromString (line 418) | func BoardSearchFieldFromString(field string) (BoardSearchField, error) {
FILE: server/model/board_statistics.go
type BoardsStatistics (line 7) | type BoardsStatistics struct
FILE: server/model/boards_and_blocks.go
type BlockDoesntBelongToAnyBoardErr (line 20) | type BlockDoesntBelongToAnyBoardErr struct
method Error (line 24) | func (e BlockDoesntBelongToAnyBoardErr) Error() string {
type BoardsAndBlocks (line 31) | type BoardsAndBlocks struct
method IsValid (line 41) | func (bab *BoardsAndBlocks) IsValid() error {
type DeleteBoardsAndBlocks (line 66) | type DeleteBoardsAndBlocks struct
method IsValid (line 92) | func (dbab *DeleteBoardsAndBlocks) IsValid() error {
function NewDeleteBoardsAndBlocksFromBabs (line 76) | func NewDeleteBoardsAndBlocksFromBabs(babs *BoardsAndBlocks) *DeleteBoar...
type PatchBoardsAndBlocks (line 103) | type PatchBoardsAndBlocks struct
method IsValid (line 121) | func (dbab *PatchBoardsAndBlocks) IsValid() error {
function GenerateBoardsAndBlocksIDs (line 137) | func GenerateBoardsAndBlocksIDs(bab *BoardsAndBlocks, logger mlog.Logger...
function BoardsAndBlocksFromJSON (line 168) | func BoardsAndBlocksFromJSON(data io.Reader) *BoardsAndBlocks {
FILE: server/model/boards_and_blocks_test.go
function TestIsValidBoardsAndBlocks (line 11) | func TestIsValidBoardsAndBlocks(t *testing.T) {
function TestGenerateBoardsAndBlocksIDs (line 67) | func TestGenerateBoardsAndBlocksIDs(t *testing.T) {
function TestIsValidPatchBoardsAndBlocks (line 153) | func TestIsValidPatchBoardsAndBlocks(t *testing.T) {
function TestIsValidDeleteBoardsAndBlocks (line 220) | func TestIsValidDeleteBoardsAndBlocks(t *testing.T) {
FILE: server/model/card.go
type ErrInvalidCard (line 13) | type ErrInvalidCard struct
method Error (line 23) | func (e ErrInvalidCard) Error() string {
function NewErrInvalidCard (line 17) | func NewErrInvalidCard(msg string) ErrInvalidCard {
type ErrInvalidFieldType (line 29) | type ErrInvalidFieldType struct
method Error (line 33) | func (e ErrInvalidFieldType) Error() string {
type Card (line 39) | type Card struct
method Populate (line 90) | func (c *Card) Populate() {
method PopulateWithBoardID (line 109) | func (c *Card) PopulateWithBoardID(boardID string) {
method CheckValid (line 115) | func (c *Card) CheckValid() error {
type CardPatch (line 142) | type CardPatch struct
method Patch (line 161) | func (p *CardPatch) Patch(card *Card) *Card {
method CheckValid (line 188) | func (p *CardPatch) CheckValid() error {
function Card2Block (line 196) | func Card2Block(card *Card) *Block {
function Block2Card (line 221) | func Block2Card(block *Block) (*Card, error) {
function CardPatch2BlockPatch (line 293) | func CardPatch2BlockPatch(cardPatch *CardPatch) (*BlockPatch, error) {
FILE: server/model/card_test.go
function TestBlock2Card (line 12) | func TestBlock2Card(t *testing.T) {
constant sampleBlockFieldsJSON (line 57) | sampleBlockFieldsJSON = `
FILE: server/model/category.go
constant CategoryTypeSystem (line 13) | CategoryTypeSystem = "system"
constant CategoryTypeCustom (line 14) | CategoryTypeCustom = "custom"
type Category (line 19) | type Category struct
method Hydrate (line 65) | func (c *Category) Hydrate() {
method IsValid (line 87) | func (c *Category) IsValid() error {
function CategoryFromJSON (line 111) | func CategoryFromJSON(data io.Reader) *Category {
FILE: server/model/category_boards.go
constant CategoryBoardsSortOrderGap (line 3) | CategoryBoardsSortOrderGap = 10
type CategoryBoards (line 7) | type CategoryBoards struct
type BoardCategoryWebsocketData (line 19) | type BoardCategoryWebsocketData struct
type CategoryBoardMetadata (line 25) | type CategoryBoardMetadata struct
FILE: server/model/clientConfig.go
type ClientConfig (line 5) | type ClientConfig struct
FILE: server/model/cloud.go
constant LimitUnlimited (line 6) | LimitUnlimited = 0
type BoardsCloudLimits (line 11) | type BoardsCloudLimits struct
FILE: server/model/compliance.go
type BoardsComplianceResponse (line 7) | type BoardsComplianceResponse struct
type BoardsComplianceHistoryResponse (line 19) | type BoardsComplianceHistoryResponse struct
type BlocksComplianceHistoryResponse (line 31) | type BlocksComplianceHistoryResponse struct
type BoardHistory (line 43) | type BoardHistory struct
type BlockHistory (line 55) | type BlockHistory struct
type QueryBoardsForComplianceOptions (line 67) | type QueryBoardsForComplianceOptions struct
type QueryBoardsComplianceHistoryOptions (line 73) | type QueryBoardsComplianceHistoryOptions struct
type QueryBlocksComplianceHistoryOptions (line 81) | type QueryBlocksComplianceHistoryOptions struct
FILE: server/model/database.go
constant SqliteDBType (line 4) | SqliteDBType = "sqlite3"
constant PostgresDBType (line 5) | PostgresDBType = "postgres"
constant MysqlDBType (line 6) | MysqlDBType = "mysql"
FILE: server/model/error.go
type ErrNotFound (line 33) | type ErrNotFound struct
method Error (line 44) | func (nf *ErrNotFound) Error() string {
function NewErrNotFound (line 38) | func NewErrNotFound(entity string) *ErrNotFound {
type ErrNotAllFound (line 51) | type ErrNotAllFound struct
method Error (line 63) | func (naf *ErrNotAllFound) Error() string {
function NewErrNotAllFound (line 56) | func NewErrNotAllFound(entity string, resources []string) *ErrNotAllFound {
type ErrBadRequest (line 69) | type ErrBadRequest struct
method Error (line 80) | func (br *ErrBadRequest) Error() string {
function NewErrBadRequest (line 74) | func NewErrBadRequest(reason string) *ErrBadRequest {
type ErrUnauthorized (line 86) | type ErrUnauthorized struct
method Error (line 97) | func (br *ErrUnauthorized) Error() string {
function NewErrUnauthorized (line 91) | func NewErrUnauthorized(reason string) *ErrUnauthorized {
type ErrPermission (line 103) | type ErrPermission struct
method Error (line 114) | func (br *ErrPermission) Error() string {
function NewErrPermission (line 108) | func NewErrPermission(reason string) *ErrPermission {
type ErrForbidden (line 120) | type ErrForbidden struct
method Error (line 131) | func (br *ErrForbidden) Error() string {
function NewErrForbidden (line 125) | func NewErrForbidden(reason string) *ErrForbidden {
type ErrInvalidCategory (line 135) | type ErrInvalidCategory struct
method Error (line 145) | func (e *ErrInvalidCategory) Error() string {
function NewErrInvalidCategory (line 139) | func NewErrInvalidCategory(msg string) *ErrInvalidCategory {
type ErrNotImplemented (line 149) | type ErrNotImplemented struct
method Error (line 159) | func (ni *ErrNotImplemented) Error() string {
function NewErrNotImplemented (line 153) | func NewErrNotImplemented(msg string) *ErrNotImplemented {
function IsErrBadRequest (line 172) | func IsErrBadRequest(err error) bool {
function IsErrUnauthorized (line 221) | func IsErrUnauthorized(err error) bool {
function IsErrForbidden (line 236) | func IsErrForbidden(err error) bool {
function IsErrNotFound (line 268) | func IsErrNotFound(err error) bool {
function IsErrRequestEntityTooLarge (line 309) | func IsErrRequestEntityTooLarge(err error) bool {
function IsErrNotImplemented (line 317) | func IsErrNotImplemented(err error) bool {
FILE: server/model/errorResponse.go
type ErrorResponse (line 5) | type ErrorResponse struct
FILE: server/model/file.go
function NewFileInfo (line 14) | func NewFileInfo(name string) *mm_model.FileInfo {
FILE: server/model/import_export.go
type Archive (line 15) | type Archive struct
type ArchiveHeader (line 22) | type ArchiveHeader struct
type ArchiveLine (line 28) | type ArchiveLine struct
type ExportArchiveOptions (line 35) | type ExportArchiveOptions struct
type ImportArchiveOptions (line 44) | type ImportArchiveOptions struct
type ErrUnsupportedArchiveVersion (line 53) | type ErrUnsupportedArchiveVersion struct
method Error (line 66) | func (e ErrUnsupportedArchiveVersion) Error() string {
function NewErrUnsupportedArchiveVersion (line 59) | func NewErrUnsupportedArchiveVersion(got int, want int) ErrUnsupportedAr...
type ErrUnsupportedArchiveLineType (line 72) | type ErrUnsupportedArchiveLineType struct
method Error (line 85) | func (e ErrUnsupportedArchiveLineType) Error() string {
function NewErrUnsupportedArchiveLineType (line 78) | func NewErrUnsupportedArchiveLineType(line int, got string) ErrUnsupport...
FILE: server/model/mocks/mockservicesapi.go
type MockServicesAPI (line 18) | type MockServicesAPI struct
method EXPECT (line 36) | func (m *MockServicesAPI) EXPECT() *MockServicesAPIMockRecorder {
method CreateMember (line 41) | func (m *MockServicesAPI) CreateMember(arg0, arg1 string) (*model.Team...
method CreatePost (line 56) | func (m *MockServicesAPI) CreatePost(arg0 *model.Post) (*model.Post, e...
method DeletePreferencesForUser (line 71) | func (m *MockServicesAPI) DeletePreferencesForUser(arg0 string, arg1 m...
method EnsureBot (line 85) | func (m *MockServicesAPI) EnsureBot(arg0 *model.Bot) (string, error) {
method GetChannelByID (line 100) | func (m *MockServicesAPI) GetChannelByID(arg0 string) (*model.Channel,...
method GetChannelMember (line 115) | func (m *MockServicesAPI) GetChannelMember(arg0, arg1 string) (*model....
method GetChannelsForTeamForUser (line 130) | func (m *MockServicesAPI) GetChannelsForTeamForUser(arg0, arg1 string,...
method GetConfig (line 145) | func (m *MockServicesAPI) GetConfig() *model.Config {
method GetDiagnosticID (line 159) | func (m *MockServicesAPI) GetDiagnosticID() string {
method GetDirectChannel (line 173) | func (m *MockServicesAPI) GetDirectChannel(arg0, arg1 string) (*model....
method GetDirectChannelOrCreate (line 188) | func (m *MockServicesAPI) GetDirectChannelOrCreate(arg0, arg1 string) ...
method GetFileInfo (line 203) | func (m *MockServicesAPI) GetFileInfo(arg0 string) (*model.FileInfo, e...
method GetLicense (line 218) | func (m *MockServicesAPI) GetLicense() *model.License {
method GetLogger (line 232) | func (m *MockServicesAPI) GetLogger() mlog.LoggerIFace {
method GetMasterDB (line 246) | func (m *MockServicesAPI) GetMasterDB() (*sql.DB, error) {
method GetPreferencesForUser (line 261) | func (m *MockServicesAPI) GetPreferencesForUser(arg0 string) (model.Pr...
method GetTeamMember (line 276) | func (m *MockServicesAPI) GetTeamMember(arg0, arg1 string) (*model.Tea...
method GetUserByEmail (line 291) | func (m *MockServicesAPI) GetUserByEmail(arg0 string) (*model.User, er...
method GetUserByID (line 306) | func (m *MockServicesAPI) GetUserByID(arg0 string) (*model.User, error) {
method GetUserByUsername (line 321) | func (m *MockServicesAPI) GetUserByUsername(arg0 string) (*model.User,...
method GetUsersFromProfiles (line 336) | func (m *MockServicesAPI) GetUsersFromProfiles(arg0 *model.UserGetOpti...
method HasPermissionTo (line 351) | func (m *MockServicesAPI) HasPermissionTo(arg0 string, arg1 *model.Per...
method HasPermissionToChannel (line 365) | func (m *MockServicesAPI) HasPermissionToChannel(arg0, arg1 string, ar...
method HasPermissionToTeam (line 379) | func (m *MockServicesAPI) HasPermissionToTeam(arg0, arg1 string, arg2 ...
method KVSetWithOptions (line 393) | func (m *MockServicesAPI) KVSetWithOptions(arg0 string, arg1 []byte, a...
method PublishPluginClusterEvent (line 408) | func (m *MockServicesAPI) PublishPluginClusterEvent(arg0 model.PluginC...
method PublishWebSocketEvent (line 422) | func (m *MockServicesAPI) PublishWebSocketEvent(arg0 string, arg1 map[...
method RegisterRouter (line 434) | func (m *MockServicesAPI) RegisterRouter(arg0 *mux.Router) {
method UpdatePreferencesForUser (line 446) | func (m *MockServicesAPI) UpdatePreferencesForUser(arg0 string, arg1 m...
method UpdateUser (line 460) | func (m *MockServicesAPI) UpdateUser(arg0 *model.User) (*model.User, e...
type MockServicesAPIMockRecorder (line 24) | type MockServicesAPIMockRecorder struct
method CreateMember (line 50) | func (mr *MockServicesAPIMockRecorder) CreateMember(arg0, arg1 interfa...
method CreatePost (line 65) | func (mr *MockServicesAPIMockRecorder) CreatePost(arg0 interface{}) *g...
method DeletePreferencesForUser (line 79) | func (mr *MockServicesAPIMockRecorder) DeletePreferencesForUser(arg0, ...
method EnsureBot (line 94) | func (mr *MockServicesAPIMockRecorder) EnsureBot(arg0 interface{}) *go...
method GetChannelByID (line 109) | func (mr *MockServicesAPIMockRecorder) GetChannelByID(arg0 interface{}...
method GetChannelMember (line 124) | func (mr *MockServicesAPIMockRecorder) GetChannelMember(arg0, arg1 int...
method GetChannelsForTeamForUser (line 139) | func (mr *MockServicesAPIMockRecorder) GetChannelsForTeamForUser(arg0,...
method GetConfig (line 153) | func (mr *MockServicesAPIMockRecorder) GetConfig() *gomock.Call {
method GetDiagnosticID (line 167) | func (mr *MockServicesAPIMockRecorder) GetDiagnosticID() *gomock.Call {
method GetDirectChannel (line 182) | func (mr *MockServicesAPIMockRecorder) GetDirectChannel(arg0, arg1 int...
method GetDirectChannelOrCreate (line 197) | func (mr *MockServicesAPIMockRecorder) GetDirectChannelOrCreate(arg0, ...
method GetFileInfo (line 212) | func (mr *MockServicesAPIMockRecorder) GetFileInfo(arg0 interface{}) *...
method GetLicense (line 226) | func (mr *MockServicesAPIMockRecorder) GetLicense() *gomock.Call {
method GetLogger (line 240) | func (mr *MockServicesAPIMockRecorder) GetLogger() *gomock.Call {
method GetMasterDB (line 255) | func (mr *MockServicesAPIMockRecorder) GetMasterDB() *gomock.Call {
method GetPreferencesForUser (line 270) | func (mr *MockServicesAPIMockRecorder) GetPreferencesForUser(arg0 inte...
method GetTeamMember (line 285) | func (mr *MockServicesAPIMockRecorder) GetTeamMember(arg0, arg1 interf...
method GetUserByEmail (line 300) | func (mr *MockServicesAPIMockRecorder) GetUserByEmail(arg0 interface{}...
method GetUserByID (line 315) | func (mr *MockServicesAPIMockRecorder) GetUserByID(arg0 interface{}) *...
method GetUserByUsername (line 330) | func (mr *MockServicesAPIMockRecorder) GetUserByUsername(arg0 interfac...
method GetUsersFromProfiles (line 345) | func (mr *MockServicesAPIMockRecorder) GetUsersFromProfiles(arg0 inter...
method HasPermissionTo (line 359) | func (mr *MockServicesAPIMockRecorder) HasPermissionTo(arg0, arg1 inte...
method HasPermissionToChannel (line 373) | func (mr *MockServicesAPIMockRecorder) HasPermissionToChannel(arg0, ar...
method HasPermissionToTeam (line 387) | func (mr *MockServicesAPIMockRecorder) HasPermissionToTeam(arg0, arg1,...
method KVSetWithOptions (line 402) | func (mr *MockServicesAPIMockRecorder) KVSetWithOptions(arg0, arg1, ar...
method PublishPluginClusterEvent (line 416) | func (mr *MockServicesAPIMockRecorder) PublishPluginClusterEvent(arg0,...
method PublishWebSocketEvent (line 428) | func (mr *MockServicesAPIMockRecorder) PublishWebSocketEvent(arg0, arg...
method RegisterRouter (line 440) | func (mr *MockServicesAPIMockRecorder) RegisterRouter(arg0 interface{}...
method UpdatePreferencesForUser (line 454) | func (mr *MockServicesAPIMockRecorder) UpdatePreferencesForUser(arg0, ...
method UpdateUser (line 469) | func (mr *MockServicesAPIMockRecorder) UpdateUser(arg0 interface{}) *g...
function NewMockServicesAPI (line 29) | func NewMockServicesAPI(ctrl *gomock.Controller) *MockServicesAPI {
FILE: server/model/mocks/propValueResolverMock.go
type MockPropValueResolver (line 15) | type MockPropValueResolver struct
method EXPECT (line 33) | func (m *MockPropValueResolver) EXPECT() *MockPropValueResolverMockRec...
method GetUserByID (line 38) | func (m *MockPropValueResolver) GetUserByID(arg0 string) (*model.User,...
type MockPropValueResolverMockRecorder (line 21) | type MockPropValueResolverMockRecorder struct
method GetUserByID (line 47) | func (mr *MockPropValueResolverMockRecorder) GetUserByID(arg0 interfac...
function NewMockPropValueResolver (line 26) | func NewMockPropValueResolver(ctrl *gomock.Controller) *MockPropValueRes...
FILE: server/model/notification.go
type NotificationHint (line 12) | type NotificationHint struct
method IsValid (line 33) | func (s *NotificationHint) IsValid() error {
method Copy (line 49) | func (s *NotificationHint) Copy() *NotificationHint {
method LogClone (line 59) | func (s *NotificationHint) LogClone() interface{} {
type ErrInvalidNotificationHint (line 75) | type ErrInvalidNotificationHint struct
method Error (line 79) | func (e ErrInvalidNotificationHint) Error() string {
FILE: server/model/properties.go
type PropValueResolver (line 26) | type PropValueResolver interface
type BlockProperties (line 31) | type BlockProperties
type BlockProp (line 34) | type BlockProp struct
type PropSchema (line 42) | type PropSchema
type PropDefOption (line 45) | type PropDefOption struct
type PropDef (line 53) | type PropDef struct
method GetValue (line 63) | func (pd PropDef) GetValue(v interface{}, resolver PropValueResolver) ...
method ParseDate (line 155) | func (pd PropDef) ParseDate(s string) (string, error) {
function ParsePropertySchema (line 178) | func ParsePropertySchema(board *Board) (PropSchema, error) {
function getMapString (line 214) | func getMapString(key string, m map[string]interface{}) string {
function ParseProperties (line 229) | func ParseProperties(block *Block, schema PropSchema, resolver PropValue...
FILE: server/model/properties_test.go
type MockResolver (line 15) | type MockResolver struct
method GetUserByID (line 17) | func (r MockResolver) GetUserByID(userID string) (*User, error) {
function Test_parsePropertySchema (line 33) | func Test_parsePropertySchema(t *testing.T) {
function Test_GetValue (line 65) | func Test_GetValue(t *testing.T) {
constant cardPropertiesExample (line 93) | cardPropertiesExample = `[
FILE: server/model/services_api.go
constant botUsername (line 18) | botUsername = "boards"
constant botDisplayname (line 19) | botDisplayname = "Boards"
constant botDescription (line 20) | botDescription = "Created by Boards plugin."
type ServicesAPI (line 30) | type ServicesAPI interface
FILE: server/model/sharing.go
type Sharing (line 10) | type Sharing struct
function SharingFromJSON (line 32) | func SharingFromJSON(data io.Reader) Sharing {
FILE: server/model/subscription.go
constant SubTypeUser (line 9) | SubTypeUser = "user"
constant SubTypeChannel (line 10) | SubTypeChannel = "channel"
type SubscriberType (line 13) | type SubscriberType
method IsValid (line 15) | func (st SubscriberType) IsValid() bool {
type Subscription (line 25) | type Subscription struct
method IsValid (line 55) | func (s *Subscription) IsValid() error {
function SubscriptionFromJSON (line 74) | func SubscriptionFromJSON(data io.Reader) (*Subscription, error) {
type ErrInvalidSubscription (line 82) | type ErrInvalidSubscription struct
method Error (line 86) | func (e ErrInvalidSubscription) Error() string {
type Subscriber (line 92) | type Subscriber struct
FILE: server/model/team.go
type Team (line 10) | type Team struct
function TeamFromJSON (line 36) | func TeamFromJSON(data io.Reader) *Team {
function TeamsFromJSON (line 42) | func TeamsFromJSON(data io.Reader) []*Team {
FILE: server/model/user.go
constant SingleUser (line 9) | SingleUser = "single-user"
constant GlobalTeamID (line 10) | GlobalTeamID = "0"
constant SystemUserID (line 11) | SystemUserID = "system"
constant PreferencesCategoryFocalboard (line 12) | PreferencesCategoryFocalboard = "focalboard"
type User (line 17) | type User struct
method Sanitize (line 105) | func (u *User) Sanitize(options map[string]bool) {
type UserPreferencesPatch (line 77) | type UserPreferencesPatch struct
type Session (line 87) | type Session struct
function UserFromJSON (line 97) | func UserFromJSON(data io.Reader) (*User, error) {
FILE: server/model/util.go
function GetMillis (line 13) | func GetMillis() int64 {
function GetMillisForTime (line 18) | func GetMillisForTime(thisTime time.Time) int64 {
function GetTimeForMillis (line 23) | func GetTimeForMillis(millis int64) time.Time {
FILE: server/model/version.go
function LogServerInfo (line 61) | func LogServerInfo(logger mlog.LoggerIFace) {
FILE: server/server/initHandlers.go
method initHandlers (line 3) | func (s *Server) initHandlers() {
FILE: server/server/params.go
type Params (line 16) | type Params struct
method CheckValid (line 28) | func (p Params) CheckValid() error {
type ErrServerParam (line 47) | type ErrServerParam struct
method Error (line 52) | func (e ErrServerParam) Error() string {
FILE: server/server/server.go
constant cleanupSessionTaskFrequency (line 41) | cleanupSessionTaskFrequency = 10 * time.Minute
constant updateMetricsTaskFrequency (line 42) | updateMetricsTaskFrequency = 15 * time.Minute
constant minSessionExpiryTime (line 44) | minSessionExpiryTime = int64(60 * 60 * 24 * 31)
constant MattermostAuthMod (line 46) | MattermostAuthMod = "mattermost"
type Server (line 49) | type Server struct
method Start (line 242) | func (s *Server) Start() error {
method Shutdown (line 320) | func (s *Server) Shutdown() error {
method Config (line 357) | func (s *Server) Config() *config.Configuration {
method Logger (line 361) | func (s *Server) Logger() mlog.LoggerIFace {
method App (line 365) | func (s *Server) App() *app.App {
method Store (line 369) | func (s *Server) Store() store.Store {
method UpdateAppConfig (line 373) | func (s *Server) UpdateAppConfig() {
method startLocalModeServer (line 379) | func (s *Server) startLocalModeServer() error {
method stopLocalModeServer (line 413) | func (s *Server) stopLocalModeServer() {
method GetRootRouter (line 420) | func (s *Server) GetRootRouter() *mux.Router {
function New (line 71) | func New(params Params) (*Server, error) {
function NewStore (line 211) | func NewStore(config *config.Configuration, isSingleUser bool, logger ml...
type telemetryOptions (line 424) | type telemetryOptions struct
function initTelemetry (line 433) | func initTelemetry(opts telemetryOptions) *telemetry.Service {
function initNotificationService (line 515) | func initNotificationService(backends []notify.Backend, logger mlog.Logg...
FILE: server/services/audit/audit.go
constant DefMaxQueueSize (line 8) | DefMaxQueueSize = 1000
constant KeyAPIPath (line 10) | KeyAPIPath = "api_path"
constant KeyEvent (line 11) | KeyEvent = "event"
constant KeyStatus (line 12) | KeyStatus = "status"
constant KeyUserID (line 13) | KeyUserID = "user_id"
constant KeySessionID (line 14) | KeySessionID = "session_id"
constant KeyClient (line 15) | KeyClient = "client"
constant KeyIPAddress (line 16) | KeyIPAddress = "ip_address"
constant KeyClusterID (line 17) | KeyClusterID = "cluster_id"
constant KeyTeamID (line 18) | KeyTeamID = "team_id"
constant Success (line 20) | Success = "success"
constant Attempt (line 21) | Attempt = "attempt"
constant Fail (line 22) | Fail = "fail"
type Audit (line 32) | type Audit struct
method Configure (line 57) | func (a *Audit) Configure(cfgFile string, cfgEscaped string) error {
method Shutdown (line 63) | func (a *Audit) Shutdown() error {
method LogRecord (line 68) | func (a *Audit) LogRecord(level mlog.Level, rec *Record) {
function NewAudit (line 37) | func NewAudit(options ...mlog.Option) (*Audit, error) {
FILE: server/services/audit/record.go
type Meta (line 9) | type Meta struct
type FuncMetaTypeConv (line 16) | type FuncMetaTypeConv
type Record (line 19) | type Record struct
method Success (line 32) | func (rec *Record) Success() {
method Fail (line 37) | func (rec *Record) Fail() {
method AddMeta (line 42) | func (rec *Record) AddMeta(name string, val interface{}) {
method AddMetaTypeConverter (line 67) | func (rec *Record) AddMetaTypeConverter(f FuncMetaTypeConv) {
FILE: server/services/audit/record_test.go
type bloated (line 12) | type bloated struct
type wilted (line 19) | type wilted struct
function conv (line 23) | func conv(val interface{}) (interface{}, bool) {
function TestRecord_AddMeta (line 30) | func TestRecord_AddMeta(t *testing.T) {
FILE: server/services/auth/email.go
function IsEmailValid (line 8) | func IsEmailValid(e string) bool {
FILE: server/services/auth/password.go
constant PasswordMaximumLength (line 11) | PasswordMaximumLength = 64
constant PasswordSpecialChars (line 12) | PasswordSpecialChars = "!\"\\#$%&'()*+,-./:;<=>?@[]^_`|~"
constant PasswordNumbers (line 13) | PasswordNumbers = "0123456789"
constant PasswordUpperCaseLetters (line 14) | PasswordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
constant PasswordLowerCaseLetters (line 15) | PasswordLowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"
constant PasswordAllChars (line 16) | PasswordAllChars = PasswordSpecialChars + PasswordNumbers + Pass...
constant InvalidLowercasePassword (line 18) | InvalidLowercasePassword = "lowercase"
constant InvalidMinLengthPassword (line 19) | InvalidMinLengthPassword = "min-length"
constant InvalidMaxLengthPassword (line 20) | InvalidMaxLengthPassword = "max-length"
constant InvalidNumberPassword (line 21) | InvalidNumberPassword = "number"
constant InvalidUppercasePassword (line 22) | InvalidUppercasePassword = "uppercase"
constant InvalidSymbolPassword (line 23) | InvalidSymbolPassword = "symbol"
function HashPassword (line 29) | func HashPassword(password string) string {
function ComparePassword (line 39) | func ComparePassword(hash, password string) bool {
type InvalidPasswordError (line 48) | type InvalidPasswordError struct
method Error (line 52) | func (ipe *InvalidPasswordError) Error() string {
type PasswordSettings (line 56) | type PasswordSettings struct
function IsPasswordValid (line 64) | func IsPasswordValid(password string, settings PasswordSettings) error {
FILE: server/services/auth/password_test.go
function TestPasswordHash (line 11) | func TestPasswordHash(t *testing.T) {
function TestIsPasswordValidWithSettings (line 18) | func TestIsPasswordValidWithSettings(t *testing.T) {
FILE: server/services/auth/request_parser.go
constant HeaderToken (line 12) | HeaderToken = "token"
constant HeaderAuth (line 13) | HeaderAuth = "Authorization"
constant HeaderBearer (line 14) | HeaderBearer = "BEARER"
constant SessionCookieToken (line 15) | SessionCookieToken = "FOCALBOARDAUTHTOKEN"
type TokenLocation (line 18) | type TokenLocation
method String (line 27) | func (tl TokenLocation) String() string {
constant TokenLocationNotFound (line 21) | TokenLocationNotFound TokenLocation = iota
constant TokenLocationHeader (line 22) | TokenLocationHeader
constant TokenLocationCookie (line 23) | TokenLocationCookie
constant TokenLocationQueryString (line 24) | TokenLocationQueryString
function ParseAuthTokenFromRequest (line 42) | func ParseAuthTokenFromRequest(r *http.Request) (string, TokenLocation) {
FILE: server/services/auth/request_parser_test.go
function TestParseAuthTokenFromRequest (line 12) | func TestParseAuthTokenFromRequest(t *testing.T) {
FILE: server/services/config/config.go
constant DefaultServerRoot (line 10) | DefaultServerRoot = "http://localhost:8000"
constant DefaultPort (line 11) | DefaultPort = 8000
constant DBPingAttempts (line 12) | DBPingAttempts = 5
type AmazonS3Config (line 15) | type AmazonS3Config struct
type Configuration (line 30) | type Configuration struct
function ReadConfigFile (line 75) | func ReadConfigFile(configFilePath string) (*Configuration, error) {
function removeSecurityData (line 132) | func removeSecurityData(config Configuration) Configuration {
FILE: server/services/metrics/metrics.go
constant MetricsNamespace (line 11) | MetricsNamespace = "focalboard"
constant MetricsSubsystemBlocks (line 12) | MetricsSubsystemBlocks = "blocks"
constant MetricsSubsystemBoards (line 13) | MetricsSubsystemBoards = "boards"
constant MetricsSubsystemTeams (line 14) | MetricsSubsystemTeams = "teams"
constant MetricsSubsystemSystem (line 15) | MetricsSubsystemSystem = "system"
constant MetricsCloudInstallationLabel (line 17) | MetricsCloudInstallationLabel = "installationId"
type InstanceInfo (line 20) | type InstanceInfo struct
type Metrics (line 28) | type Metrics struct
method IncrementLoginCount (line 178) | func (m *Metrics) IncrementLoginCount(num int) {
method IncrementLogoutCount (line 184) | func (m *Metrics) IncrementLogoutCount(num int) {
method IncrementLoginFailCount (line 190) | func (m *Metrics) IncrementLoginFailCount(num int) {
method IncrementBlocksInserted (line 196) | func (m *Metrics) IncrementBlocksInserted(num int) {
method IncrementBlocksPatched (line 203) | func (m *Metrics) IncrementBlocksPatched(num int) {
method IncrementBlocksDeleted (line 210) | func (m *Metrics) IncrementBlocksDeleted(num int) {
method ObserveBlockCount (line 217) | func (m *Metrics) ObserveBlockCount(blockType string, count int64) {
method ObserveBoardCount (line 223) | func (m *Metrics) ObserveBoardCount(count int64) {
method ObserveTeamCount (line 229) | func (m *Metrics) ObserveTeamCount(count int64) {
function NewMetrics (line 50) | func NewMetrics(info InstanceInfo) *Metrics {
FILE: server/services/metrics/service.go
type Service (line 13) | type Service struct
method Run (line 30) | func (h *Service) Run() error {
method Shutdown (line 35) | func (h *Service) Shutdown() error {
function NewMetricsServer (line 18) | func NewMetricsServer(address string, metricsService *Metrics, logger ml...
FILE: server/services/notify/notifylogger/logger_backend.go
constant backendName (line 13) | backendName = "notifyLogger"
type Backend (line 16) | type Backend struct
method Start (line 28) | func (b *Backend) Start() error {
method ShutDown (line 32) | func (b *Backend) ShutDown() error {
method BlockChanged (line 37) | func (b *Backend) BlockChanged(evt notify.BlockChangeEvent) error {
method Name (line 57) | func (b *Backend) Name() string {
function New (line 21) | func New(logger mlog.LoggerIFace, level mlog.Level) *Backend {
FILE: server/services/notify/notifymentions/app_api.go
type AppAPI (line 7) | type AppAPI interface
FILE: server/services/notify/notifymentions/delivery.go
type MentionDelivery (line 15) | type MentionDelivery interface
FILE: server/services/notify/notifymentions/extract.go
constant defPrefixLines (line 9) | defPrefixLines = 2
constant defPrefixMaxChars (line 10) | defPrefixMaxChars = 100
constant defSuffixLines (line 11) | defSuffixLines = 2
constant defSuffixMaxChars (line 12) | defSuffixMaxChars = 100
type limits (line 15) | type limits struct
function newLimits (line 22) | func newLimits() limits {
function extractText (line 35) | func extractText(s string, mention string, limits limits) string {
function safeConcat (line 64) | func safeConcat(lines []string, start int, end int) string {
function safeSubstr (line 79) | func safeSubstr(s string, start int, end int) string {
function min (line 86) | func min(a int, b int) int {
function max (line 93) | func max(a int, b int) int {
FILE: server/services/notify/notifymentions/extract_test.go
constant s0 (line 12) | s0 = "Zero is in the mind @billy."
constant s1 (line 13) | s1 = "This is line 1."
constant s2 (line 14) | s2 = "Line two is right here."
constant s3 (line 15) | s3 = "Three is the line I am."
constant s4 (line 16) | s4 = "'Four score and seven years...', said @lincoln."
constant s5 (line 17) | s5 = "Fast Five was arguably the best F&F film."
constant s6 (line 18) | s6 = "Big Hero 6 may have an inflated sense of self."
constant s7 (line 19) | s7 = "The seventh sign, @sarah, will be a failed unit test."
function join (line 34) | func join(s ...string) string {
function Test_extractText (line 38) | func Test_extractText(t *testing.T) {
function Test_safeConcat (line 66) | func Test_safeConcat(t *testing.T) {
function Test_safeSubstr (line 92) | func Test_safeSubstr(t *testing.T) {
FILE: server/services/notify/notifymentions/mentions.go
function extractMentions (line 19) | func extractMentions(block *model.Block) map[string]struct{} {
FILE: server/services/notify/notifymentions/mentions_backend.go
constant backendName (line 20) | backendName = "notifyMentions"
type MentionListener (line 27) | type MentionListener interface
type BackendParams (line 31) | type BackendParams struct
type Backend (line 39) | type Backend struct
method Start (line 58) | func (b *Backend) Start() error {
method ShutDown (line 62) | func (b *Backend) ShutDown() error {
method Name (line 67) | func (b *Backend) Name() string {
method AddListener (line 71) | func (b *Backend) AddListener(l MentionListener) {
method RemoveListener (line 78) | func (b *Backend) RemoveListener(l MentionListener) {
method BlockChanged (line 91) | func (b *Backend) BlockChanged(evt notify.BlockChangeEvent) error {
method deliverMentionNotification (line 163) | func (b *Backend) deliverMentionNotification(username string, extract ...
function New (line 49) | func New(params BackendParams) *Backend {
function safeCallListener (line 153) | func safeCallListener(listener MentionListener, userID string, evt notif...
FILE: server/services/notify/notifymentions/mentions_test.go
function Test_extractMentions (line 15) | func Test_extractMentions(t *testing.T) {
function makeBlock (line 38) | func makeBlock(text string) *model.Block {
function makeMap (line 46) | func makeMap(mentions ...string) map[string]struct{} {
FILE: server/services/notify/notifysubscriptions/app_api.go
type AppAPI (line 12) | type AppAPI interface
FILE: server/services/notify/notifysubscriptions/delivery.go
type SubscriptionDelivery (line 14) | type SubscriptionDelivery interface
FILE: server/services/notify/notifysubscriptions/diff.go
type Diff (line 16) | type Diff struct
type PropDiff (line 33) | type PropDiff struct
type SchemaDiff (line 41) | type SchemaDiff struct
type diffGenerator (line 48) | type diffGenerator struct
method generateDiffs (line 58) | func (dg *diffGenerator) generateDiffs() ([]*Diff, error) {
method generateDiffsForCard (line 144) | func (dg *diffGenerator) generateDiffsForCard(card *model.Block, schem...
method generateDiffForBlock (line 207) | func (dg *diffGenerator) generateDiffForBlock(newBlock *model.Block, s...
method generatePropDiffs (line 293) | func (dg *diffGenerator) generatePropDiffs(oldBlock, newBlock *model.B...
function sortPropDiffs (line 355) | func sortPropDiffs(propDiffs []PropDiff) []PropDiff {
FILE: server/services/notify/notifysubscriptions/diff2markdown.go
function generateMarkdownDiff (line 11) | func generateMarkdownDiff(oldText string, newText string, logger mlog.Lo...
constant truncLenEquals (line 49) | truncLenEquals = 60
constant truncLenInserts (line 50) | truncLenInserts = 120
constant truncLenDeletes (line 51) | truncLenDeletes = 80
type markDownCfg (line 54) | type markDownCfg struct
function generateMarkdown (line 61) | func generateMarkdown(diffs []diffmatchpatch.Diff, cfg markDownCfg) stri...
function truncate (line 88) | func truncate(s string, maxLen int, first bool, last bool) string {
function normalizeText (line 115) | func normalizeText(s string) string {
function leftWords (line 125) | func leftWords(s string, maxLen int) string {
function rightWords (line 137) | func rightWords(s string, maxLen int) string {
function reverse (line 154) | func reverse(ss []string) {
function words (line 162) | func words(words []string, maxChars int) []string {
FILE: server/services/notify/notifysubscriptions/diff2markdown_test.go
function Test_reverse (line 9) | func Test_reverse(t *testing.T) {
FILE: server/services/notify/notifysubscriptions/diff2slackattachments.go
constant defAddCardNotify (line 23) | defAddCardNotify = "{{.Authors | printAuthors \"unknown_user\" }} has...
constant defModifyCardNotify (line 24) | defModifyCardNotify = "###### {{.Authors | printAuthors \"unknown_user\"...
constant defDeleteCardNotify (line 25) | defDeleteCardNotify = "{{.Authors | printAuthors \"unknown_user\" }} has...
type DiffConvOpts (line 35) | type DiffConvOpts struct
function getTemplate (line 43) | func getTemplate(name string, opts DiffConvOpts, def string) (*template....
function makeAuthorsList (line 90) | func makeAuthorsList(authors StringMap, empty string) string {
function execTemplate (line 106) | func execTemplate(w io.Writer, name string, opts DiffConvOpts, def strin...
function Diffs2SlackAttachments (line 115) | func Diffs2SlackAttachments(diffs []*Diff, opts DiffConvOpts) ([]*mm_mod...
function cardDiff2SlackAttachment (line 136) | func cardDiff2SlackAttachment(cardDiff *Diff, opts DiffConvOpts) (*mm_mo...
function appendTitleChanges (line 204) | func appendTitleChanges(fields []*mm_model.SlackAttachmentField, cardDif...
function appendPropertyChanges (line 215) | func appendPropertyChanges(fields []*mm_model.SlackAttachmentField, card...
function appendCommentChanges (line 241) | func appendCommentChanges(fields []*mm_model.SlackAttachmentField, cardD...
function appendAttachmentChanges (line 270) | func appendAttachmentChanges(fields []*mm_model.SlackAttachmentField, ca...
function appendContentChanges (line 295) | func appendContentChanges(fields []*mm_model.SlackAttachmentField, cardD...
FILE: server/services/notify/notifysubscriptions/notifier.go
constant defBlockNotificationFreq (line 21) | defBlockNotificationFreq = time.Minute * 2
constant enqueueNotifyHintTimeout (line 22) | enqueueNotifyHintTimeout = time.Second * 10
constant hintQueueSize (line 23) | hintQueueSize = 20
type notifier (line 33) | type notifier struct
method start (line 58) | func (n *notifier) start() {
method stop (line 68) | func (n *notifier) stop() {
method loop (line 78) | func (n *notifier) loop() {
method onNotifyHint (line 117) | func (n *notifier) onNotifyHint(hint *model.NotificationHint) error {
method notify (line 128) | func (n *notifier) notify() {
method notifySubscribers (line 148) | func (n *notifier) notifySubscribers(hint *model.NotificationHint) err...
function newNotifier (line 46) | func newNotifier(params BackendParams) *notifier {
FILE: server/services/notify/notifysubscriptions/subscriptions_backend.go
constant backendName (line 21) | backendName = "notifySubscriptions"
type BackendParams (line 24) | type BackendParams struct
type Backend (line 35) | type Backend struct
method Start (line 57) | func (b *Backend) Start() error {
method ShutDown (line 66) | func (b *Backend) ShutDown() error {
method Name (line 73) | func (b *Backend) Name() string {
method getBlockUpdateFreq (line 77) | func (b *Backend) getBlockUpdateFreq(blockType model.BlockType) time.D...
method BlockChanged (line 96) | func (b *Backend) BlockChanged(evt notify.BlockChangeEvent) error {
method notifySubscribers (line 160) | func (b *Backend) notifySubscribers(subs []*model.Subscriber, blockID ...
method OnMention (line 184) | func (b *Backend) OnMention(userID string, evt notify.BlockChangeEvent) {
function New (line 45) | func New(params BackendParams) *Backend {
FILE: server/services/notify/notifysubscriptions/util.go
function getBoardDescription (line 12) | func getBoardDescription(board *model.Block) string {
function stripNewlines (line 30) | func stripNewlines(s string) string {
type StringMap (line 34) | type StringMap
method Add (line 36) | func (sm StringMap) Add(k string, v string) {
method Append (line 40) | func (sm StringMap) Append(m StringMap) {
method Keys (line 46) | func (sm StringMap) Keys() []string {
method Values (line 54) | func (sm StringMap) Values() []string {
FILE: server/services/notify/plugindelivery/mention_deliver.go
method MentionDeliver (line 16) | func (pd *PluginDelivery) MentionDeliver(mentionedUser *mm_model.User, e...
FILE: server/services/notify/plugindelivery/message.go
constant defCommentTemplate (line 14) | defCommentTemplate = "@%s mentioned you in a comment on the card [%s...
constant defDescriptionTemplate (line 15) | defDescriptionTemplate = "@%s mentioned you in the card [%s](%s) in boar...
function formatMessage (line 18) | func formatMessage(author string, extract string, card string, link stri...
FILE: server/services/notify/plugindelivery/plugin_delivery.go
type servicesAPI (line 10) | type servicesAPI interface
type PluginDelivery (line 39) | type PluginDelivery struct
function New (line 46) | func New(botID string, serverRoot string, api servicesAPI) *PluginDelive...
FILE: server/services/notify/plugindelivery/subscription_deliver.go
method SubscriptionDeliverSlackAttachments (line 20) | func (pd *PluginDelivery) SubscriptionDeliverSlackAttachments(teamID str...
method getDirectChannelID (line 48) | func (pd *PluginDelivery) getDirectChannelID(teamID string, subscriberID...
method getDirectChannel (line 67) | func (pd *PluginDelivery) getDirectChannel(teamID string, userID string,...
FILE: server/services/notify/plugindelivery/user.go
constant usernameSpecialChars (line 15) | usernameSpecialChars = ".-_ "
method UserByUsername (line 18) | func (pd *PluginDelivery) UserByUsername(username string) (*mm_model.Use...
function trimUsernameSpecialChar (line 47) | func trimUsernameSpecialChar(word string) (string, bool) {
FILE: server/services/notify/plugindelivery/user_test.go
function Test_userByUsername (line 47) | func Test_userByUsername(t *testing.T) {
type servicesAPIMock (line 82) | type servicesAPIMock struct
method GetUserByUsername (line 92) | func (m servicesAPIMock) GetUserByUsername(name string) (*mm_model.Use...
method GetDirectChannel (line 100) | func (m servicesAPIMock) GetDirectChannel(userID1, userID2 string) (*m...
method GetDirectChannelOrCreate (line 104) | func (m servicesAPIMock) GetDirectChannelOrCreate(userID1, userID2 str...
method CreatePost (line 108) | func (m servicesAPIMock) CreatePost(post *mm_model.Post) (*mm_model.Po...
method GetUserByID (line 112) | func (m servicesAPIMock) GetUserByID(userID string) (*mm_model.User, e...
method GetTeamMember (line 121) | func (m servicesAPIMock) GetTeamMember(teamID string, userID string) (...
method GetChannelByID (line 138) | func (m servicesAPIMock) GetChannelByID(channelID string) (*mm_model.C...
method GetChannelMember (line 142) | func (m servicesAPIMock) GetChannelMember(channelID string, userID str...
method CreateMember (line 146) | func (m servicesAPIMock) CreateMember(teamID string, userID string) (*...
function newServicesAPIMock (line 86) | func newServicesAPIMock(users map[string]*mm_model.User) servicesAPIMock {
FILE: server/services/notify/service.go
type Action (line 15) | type Action
constant Add (line 18) | Add Action = "add"
constant Update (line 19) | Update Action = "update"
constant Delete (line 20) | Delete Action = "delete"
type BlockChangeEvent (line 23) | type BlockChangeEvent struct
type Backend (line 34) | type Backend interface
type Service (line 42) | type Service struct
method AddBackend (line 67) | func (s *Service) AddBackend(backend Backend) error {
method Shutdown (line 78) | func (s *Service) Shutdown() error {
method BlockChanged (line 94) | func (s *Service) BlockChanged(evt BlockChangeEvent) {
function New (line 49) | func New(logger mlog.LoggerIFace, backends ...Backend) (*Service, error) {
FILE: server/services/permissions/localpermissions/helpers_test.go
type TestHelper (line 19) | type TestHelper struct
method checkBoardPermissions (line 37) | func (th *TestHelper) checkBoardPermissions(roleName string, member *m...
function SetupTestHelper (line 26) | func SetupTestHelper(t *testing.T) *TestHelper {
FILE: server/services/permissions/localpermissions/localpermissions.go
type Service (line 14) | type Service struct
method HasPermissionTo (line 26) | func (s *Service) HasPermissionTo(userID string, permission *mmModel.P...
method HasPermissionToTeam (line 30) | func (s *Service) HasPermissionToTeam(userID, teamID string, permissio...
method HasPermissionToChannel (line 40) | func (s *Service) HasPermissionToChannel(userID, channelID string, per...
method HasPermissionToBoard (line 47) | func (s *Service) HasPermissionToBoard(userID, boardID string, permiss...
function New (line 19) | func New(store permissions.Store, logger mlog.LoggerIFace) *Service {
FILE: server/services/permissions/localpermissions/localpermissions_test.go
function TestHasPermissionToTeam (line 17) | func TestHasPermissionToTeam(t *testing.T) {
function TestHasPermissionToBoard (line 37) | func TestHasPermissionToBoard(t *testing.T) {
FILE: server/services/permissions/mmpermissions/helpers_test.go
type TestHelper (line 20) | type TestHelper struct
method checkBoardPermissions (line 42) | func (th *TestHelper) checkBoardPermissions(roleName string, member *m...
function SetupTestHelper (line 28) | func SetupTestHelper(t *testing.T) *TestHelper {
FILE: server/services/permissions/mmpermissions/mmpermissions.go
type APIInterface (line 14) | type APIInterface interface
type Service (line 20) | type Service struct
method HasPermissionTo (line 34) | func (s *Service) HasPermissionTo(userID string, permission *mmModel.P...
method HasPermissionToTeam (line 41) | func (s *Service) HasPermissionToTeam(userID, teamID string, permissio...
method HasPermissionToChannel (line 48) | func (s *Service) HasPermissionToChannel(userID, channelID string, per...
method HasPermissionToBoard (line 55) | func (s *Service) HasPermissionToBoard(userID, boardID string, permiss...
function New (line 26) | func New(store permissions.Store, api APIInterface, logger mlog.LoggerIF...
FILE: server/services/permissions/mmpermissions/mmpermissions_test.go
constant testTeamID (line 16) | testTeamID = "team-id"
constant testBoardID (line 17) | testBoardID = "board-id"
constant testUserID (line 18) | testUserID = "user-id"
function TestHasPermissionsToTeam (line 21) | func TestHasPermissionsToTeam(t *testing.T) {
function TestHasPermissionToBoard (line 58) | func TestHasPermissionToBoard(t *testing.T) {
FILE: server/services/permissions/mmpermissions/mocks/mockpluginapi.go
type MockAPI (line 17) | type MockAPI struct
method EXPECT (line 35) | func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
method AddChannelMember (line 40) | func (m *MockAPI) AddChannelMember(arg0, arg1 string) (*model.ChannelM...
method AddReaction (line 55) | func (m *MockAPI) AddReaction(arg0 *model.Reaction) (*model.Reaction, ...
method AddUserToChannel (line 70) | func (m *MockAPI) AddUserToChannel(arg0, arg1, arg2 string) (*model.Ch...
method CopyFileInfos (line 85) | func (m *MockAPI) CopyFileInfos(arg0 string, arg1 []string) ([]string,...
method CreateBot (line 100) | func (m *MockAPI) CreateBot(arg0 *model.Bot) (*model.Bot, *model.AppEr...
method CreateChannel (line 115) | func (m *MockAPI) CreateChannel(arg0 *model.Channel) (*model.Channel, ...
method CreateChannelSidebarCategory (line 130) | func (m *MockAPI) CreateChannelSidebarCategory(arg0, arg1 string, arg2...
method CreateCommand (line 145) | func (m *MockAPI) CreateCommand(arg0 *model.Command) (*model.Command, ...
method CreateOAuthApp (line 160) | func (m *MockAPI) CreateOAuthApp(arg0 *model.OAuthApp) (*model.OAuthAp...
method CreatePost (line 175) | func (m *MockAPI) CreatePost(arg0 *model.Post) (*model.Post, *model.Ap...
method CreateSession (line 190) | func (m *MockAPI) CreateSession(arg0 *model.Session) (*model.Session, ...
method CreateTeam (line 205) | func (m *MockAPI) CreateTeam(arg0 *model.Team) (*model.Team, *model.Ap...
method CreateTeamMember (line 220) | func (m *MockAPI) CreateTeamMember(arg0, arg1 string) (*model.TeamMemb...
method CreateTeamMembers (line 235) | func (m *MockAPI) CreateTeamMembers(arg0 string, arg1 []string, arg2 s...
method CreateTeamMembersGracefully (line 250) | func (m *MockAPI) CreateTeamMembersGracefully(arg0 string, arg1 []stri...
method CreateUploadSession (line 265) | func (m *MockAPI) CreateUploadSession(arg0 *model.UploadSession) (*mod...
method CreateUser (line 280) | func (m *MockAPI) CreateUser(arg0 *model.User) (*model.User, *model.Ap...
method CreateUserAccessToken (line 295) | func (m *MockAPI) CreateUserAccessToken(arg0 *model.UserAccessToken) (...
method DeleteChannel (line 310) | func (m *MockAPI) DeleteChannel(arg0 string) *model.AppError {
method DeleteChannelMember (line 324) | func (m *MockAPI) DeleteChannelMember(arg0, arg1 string) *model.AppErr...
method DeleteCommand (line 338) | func (m *MockAPI) DeleteCommand(arg0 string) error {
method DeleteEphemeralPost (line 352) | func (m *MockAPI) DeleteEphemeralPost(arg0, arg1 string) {
method DeleteOAuthApp (line 364) | func (m *MockAPI) DeleteOAuthApp(arg0 string) *model.AppError {
method DeletePost (line 378) | func (m *MockAPI) DeletePost(arg0 string) *model.AppError {
method DeletePreferencesForUser (line 392) | func (m *MockAPI) DeletePreferencesForUser(arg0 string, arg1 []model.P...
method DeleteTeam (line 406) | func (m *MockAPI) DeleteTeam(arg0 string) *model.AppError {
method DeleteTeamMember (line 420) | func (m *MockAPI) DeleteTeamMember(arg0, arg1, arg2 string) *model.App...
method DeleteUser (line 434) | func (m *MockAPI) DeleteUser(arg0 string) *model.AppError {
method DisablePlugin (line 448) | func (m *MockAPI) DisablePlugin(arg0 string) *model.AppError {
method EnablePlugin (line 462) | func (m *MockAPI) EnablePlugin(arg0 string) *model.AppError {
method EnsureBotUser (line 476) | func (m *MockAPI) EnsureBotUser(arg0 *model.Bot) (string, error) {
method ExecuteSlashCommand (line 491) | func (m *MockAPI) ExecuteSlashCommand(arg0 *model.CommandArgs) (*model...
method ExtendSessionExpiry (line 506) | func (m *MockAPI) ExtendSessionExpiry(arg0 string, arg1 int64) *model....
method GetBot (line 520) | func (m *MockAPI) GetBot(arg0 string, arg1 bool) (*model.Bot, *model.A...
method GetBots (line 535) | func (m *MockAPI) GetBots(arg0 *model.BotGetOptions) ([]*model.Bot, *m...
method GetBundlePath (line 550) | func (m *MockAPI) GetBundlePath() (string, error) {
method GetChannel (line 565) | func (m *MockAPI) GetChannel(arg0 string) (*model.Channel, *model.AppE...
method GetChannelByName (line 580) | func (m *MockAPI) GetChannelByName(arg0, arg1 string, arg2 bool) (*mod...
method GetChannelByNameForTeamName (line 595) | func (m *MockAPI) GetChannelByNameForTeamName(arg0, arg1 string, arg2 ...
method GetChannelMember (line 610) | func (m *MockAPI) GetChannelMember(arg0, arg1 string) (*model.ChannelM...
method GetChannelMembers (line 625) | func (m *MockAPI) GetChannelMembers(arg0 string, arg1, arg2 int) (mode...
method GetChannelMembersByIds (line 640) | func (m *MockAPI) GetChannelMembersByIds(arg0 string, arg1 []string) (...
method GetChannelMembersForUser (line 655) | func (m *MockAPI) GetChannelMembersForUser(arg0, arg1 string, arg2, ar...
method GetChannelSidebarCategories (line 670) | func (m *MockAPI) GetChannelSidebarCategories(arg0, arg1 string) (*mod...
method GetChannelStats (line 685) | func (m *MockAPI) GetChannelStats(arg0 string) (*model.ChannelStats, *...
method GetChannelsForTeamForUser (line 700) | func (m *MockAPI) GetChannelsForTeamForUser(arg0, arg1 string, arg2 bo...
method GetCommand (line 715) | func (m *MockAPI) GetCommand(arg0 string) (*model.Command, error) {
method GetConfig (line 730) | func (m *MockAPI) GetConfig() *model.Config {
method GetDiagnosticId (line 744) | func (m *MockAPI) GetDiagnosticId() string {
method GetDirectChannel (line 758) | func (m *MockAPI) GetDirectChannel(arg0, arg1 string) (*model.Channel,...
method GetEmoji (line 773) | func (m *MockAPI) GetEmoji(arg0 string) (*model.Emoji, *model.AppError) {
method GetEmojiByName (line 788) | func (m *MockAPI) GetEmojiByName(arg0 string) (*model.Emoji, *model.Ap...
method GetEmojiImage (line 803) | func (m *MockAPI) GetEmojiImage(arg0 string) ([]byte, string, *model.A...
method GetEmojiList (line 819) | func (m *MockAPI) GetEmojiList(arg0 string, arg1, arg2 int) ([]*model....
method GetFile (line 834) | func (m *MockAPI) GetFile(arg0 string) ([]byte, *model.AppError) {
method GetFileInfo (line 849) | func (m *MockAPI) GetFileInfo(arg0 string) (*model.FileInfo, *model.Ap...
method GetFileInfos (line 864) | func (m *MockAPI) GetFileInfos(arg0, arg1 int, arg2 *model.GetFileInfo...
method GetFileLink (line 879) | func (m *MockAPI) GetFileLink(arg0 string) (string, *model.AppError) {
method GetGroup (line 894) | func (m *MockAPI) GetGroup(arg0 string) (*model.Group, *model.AppError) {
method GetGroupByName (line 909) | func (m *MockAPI) GetGroupByName(arg0 string) (*model.Group, *model.Ap...
method GetGroupChannel (line 924) | func (m *MockAPI) GetGroupChannel(arg0 []string) (*model.Channel, *mod...
method GetGroupMemberUsers (line 939) | func (m *MockAPI) GetGroupMemberUsers(arg0 string, arg1, arg2 int) ([]...
method GetGroupsBySource (line 954) | func (m *MockAPI) GetGroupsBySource(arg0 model.GroupSource) ([]*model....
method GetGroupsForUser (line 969) | func (m *MockAPI) GetGroupsForUser(arg0 string) ([]*model.Group, *mode...
method GetLDAPUserAttributes (line 984) | func (m *MockAPI) GetLDAPUserAttributes(arg0 string, arg1 []string) (m...
method GetLicense (line 999) | func (m *MockAPI) GetLicense() *model.License {
method GetOAuthApp (line 1013) | func (m *MockAPI) GetOAuthApp(arg0 string) (*model.OAuthApp, *model.Ap...
method GetPluginConfig (line 1028) | func (m *MockAPI) GetPluginConfig() map[string]interface{} {
method GetPluginStatus (line 1042) | func (m *MockAPI) GetPluginStatus(arg0 string) (*model.PluginStatus, *...
method GetPlugins (line 1057) | func (m *MockAPI) GetPlugins() ([]*model.Manifest, *model.AppError) {
method GetPost (line 1072) | func (m *MockAPI) GetPost(arg0 string) (*model.Post, *model.AppError) {
method GetPostThread (line 1087) | func (m *MockAPI) GetPostThread(arg0 string) (*model.PostList, *model....
method GetPostsAfter (line 1102) | func (m *MockAPI) GetPostsAfter(arg0, arg1 string, arg2, arg3 int) (*m...
method GetPostsBefore (line 1117) | func (m *MockAPI) GetPostsBefore(arg0, arg1 string, arg2, arg3 int) (*...
method GetPostsForChannel (line 1132) | func (m *MockAPI) GetPostsForChannel(arg0 string, arg1, arg2 int) (*mo...
method GetPostsSince (line 1147) | func (m *MockAPI) GetPostsSince(arg0 string, arg1 int64) (*model.PostL...
method GetPreferencesForUser (line 1162) | func (m *MockAPI) GetPreferencesForUser(arg0 string) ([]model.Preferen...
method GetProfileImage (line 1177) | func (m *MockAPI) GetProfileImage(arg0 string) ([]byte, *model.AppErro...
method GetPublicChannelsForTeam (line 1192) | func (m *MockAPI) GetPublicChannelsForTeam(arg0 string, arg1, arg2 int...
method GetReactions (line 1207) | func (m *MockAPI) GetReactions(arg0 string) ([]*model.Reaction, *model...
method GetServerVersion (line 1222) | func (m *MockAPI) GetServerVersion() string {
method GetSession (line 1236) | func (m *MockAPI) GetSession(arg0 string) (*model.Session, *model.AppE...
method GetSystemInstallDate (line 1251) | func (m *MockAPI) GetSystemInstallDate() (int64, *model.AppError) {
method GetTeam (line 1266) | func (m *MockAPI) GetTeam(arg0 string) (*model.Team, *model.AppError) {
method GetTeamByName (line 1281) | func (m *MockAPI) GetTeamByName(arg0 string) (*model.Team, *model.AppE...
method GetTeamIcon (line 1296) | func (m *MockAPI) GetTeamIcon(arg0 string) ([]byte, *model.AppError) {
method GetTeamMember (line 1311) | func (m *MockAPI) GetTeamMember(arg0, arg1 string) (*model.TeamMember,...
method GetTeamMembers (line 1326) | func (m *MockAPI) GetTeamMembers(arg0 string, arg1, arg2 int) ([]*mode...
method GetTeamMembersForUser (line 1341) | func (m *MockAPI) GetTeamMembersForUser(arg0 string, arg1, arg2 int) (...
method GetTeamStats (line 1356) | func (m *MockAPI) GetTeamStats(arg0 string) (*model.TeamStats, *model....
method GetTeams (line 1371) | func (m *MockAPI) GetTeams() ([]*model.Team, *model.AppError) {
method GetTeamsForUser (line 1386) | func (m *MockAPI) GetTeamsForUser(arg0 string) ([]*model.Team, *model....
method GetTeamsUnreadForUser (line 1401) | func (m *MockAPI) GetTeamsUnreadForUser(arg0 string) ([]*model.TeamUnr...
method GetTelemetryId (line 1416) | func (m *MockAPI) GetTelemetryId() string {
method GetUnsanitizedConfig (line 1430) | func (m *MockAPI) GetUnsanitizedConfig() *model.Config {
method GetUploadSession (line 1444) | func (m *MockAPI) GetUploadSession(arg0 string) (*model.UploadSession,...
method GetUser (line 1459) | func (m *MockAPI) GetUser(arg0 string) (*model.User, *model.AppError) {
method GetUserByEmail (line 1474) | func (m *MockAPI) GetUserByEmail(arg0 string) (*model.User, *model.App...
method GetUserByUsername (line 1489) | func (m *MockAPI) GetUserByUsername(arg0 string) (*model.User, *model....
method GetUserStatus (line 1504) | func (m *MockAPI) GetUserStatus(arg0 string) (*model.Status, *model.Ap...
method GetUserStatusesByIds (line 1519) | func (m *MockAPI) GetUserStatusesByIds(arg0 []string) ([]*model.Status...
method GetUsers (line 1534) | func (m *MockAPI) GetUsers(arg0 *model.UserGetOptions) ([]*model.User,...
method GetUsersByUsernames (line 1549) | func (m *MockAPI) GetUsersByUsernames(arg0 []string) ([]*model.User, *...
method GetUsersInChannel (line 1564) | func (m *MockAPI) GetUsersInChannel(arg0, arg1 string, arg2, arg3 int)...
method GetUsersInTeam (line 1579) | func (m *MockAPI) GetUsersInTeam(arg0 string, arg1, arg2 int) ([]*mode...
method HasPermissionTo (line 1594) | func (m *MockAPI) HasPermissionTo(arg0 string, arg1 *model.Permission)...
method HasPermissionToChannel (line 1608) | func (m *MockAPI) HasPermissionToChannel(arg0, arg1 string, arg2 *mode...
method HasPermissionToTeam (line 1622) | func (m *MockAPI) HasPermissionToTeam(arg0, arg1 string, arg2 *model.P...
method InstallPlugin (line 1636) | func (m *MockAPI) InstallPlugin(arg0 io.Reader, arg1 bool) (*model.Man...
method IsEnterpriseReady (line 1651) | func (m *MockAPI) IsEnterpriseReady() bool {
method KVCompareAndDelete (line 1665) | func (m *MockAPI) KVCompareAndDelete(arg0 string, arg1 []byte) (bool, ...
method KVCompareAndSet (line 1680) | func (m *MockAPI) KVCompareAndSet(arg0 string, arg1, arg2 []byte) (boo...
method KVDelete (line 1695) | func (m *MockAPI) KVDelete(arg0 string) *model.AppError {
method KVDeleteAll (line 1709) | func (m *MockAPI) KVDeleteAll() *model.AppError {
method KVGet (line 1723) | func (m *MockAPI) KVGet(arg0 string) ([]byte, *model.AppError) {
method KVList (line 1738) | func (m *MockAPI) KVList(arg0, arg1 int) ([]string, *model.AppError) {
method KVSet (line 1753) | func (m *MockAPI) KVSet(arg0 string, arg1 []byte) *model.AppError {
method KVSetWithExpiry (line 1767) | func (m *MockAPI) KVSetWithExpiry(arg0 string, arg1 []byte, arg2 int64...
method KVSetWithOptions (line 1781) | func (m *MockAPI) KVSetWithOptions(arg0 string, arg1 []byte, arg2 mode...
method ListBuiltInCommands (line 1796) | func (m *MockAPI) ListBuiltInCommands() ([]*model.Command, error) {
method ListCommands (line 1811) | func (m *MockAPI) ListCommands(arg0 string) ([]*model.Command, error) {
method ListCustomCommands (line 1826) | func (m *MockAPI) ListCustomCommands(arg0 string) ([]*model.Command, e...
method ListPluginCommands (line 1841) | func (m *MockAPI) ListPluginCommands(arg0 string) ([]*model.Command, e...
method LoadPluginConfiguration (line 1856) | func (m *MockAPI) LoadPluginConfiguration(arg0 interface{}) error {
method LogDebug (line 1870) | func (m *MockAPI) LogDebug(arg0 string, arg1 ...interface{}) {
method LogError (line 1887) | func (m *MockAPI) LogError(arg0 string, arg1 ...interface{}) {
method LogInfo (line 1904) | func (m *MockAPI) LogInfo(arg0 string, arg1 ...interface{}) {
method LogWarn (line 1921) | func (m *MockAPI) LogWarn(arg0 string, arg1 ...interface{}) {
method OpenInteractiveDialog (line 1938) | func (m *MockAPI) OpenInteractiveDialog(arg0 model.OpenDialogRequest) ...
method PatchBot (line 1952) | func (m *MockAPI) PatchBot(arg0 string, arg1 *model.BotPatch) (*model....
method PermanentDeleteBot (line 1967) | func (m *MockAPI) PermanentDeleteBot(arg0 string) *model.AppError {
method PluginHTTP (line 1981) | func (m *MockAPI) PluginHTTP(arg0 *http.Request) *http.Response {
method PublishPluginClusterEvent (line 1995) | func (m *MockAPI) PublishPluginClusterEvent(arg0 model.PluginClusterEv...
method PublishUserTyping (line 2009) | func (m *MockAPI) PublishUserTyping(arg0, arg1, arg2 string) *model.Ap...
method PublishWebSocketEvent (line 2023) | func (m *MockAPI) PublishWebSocketEvent(arg0 string, arg1 map[string]i...
method ReadFile (line 2035) | func (m *MockAPI) ReadFile(arg0 string) ([]byte, *model.AppError) {
method RegisterCollectionAndTopic (line 2050) | func (m *MockAPI) RegisterCollectionAndTopic(arg0, arg1 string) error {
method RegisterCommand (line 2064) | func (m *MockAPI) RegisterCommand(arg0 *model.Command) error {
method RemovePlugin (line 2078) | func (m *MockAPI) RemovePlugin(arg0 string) *model.AppError {
method RemoveReaction (line 2092) | func (m *MockAPI) RemoveReaction(arg0 *model.Reaction) *model.AppError {
method RemoveTeamIcon (line 2106) | func (m *MockAPI) RemoveTeamIcon(arg0 string) *model.AppError {
method RemoveUserCustomStatus (line 2120) | func (m *MockAPI) RemoveUserCustomStatus(arg0 string) *model.AppError {
method RequestTrialLicense (line 2134) | func (m *MockAPI) RequestTrialLicense(arg0 string, arg1 int, arg2, arg...
method RevokeSession (line 2148) | func (m *MockAPI) RevokeSession(arg0 string) *model.AppError {
method RevokeUserAccessToken (line 2162) | func (m *MockAPI) RevokeUserAccessToken(arg0 string) *model.AppError {
method RolesGrantPermission (line 2176) | func (m *MockAPI) RolesGrantPermission(arg0 []string, arg1 string) bool {
method SaveConfig (line 2190) | func (m *MockAPI) SaveConfig(arg0 *model.Config) *model.AppError {
method SavePluginConfig (line 2204) | func (m *MockAPI) SavePluginConfig(arg0 map[string]interface{}) *model...
method SearchChannels (line 2218) | func (m *MockAPI) SearchChannels(arg0, arg1 string) ([]*model.Channel,...
method SearchPostsInTeam (line 2233) | func (m *MockAPI) SearchPostsInTeam(arg0 string, arg1 []*model.SearchP...
method SearchPostsInTeamForUser (line 2248) | func (m *MockAPI) SearchPostsInTeamForUser(arg0, arg1 string, arg2 mod...
method SearchTeams (line 2263) | func (m *MockAPI) SearchTeams(arg0 string) ([]*model.Team, *model.AppE...
method SearchUsers (line 2278) | func (m *MockAPI) SearchUsers(arg0 *model.UserSearch) ([]*model.User, ...
method SendEphemeralPost (line 2293) | func (m *MockAPI) SendEphemeralPost(arg0 string, arg1 *model.Post) *mo...
method SendMail (line 2307) | func (m *MockAPI) SendMail(arg0, arg1, arg2 string) *model.AppError {
method SetProfileImage (line 2321) | func (m *MockAPI) SetProfileImage(arg0 string, arg1 []byte) *model.App...
method SetTeamIcon (line 2335) | func (m *MockAPI) SetTeamIcon(arg0 string, arg1 []byte) *model.AppError {
method SetUserStatusTimedDND (line 2349) | func (m *MockAPI) SetUserStatusTimedDND(arg0 string, arg1 int64) (*mod...
method UnregisterCommand (line 2364) | func (m *MockAPI) UnregisterCommand(arg0, arg1 string) error {
method UpdateBotActive (line 2378) | func (m *MockAPI) UpdateBotActive(arg0 string, arg1 bool) (*model.Bot,...
method UpdateChannel (line 2393) | func (m *MockAPI) UpdateChannel(arg0 *model.Channel) (*model.Channel, ...
method UpdateChannelMemberNotifications (line 2408) | func (m *MockAPI) UpdateChannelMemberNotifications(arg0, arg1 string, ...
method UpdateChannelMemberRoles (line 2423) | func (m *MockAPI) UpdateChannelMemberRoles(arg0, arg1, arg2 string) (*...
method UpdateChannelSidebarCategories (line 2438) | func (m *MockAPI) UpdateChannelSidebarCategories(arg0, arg1 string, ar...
method UpdateCommand (line 2453) | func (m *MockAPI) UpdateCommand(arg0 string, arg1 *model.Command) (*mo...
method UpdateEphemeralPost (line 2468) | func (m *MockAPI) UpdateEphemeralPost(arg0 string, arg1 *model.Post) *...
method UpdateOAuthApp (line 2482) | func (m *MockAPI) UpdateOAuthApp(arg0 *model.OAuthApp) (*model.OAuthAp...
method UpdatePost (line 2497) | func (m *MockAPI) UpdatePost(arg0 *model.Post) (*model.Post, *model.Ap...
method UpdatePreferencesForUser (line 2512) | func (m *MockAPI) UpdatePreferencesForUser(arg0 string, arg1 []model.P...
method UpdateTeam (line 2526) | func (m *MockAPI) UpdateTeam(arg0 *model.Team) (*model.Team, *model.Ap...
method UpdateTeamMemberRoles (line 2541) | func (m *MockAPI) UpdateTeamMemberRoles(arg0, arg1, arg2 string) (*mod...
method UpdateUser (line 2556) | func (m *MockAPI) UpdateUser(arg0 *model.User) (*model.User, *model.Ap...
method UpdateUserActive (line 2571) | func (m *MockAPI) UpdateUserActive(arg0 string, arg1 bool) *model.AppE...
method UpdateUserCustomStatus (line 2585) | func (m *MockAPI) UpdateUserCustomStatus(arg0 string, arg1 *model.Cust...
method UpdateUserStatus (line 2599) | func (m *MockAPI) UpdateUserStatus(arg0, arg1 string) (*model.Status, ...
method UploadData (line 2614) | func (m *MockAPI) UploadData(arg0 *model.UploadSession, arg1 io.Reader...
method UploadFile (line 2629) | func (m *MockAPI) UploadFile(arg0 []byte, arg1, arg2 string) (*model.F...
type MockAPIMockRecorder (line 23) | type MockAPIMockRecorder struct
method AddChannelMember (line 49) | func (mr *MockAPIMockRecorder) AddChannelMember(arg0, arg1 interface{}...
method AddReaction (line 64) | func (mr *MockAPIMockRecorder) AddReaction(arg0 interface{}) *gomock.C...
method AddUserToChannel (line 79) | func (mr *MockAPIMockRecorder) AddUserToChannel(arg0, arg1, arg2 inter...
method CopyFileInfos (line 94) | func (mr *MockAPIMockRecorder) CopyFileInfos(arg0, arg1 interface{}) *...
method CreateBot (line 109) | func (mr *MockAPIMockRecorder) CreateBot(arg0 interface{}) *gomock.Call {
method CreateChannel (line 124) | func (mr *MockAPIMockRecorder) CreateChannel(arg0 interface{}) *gomock...
method CreateChannelSidebarCategory (line 139) | func (mr *MockAPIMockRecorder) CreateChannelSidebarCategory(arg0, arg1...
method CreateCommand (line 154) | func (mr *MockAPIMockRecorder) CreateCommand(arg0 interface{}) *gomock...
method CreateOAuthApp (line 169) | func (mr *MockAPIMockRecorder) CreateOAuthApp(arg0 interface{}) *gomoc...
method CreatePost (line 184) | func (mr *MockAPIMockRecorder) CreatePost(arg0 interface{}) *gomock.Ca...
method CreateSession (line 199) | func (mr *MockAPIMockRecorder) CreateSession(arg0 interface{}) *gomock...
method CreateTeam (line 214) | func (mr *MockAPIMockRecorder) CreateTeam(arg0 interface{}) *gomock.Ca...
method CreateTeamMember (line 229) | func (mr *MockAPIMockRecorder) CreateTeamMember(arg0, arg1 interface{}...
method CreateTeamMembers (line 244) | func (mr *MockAPIMockRecorder) CreateTeamMembers(arg0, arg1, arg2 inte...
method CreateTeamMembersGracefully (line 259) | func (mr *MockAPIMockRecorder) CreateTeamMembersGracefully(arg0, arg1,...
method CreateUploadSession (line 274) | func (mr *MockAPIMockRecorder) CreateUploadSession(arg0 interface{}) *...
method CreateUser (line 289) | func (mr *MockAPIMockRecorder) CreateUser(arg0 interface{}) *gomock.Ca...
method CreateUserAccessToken (line 304) | func (mr *MockAPIMockRecorder) CreateUserAccessToken(arg0 interface{})...
method DeleteChannel (line 318) | func (mr *MockAPIMockRecorder) DeleteChannel(arg0 interface{}) *gomock...
method DeleteChannelMember (line 332) | func (mr *MockAPIMockRecorder) DeleteChannelMember(arg0, arg1 interfac...
method DeleteCommand (line 346) | func (mr *MockAPIMockRecorder) DeleteCommand(arg0 interface{}) *gomock...
method DeleteEphemeralPost (line 358) | func (mr *MockAPIMockRecorder) DeleteEphemeralPost(arg0, arg1 interfac...
method DeleteOAuthApp (line 372) | func (mr *MockAPIMockRecorder) DeleteOAuthApp(arg0 interface{}) *gomoc...
method DeletePost (line 386) | func (mr *MockAPIMockRecorder) DeletePost(arg0 interface{}) *gomock.Ca...
method DeletePreferencesForUser (line 400) | func (mr *MockAPIMockRecorder) DeletePreferencesForUser(arg0, arg1 int...
method DeleteTeam (line 414) | func (mr *MockAPIMockRecorder) DeleteTeam(arg0 interface{}) *gomock.Ca...
method DeleteTeamMember (line 428) | func (mr *MockAPIMockRecorder) DeleteTeamMember(arg0, arg1, arg2 inter...
method DeleteUser (line 442) | func (mr *MockAPIMockRecorder) DeleteUser(arg0 interface{}) *gomock.Ca...
method DisablePlugin (line 456) | func (mr *MockAPIMockRecorder) DisablePlugin(arg0 interface{}) *gomock...
method EnablePlugin (line 470) | func (mr *MockAPIMockRecorder) EnablePlugin(arg0 interface{}) *gomock....
method EnsureBotUser (line 485) | func (mr *MockAPIMockRecorder) EnsureBotUser(arg0 interface{}) *gomock...
method ExecuteSlashCommand (line 500) | func (mr *MockAPIMockRecorder) ExecuteSlashCommand(arg0 interface{}) *...
method ExtendSessionExpiry (line 514) | func (mr *MockAPIMockRecorder) ExtendSessionExpiry(arg0, arg1 interfac...
method GetBot (line 529) | func (mr *MockAPIMockRecorder) GetBot(arg0, arg1 interface{}) *gomock....
method GetBots (line 544) | func (mr *MockAPIMockRecorder) GetBots(arg0 interface{}) *gomock.Call {
method GetBundlePath (line 559) | func (mr *MockAPIMockRecorder) GetBundlePath() *gomock.Call {
method GetChannel (line 574) | func (mr *MockAPIMockRecorder) GetChannel(arg0 interface{}) *gomock.Ca...
method GetChannelByName (line 589) | func (mr *MockAPIMockRecorder) GetChannelByName(arg0, arg1, arg2 inter...
method GetChannelByNameForTeamName (line 604) | func (mr *MockAPIMockRecorder) GetChannelByNameForTeamName(arg0, arg1,...
method GetChannelMember (line 619) | func (mr *MockAPIMockRecorder) GetChannelMember(arg0, arg1 interface{}...
method GetChannelMembers (line 634) | func (mr *MockAPIMockRecorder) GetChannelMembers(arg0, arg1, arg2 inte...
method GetChannelMembersByIds (line 649) | func (mr *MockAPIMockRecorder) GetChannelMembersByIds(arg0, arg1 inter...
method GetChannelMembersForUser (line 664) | func (mr *MockAPIMockRecorder) GetChannelMembersForUser(arg0, arg1, ar...
method GetChannelSidebarCategories (line 679) | func (mr *MockAPIMockRecorder) GetChannelSidebarCategories(arg0, arg1 ...
method GetChannelStats (line 694) | func (mr *MockAPIMockRecorder) GetChannelStats(arg0 interface{}) *gomo...
method GetChannelsForTeamForUser (line 709) | func (mr *MockAPIMockRecorder) GetChannelsForTeamForUser(arg0, arg1, a...
method GetCommand (line 724) | func (mr *MockAPIMockRecorder) GetCommand(arg0 interface{}) *gomock.Ca...
method GetConfig (line 738) | func (mr *MockAPIMockRecorder) GetConfig() *gomock.Call {
method GetDiagnosticId (line 752) | func (mr *MockAPIMockRecorder) GetDiagnosticId() *gomock.Call {
method GetDirectChannel (line 767) | func (mr *MockAPIMockRecorder) GetDirectChannel(arg0, arg1 interface{}...
method GetEmoji (line 782) | func (mr *MockAPIMockRecorder) GetEmoji(arg0 interface{}) *gomock.Call {
method GetEmojiByName (line 797) | func (mr *MockAPIMockRecorder) GetEmojiByName(arg0 interface{}) *gomoc...
method GetEmojiImage (line 813) | func (mr *MockAPIMockRecorder) GetEmojiImage(arg0 interface{}) *gomock...
method GetEmojiList (line 828) | func (mr *MockAPIMockRecorder) GetEmojiList(arg0, arg1, arg2 interface...
method GetFile (line 843) | func (mr *MockAPIMockRecorder) GetFile(arg0 interface{}) *gomock.Call {
method GetFileInfo (line 858) | func (mr *MockAPIMockRecorder) GetFileInfo(arg0 interface{}) *gomock.C...
method GetFileInfos (line 873) | func (mr *MockAPIMockRecorder) GetFileInfos(arg0, arg1, arg2 interface...
method GetFileLink (line 888) | func (mr *MockAPIMockRecorder) GetFileLink(arg0 interface{}) *gomock.C...
method GetGroup (line 903) | func (mr *MockAPIMockRecorder) GetGroup(arg0 interface{}) *gomock.Call {
method GetGroupByName (line 918) | func (mr *MockAPIMockRecorder) GetGroupByName(arg0 interface{}) *gomoc...
method GetGroupChannel (line 933) | func (mr *MockAPIMockRecorder) GetGroupChannel(arg0 interface{}) *gomo...
method GetGroupMemberUsers (line 948) | func (mr *MockAPIMockRecorder) GetGroupMemberUsers(arg0, arg1, arg2 in...
method GetGroupsBySource (line 963) | func (mr *MockAPIMockRecorder) GetGroupsBySource(arg0 interface{}) *go...
method GetGroupsForUser (line 978) | func (mr *MockAPIMockRecorder) GetGroupsForUser(arg0 interface{}) *gom...
method GetLDAPUserAttributes (line 993) | func (mr *MockAPIMockRecorder) GetLDAPUserAttributes(arg0, arg1 interf...
method GetLicense (line 1007) | func (mr *MockAPIMockRecorder) GetLicense() *gomock.Call {
method GetOAuthApp (line 1022) | func (mr *MockAPIMockRecorder) GetOAuthApp(arg0 interface{}) *gomock.C...
method GetPluginConfig (line 1036) | func (mr *MockAPIMockRecorder) GetPluginConfig() *gomock.Call {
method GetPluginStatus (line 1051) | func (mr *MockAPIMockRecorder) GetPluginStatus(arg0 interface{}) *gomo...
method GetPlugins (line 1066) | func (mr *MockAPIMockRecorder) GetPlugins() *gomock.Call {
method GetPost (line 1081) | func (mr *MockAPIMockRecorder) GetPost(arg0 interface{}) *gomock.Call {
method GetPostThread (line 1096) | func (mr *MockAPIMockRecorder) GetPostThread(arg0 interface{}) *gomock...
method GetPostsAfter (line 1111) | func (mr *MockAPIMockRecorder) GetPostsAfter(arg0, arg1, arg2, arg3 in...
method GetPostsBefore (line 1126) | func (mr *MockAPIMockRecorder) GetPostsBefore(arg0, arg1, arg2, arg3 i...
method GetPostsForChannel (line 1141) | func (mr *MockAPIMockRecorder) GetPostsForChannel(arg0, arg1, arg2 int...
method GetPostsSince (line 1156) | func (mr *MockAPIMockRecorder) GetPostsSince(arg0, arg1 interface{}) *...
method GetPreferencesForUser (line 1171) | func (mr *MockAPIMockRecorder) GetPreferencesForUser(arg0 interface{})...
method GetProfileImage (line 1186) | func (mr *MockAPIMockRecorder) GetProfileImage(arg0 interface{}) *gomo...
method GetPublicChannelsForTeam (line 1201) | func (mr *MockAPIMockRecorder) GetPublicChannelsForTeam(arg0, arg1, ar...
method GetReactions (line 1216) | func (mr *MockAPIMockRecorder) GetReactions(arg0 interface{}) *gomock....
method GetServerVersion (line 1230) | func (mr *MockAPIMockRecorder) GetServerVersion() *gomock.Call {
method GetSession (line 1245) | func (mr *MockAPIMockRecorder) GetSession(arg0 interface{}) *gomock.Ca...
method GetSystemInstallDate (line 1260) | func (mr *MockAPIMockRecorder) GetSystemInstallDate() *gomock.Call {
method GetTeam (line 1275) | func (mr *MockAPIMockRecorder) GetTeam(arg0 interface{}) *gomock.Call {
method GetTeamByName (line 1290) | func (mr *MockAPIMockRecorder) GetTeamByName(arg0 interface{}) *gomock...
method GetTeamIcon (line 1305) | func (mr *MockAPIMockRecorder) GetTeamIcon(arg0 interface{}) *gomock.C...
method GetTeamMember (line 1320) | func (mr *MockAPIMockRecorder) GetTeamMember(arg0, arg1 interface{}) *...
method GetTeamMembers (line 1335) | func (mr *MockAPIMockRecorder) GetTeamMembers(arg0, arg1, arg2 interfa...
method GetTeamMembersForUser (line 1350) | func (mr *MockAPIMockRecorder) GetTeamMembersForUser(arg0, arg1, arg2 ...
method GetTeamStats (line 1365) | func (mr *MockAPIMockRecorder) GetTeamStats(arg0 interface{}) *gomock....
method GetTeams (line 1380) | func (mr *MockAPIMockRecorder) GetTeams() *gomock.Call {
method GetTeamsForUser (line 1395) | func (mr *MockAPIMockRecorder) GetTeamsForUser(arg0 interface{}) *gomo...
method GetTeamsUnreadForUser (line 1410) | func (mr *MockAPIMockRecorder) GetTeamsUnreadForUser(arg0 interface{})...
method GetTelemetryId (line 1424) | func (mr *MockAPIMockRecorder) GetTelemetryId() *gomock.Call {
method GetUnsanitizedConfig (line 1438) | func (mr *MockAPIMockRecorder) GetUnsanitizedConfig() *gomock.Call {
method GetUploadSession (line 1453) | func (mr *MockAPIMockRecorder) GetUploadSession(arg0 interface{}) *gom...
method GetUser (line 1468) | func (mr *MockAPIMockRecorder) GetUser(arg0 interface{}) *gomock.Call {
method GetUserByEmail (line 1483) | func (mr *MockAPIMockRecorder) GetUserByEmail(arg0 interface{}) *gomoc...
method GetUserByUsername (line 1498) | func (mr *MockAPIMockRecorder) GetUserByUsername(arg0 interface{}) *go...
method GetUserStatus (line 1513) | func (mr *MockAPIMockRecorder) GetUserStatus(arg0 interface{}) *gomock...
method GetUserStatusesByIds (line 1528) | func (mr *MockAPIMockRecorder) GetUserStatusesByIds(arg0 interface{}) ...
method GetUsers (line 1543) | func (mr *MockAPIMockRecorder) GetUsers(arg0 interface{}) *gomock.Call {
method GetUsersByUsernames (line 1558) | func (mr *MockAPIMockRecorder) GetUsersByUsernames(arg0 interface{}) *...
method GetUsersInChannel (line 1573) | func (mr *MockAPIMockRecorder) GetUsersInChannel(arg0, arg1, arg2, arg...
method GetUsersInTeam (line 1588) | func (mr *MockAPIMockRecorder) GetUsersInTeam(arg0, arg1, arg2 interfa...
method HasPermissionTo (line 1602) | func (mr *MockAPIMockRecorder) HasPermissionTo(arg0, arg1 interface{})...
method HasPermissionToChannel (line 1616) | func (mr *MockAPIMockRecorder) HasPermissionToChannel(arg0, arg1, arg2...
method HasPermissionToTeam (line 1630) | func (mr *MockAPIMockRecorder) HasPermissionToTeam(arg0, arg1, arg2 in...
method InstallPlugin (line 1645) | func (mr *MockAPIMockRecorder) InstallPlugin(arg0, arg1 interface{}) *...
method IsEnterpriseReady (line 1659) | func (mr *MockAPIMockRecorder) IsEnterpriseReady() *gomock.Call {
method KVCompareAndDelete (line 1674) | func (mr *MockAPIMockRecorder) KVCompareAndDelete(arg0, arg1 interface...
method KVCompareAndSet (line 1689) | func (mr *MockAPIMockRecorder) KVCompareAndSet(arg0, arg1, arg2 interf...
method KVDelete (line 1703) | func (mr *MockAPIMockRecorder) KVDelete(arg0 interface{}) *gomock.Call {
method KVDeleteAll (line 1717) | func (mr *MockAPIMockRecorder) KVDeleteAll() *gomock.Call {
method KVGet (line 1732) | func (mr *MockAPIMockRecorder) KVGet(arg0 interface{}) *gomock.Call {
method KVList (line 1747) | func (mr *MockAPIMockRecorder) KVList(arg0, arg1 interface{}) *gomock....
method KVSet (line 1761) | func (mr *MockAPIMockRecorder) KVSet(arg0, arg1 interface{}) *gomock.C...
method KVSetWithExpiry (line 1775) | func (mr *MockAPIMockRecorder) KVSetWithExpiry(arg0, arg1, arg2 interf...
method KVSetWithOptions (line 1790) | func (mr *MockAPIMockRecorder) KVSetWithOptions(arg0, arg1, arg2 inter...
method ListBuiltInCommands (line 1805) | func (mr *MockAPIMockRecorder) ListBuiltInCommands() *gomock.Call {
method ListCommands (line 1820) | func (mr *MockAPIMockRecorder) ListCommands(arg0 interface{}) *gomock....
method ListCustomCommands (line 1835) | func (mr *MockAPIMockRecorder) ListCustomCommands(arg0 interface{}) *g...
method ListPluginCommands (line 1850) | func (mr *MockAPIMockRecorder) ListPluginCommands(arg0 interface{}) *g...
method LoadPluginConfiguration (line 1864) | func (mr *MockAPIMockRecorder) LoadPluginConfiguration(arg0 interface{...
method LogDebug (line 1880) | func (mr *MockAPIMockRecorder) LogDebug(arg0 interface{}, arg1 ...inte...
method LogError (line 1897) | func (mr *MockAPIMockRecorder) LogError(arg0 interface{}, arg1 ...inte...
method LogInfo (line 1914) | func (mr *MockAPIMockRecorder) LogInfo(arg0 interface{}, arg1 ...inter...
method LogWarn (line 1931) | func (mr *MockAPIMockRecorder) LogWarn(arg0 interface{}, arg1 ...inter...
method OpenInteractiveDialog (line 1946) | func (mr *MockAPIMockRecorder) OpenInteractiveDialog(arg0 interface{})...
method PatchBot (line 1961) | func (mr *MockAPIMockRecorder) PatchBot(arg0, arg1 interface{}) *gomoc...
method PermanentDeleteBot (line 1975) | func (mr *MockAPIMockRecorder) PermanentDeleteBot(arg0 interface{}) *g...
method PluginHTTP (line 1989) | func (mr *MockAPIMockRecorder) PluginHTTP(arg0 interface{}) *gomock.Ca...
method PublishPluginClusterEvent (line 2003) | func (mr *MockAPIMockRecorder) PublishPluginClusterEvent(arg0, arg1 in...
method PublishUserTyping (line 2017) | func (mr *MockAPIMockRecorder) PublishUserTyping(arg0, arg1, arg2 inte...
method PublishWebSocketEvent (line 2029) | func (mr *MockAPIMockRecorder) PublishWebSocketEvent(arg0, arg1, arg2 ...
method ReadFile (line 2044) | func (mr *MockAPIMockRecorder) ReadFile(arg0 interface{}) *gomock.Call {
method RegisterCollectionAndTopic (line 2058) | func (mr *MockAPIMockRecorder) RegisterCollectionAndTopic(arg0, arg1 i...
method RegisterCommand (line 2072) | func (mr *MockAPIMockRecorder) RegisterCommand(arg0 interface{}) *gomo...
method RemovePlugin (line 2086) | func (mr *MockAPIMockRecorder) RemovePlugin(arg0 interface{}) *gomock....
method RemoveReaction (line 2100) | func (mr *MockAPIMockRecorder) RemoveReaction(arg0 interface{}) *gomoc...
method RemoveTeamIcon (line 2114) | func (mr *MockAPIMockRecorder) RemoveTeamIcon(arg0 interface{}) *gomoc...
method RemoveUserCustomStatus (line 2128) | func (mr *MockAPIMockRecorder) RemoveUserCustomStatus(arg0 interface{}...
method RequestTrialLicense (line 2142) | func (mr *MockAPIMockRecorder) RequestTrialLicense(arg0, arg1, arg2, a...
method RevokeSession (line 2156) | func (mr *MockAPIMockRecorder) RevokeSession(arg0 interface{}) *gomock...
method RevokeUserAccessToken (line 2170) | func (mr *MockAPIMockRecorder) RevokeUserAccessToken(arg0 interface{})...
method RolesGrantPermission (line 2184) | func (mr *MockAPIMockRecorder) RolesGrantPermission(arg0, arg1 interfa...
method SaveConfig (line 2198) | func (mr *MockAPIMockRecorder) SaveConfig(arg0 interface{}) *gomock.Ca...
method SavePluginConfig (line 2212) | func (mr *MockAPIMockRecorder) SavePluginConfig(arg0 interface{}) *gom...
method SearchChannels (line 2227) | func (mr *MockAPIMockRecorder) SearchChannels(arg0, arg1 interface{}) ...
method SearchPostsInTeam (line 2242) | func (mr *MockAPIMockRecorder) SearchPostsInTeam(arg0, arg1 interface{...
method SearchPostsInTeamForUser (line 2257) | func (mr *MockAPIMockRecorder) SearchPostsInTeamForUser(arg0, arg1, ar...
method SearchTeams (line 2272) | func (mr *MockAPIMockRecorder) SearchTeams(arg0 interface{}) *gomock.C...
method SearchUsers (line 2287) | func (mr *MockAPIMockRecorder) SearchUsers(arg0 interface{}) *gomock.C...
method SendEphemeralPost (line 2301) | func (mr *MockAPIMockRecorder) SendEphemeralPost(arg0, arg1 interface{...
method SendMail (line 2315) | func (mr *MockAPIMockRecorder) SendMail(arg0, arg1, arg2 interface{}) ...
method SetProfileImage (line 2329) | func (mr *MockAPIMockRecorder) SetProfileImage(arg0, arg1 interface{})...
method SetTeamIcon (line 2343) | func (mr *MockAPIMockRecorder) SetTeamIcon(arg0, arg1 interface{}) *go...
method SetUserStatusTimedDND (line 2358) | func (mr *MockAPIMockRecorder) SetUserStatusTimedDND(arg0, arg1 interf...
method UnregisterCommand (line 2372) | func (mr *MockAPIMockRecorder) UnregisterCommand(arg0, arg1 interface{...
method UpdateBotActive (line 2387) | func (mr *MockAPIMockRecorder) UpdateBotActive(arg0, arg1 interface{})...
method UpdateChannel (line 2402) | func (mr *MockAPIMockRecorder) UpdateChannel(arg0 interface{}) *gomock...
method UpdateChannelMemberNotifications (line 2417) | func (mr *MockAPIMockRecorder) UpdateChannelMemberNotifications(arg0, ...
method UpdateChannelMemberRoles (line 2432) | func (mr *MockAPIMockRecorder) UpdateChannelMemberRoles(arg0, arg1, ar...
method UpdateChannelSidebarCategories (line 2447) | func (mr *MockAPIMockRecorder) UpdateChannelSidebarCategories(arg0, ar...
method UpdateCommand (line 2462) | func (mr *MockAPIMockRecorder) UpdateCommand(arg0, arg1 interface{}) *...
method UpdateEphemeralPost (line 2476) | func (mr *MockAPIMockRecorder) UpdateEphemeralPost(arg0, arg1 interfac...
method UpdateOAuthApp (line 2491) | func (mr *MockAPIMockRecorder) UpdateOAuthApp(arg0 interface{}) *gomoc...
method UpdatePost (line 2506) | func (mr *MockAPIMockRecorder) UpdatePost(arg0 interface{}) *gomock.Ca...
method UpdatePreferencesForUser (line 2520) | func (mr *MockAPIMockRecorder) UpdatePreferencesForUser(arg0, arg1 int...
method UpdateTeam (line 2535) | func (mr *MockAPIMockRecorder) UpdateTeam(arg0 interface{}) *gomock.Ca...
method UpdateTeamMemberRoles (line 2550) | func (mr *MockAPIMockRecorder) UpdateTeamMemberRoles(arg0, arg1, arg2 ...
method UpdateUser (line 2565) | func (mr *MockAPIMockRecorder) UpdateUser(arg0 interface{}) *gomock.Ca...
method UpdateUserActive (line 2579) | func (mr *MockAPIMockRecorder) UpdateUserActive(arg0, arg1 interface{}...
method UpdateUserCustomStatus (line 2593) | func (mr *MockAPIMockRecorder) UpdateUserCustomStatus(arg0, arg1 inter...
method UpdateUserStatus (line 2608) | func (mr *MockAPIMockRecorder) UpdateUserStatus(arg0, arg1 interface{}...
method UploadData (line 2623) | func (mr *MockAPIMockRecorder) UploadData(arg0, arg1 interface{}) *gom...
method UploadFile (line 2638) | func (mr *MockAPIMockRecorder) UploadFile(arg0, arg1, arg2 interface{}...
function NewMockAPI (line 28) | func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
FILE: server/services/permissions/mocks/mockstore.go
type MockStore (line 15) | type MockStore struct
method EXPECT (line 33) | func (m *MockStore) EXPECT() *MockStoreMockRecorder {
method GetBoard (line 38) | func (m *MockStore) GetBoard(arg0 string) (*model.Board, error) {
method GetBoardHistory (line 53) | func (m *MockStore) GetBoardHistory(arg0 string, arg1 model.QueryBoard...
method GetMemberForBoard (line 68) | func (m *MockStore) GetMemberForBoard(arg0, arg1 string) (*model.Board...
type MockStoreMockRecorder (line 21) | type MockStoreMockRecorder struct
method GetBoard (line 47) | func (mr *MockStoreMockRecorder) GetBoard(arg0 interface{}) *gomock.Ca...
method GetBoardHistory (line 62) | func (mr *MockStoreMockRecorder) GetBoardHistory(arg0, arg1 interface{...
method GetMemberForBoard (line 77) | func (mr *MockStoreMockRecorder) GetMemberForBoard(arg0, arg1 interfac...
function NewMockStore (line 26) | func NewMockStore(ctrl *gomock.Controller) *MockStore {
FILE: server/services/permissions/permissions.go
type PermissionsService (line 13) | type PermissionsService interface
type Store (line 20) | type Store interface
FILE: server/services/scheduler/scheduler.go
type TaskFunc (line 11) | type TaskFunc
type ScheduledTask (line 13) | type ScheduledTask struct
method Cancel (line 63) | func (task *ScheduledTask) Cancel() {
method String (line 68) | func (task *ScheduledTask) String() string {
function CreateTask (line 22) | func CreateTask(name string, function TaskFunc, timeToExecution time.Dur...
function CreateRecurringTask (line 26) | func CreateRecurringTask(name string, function TaskFunc, interval time.D...
function createTask (line 30) | func createTask(name string, function TaskFunc, interval time.Duration, ...
FILE: server/services/scheduler/scheduler_test.go
function TestCreateTask (line 14) | func TestCreateTask(t *testing.T) {
function TestCreateRecurringTask (line 36) | func TestCreateRecurringTask(t *testing.T) {
function TestCancelTask (line 64) | func TestCancelTask(t *testing.T) {
FILE: server/services/store/generators/main.go
constant WithTransactionComment (line 22) | WithTransactionComment = "@withTransaction"
constant ErrorType (line 23) | ErrorType = "error"
constant StringType (line 24) | StringType = "string"
constant IntType (line 25) | IntType = "int"
constant Int32Type (line 26) | Int32Type = "int32"
constant Int64Type (line 27) | Int64Type = "int64"
constant BoolType (line 28) | BoolType = "bool"
function isError (line 31) | func isError(typeName string) bool {
function isString (line 35) | func isString(typeName string) bool {
function isInt (line 39) | func isInt(typeName string) bool {
function isBool (line 43) | func isBool(typeName string) bool {
function main (line 47) | func main() {
function buildTransactionalStore (line 53) | func buildTransactionalStore() error {
type methodParam (line 66) | type methodParam struct
type methodData (line 71) | type methodData struct
type storeMetadata (line 77) | type storeMetadata struct
function extractMethodMetadata (line 88) | func extractMethodMetadata(method *ast.Field, src []byte) methodData {
function extractStoreMetadata (line 122) | func extractStoreMetadata() (*storeMetadata, error) {
function generateLayer (line 163) | func generateLayer(name, templateFile string) ([]byte, error) {
FILE: server/services/store/mattermostauthlayer/mattermostauthlayer.go
type servicesAPI (line 26) | type servicesAPI interface
type MattermostAuthLayer (line 46) | type MattermostAuthLayer struct
method Shutdown (line 70) | func (s *MattermostAuthLayer) Shutdown() error {
method GetRegisteredUserCount (line 74) | func (s *MattermostAuthLayer) GetRegisteredUserCount() (int, error) {
method GetUserByID (line 90) | func (s *MattermostAuthLayer) GetUserByID(userID string) (*model.User,...
method GetUserByEmail (line 100) | func (s *MattermostAuthLayer) GetUserByEmail(email string) (*model.Use...
method GetUserByUsername (line 109) | func (s *MattermostAuthLayer) GetUserByUsername(username string) (*mod...
method CreateUser (line 118) | func (s *MattermostAuthLayer) CreateUser(user *model.User) (*model.Use...
method UpdateUser (line 122) | func (s *MattermostAuthLayer) UpdateUser(user *model.User) (*model.Use...
method UpdateUserPassword (line 126) | func (s *MattermostAuthLayer) UpdateUserPassword(username, password st...
method UpdateUserPasswordByID (line 130) | func (s *MattermostAuthLayer) UpdateUserPasswordByID(userID, password ...
method PatchUserPreferences (line 134) | func (s *MattermostAuthLayer) PatchUserPreferences(userID string, patc...
method GetUserPreferences (line 217) | func (s *MattermostAuthLayer) GetUserPreferences(userID string) (mmMod...
method GetActiveUserCount (line 222) | func (s *MattermostAuthLayer) GetActiveUserCount(updatedSecondsAgo int...
method GetSession (line 239) | func (s *MattermostAuthLayer) GetSession(token string, expireTime int6...
method CreateSession (line 243) | func (s *MattermostAuthLayer) CreateSession(session *model.Session) er...
method RefreshSession (line 247) | func (s *MattermostAuthLayer) RefreshSession(session *model.Session) e...
method UpdateSession (line 251) | func (s *MattermostAuthLayer) UpdateSession(session *model.Session) er...
method DeleteSession (line 255) | func (s *MattermostAuthLayer) DeleteSession(sessionID string) error {
method CleanUpSessions (line 259) | func (s *MattermostAuthLayer) CleanUpSessions(expireTime int64) error {
method GetTeam (line 263) | func (s *MattermostAuthLayer) GetTeam(id string) (*model.Team, error) {
method GetTeamsForUser (line 293) | func (s *MattermostAuthLayer) GetTeamsForUser(userID string) ([]*model...
method getQueryBuilder (line 325) | func (s *MattermostAuthLayer) getQueryBuilder() sq.StatementBuilderType {
method GetUsersByTeam (line 334) | func (s *MattermostAuthLayer) GetUsersByTeam(teamID string, asGuestID ...
method GetUsersList (line 371) | func (s *MattermostAuthLayer) GetUsersList(userIDs []string, showEmail...
method SearchUsersByTeam (line 393) | func (s *MattermostAuthLayer) SearchUsersByTeam(teamID string, searchQ...
method usersFromRows (line 442) | func (s *MattermostAuthLayer) usersFromRows(rows *sql.Rows) ([]*model....
method CloseRows (line 471) | func (s *MattermostAuthLayer) CloseRows(rows *sql.Rows) {
method CreatePrivateWorkspace (line 477) | func (s *MattermostAuthLayer) CreatePrivateWorkspace(userID string) (s...
method GetFileInfo (line 514) | func (s *MattermostAuthLayer) GetFileInfo(id string) (*mmModel.FileInf...
method SaveFileInfo (line 537) | func (s *MattermostAuthLayer) SaveFileInfo(fileInfo *mmModel.FileInfo)...
method GetLicense (line 598) | func (s *MattermostAuthLayer) GetLicense() *mmModel.License {
method baseUserQuery (line 639) | func (s *MattermostAuthLayer) baseUserQuery(showEmail, showName bool) ...
method SearchBoardsForUser (line 673) | func (s *MattermostAuthLayer) SearchBoardsForUser(term string, searchF...
method SearchBoardsForUserInTeam (line 802) | func (s *MattermostAuthLayer) SearchBoardsForUserInTeam(teamID, term, ...
method boardsFromRows (line 896) | func (s *MattermostAuthLayer) boardsFromRows(rows *sql.Rows, removeDup...
method implicitBoardMembershipsFromRows (line 955) | func (s *MattermostAuthLayer) implicitBoardMembershipsFromRows(rows *s...
method GetMemberForBoard (line 978) | func (s *MattermostAuthLayer) GetMemberForBoard(boardID, userID string...
method GetMembersForUser (line 1052) | func (s *MattermostAuthLayer) GetMembersForUser(userID string) ([]*mod...
method GetMembersForBoard (line 1101) | func (s *MattermostAuthLayer) GetMembersForBoard(boardID string) ([]*m...
method GetBoardsForUserAndTeam (line 1146) | func (s *MattermostAuthLayer) GetBoardsForUserAndTeam(userID, teamID s...
method SearchUserChannels (line 1180) | func (s *MattermostAuthLayer) SearchUserChannels(teamID, userID, query...
method GetChannel (line 1203) | func (s *MattermostAuthLayer) GetChannel(teamID, channelID string) (*m...
method getBoardsBotID (line 1211) | func (s *MattermostAuthLayer) getBoardsBotID() (string, error) {
method SendMessage (line 1223) | func (s *MattermostAuthLayer) SendMessage(message, postType string, re...
method PostMessage (line 1253) | func (s *MattermostAuthLayer) PostMessage(message, postType, channelID...
method GetUserTimezone (line 1275) | func (s *MattermostAuthLayer) GetUserTimezone(userID string) (string, ...
method CanSeeUser (line 1284) | func (s *MattermostAuthLayer) CanSeeUser(seerID string, seenID string)...
function New (line 56) | func New(dbType string, db *sql.DB, store store.Store, logger mlog.Logge...
function mmUserToFbUser (line 489) | func mmUserToFbUser(mmUser *mmModel.User) model.User {
function boardFields (line 602) | func boardFields(prefix string) []string { //nolint:unparam
FILE: server/services/store/mattermostauthlayer/mattermostauthlayer_test.go
function TestGetBoardsBotID (line 18) | func TestGetBoardsBotID(t *testing.T) {
FILE: server/services/store/mockstore/mockstore.go
type MockStore (line 17) | type MockStore struct
method EXPECT (line 35) | func (m *MockStore) EXPECT() *MockStoreMockRecorder {
method AddUpdateCategoryBoard (line 40) | func (m *MockStore) AddUpdateCategoryBoard(arg0, arg1 string, arg2 []s...
method CanSeeUser (line 54) | func (m *MockStore) CanSeeUser(arg0, arg1 string) (bool, error) {
method CleanUpSessions (line 69) | func (m *MockStore) CleanUpSessions(arg0 int64) error {
method CreateBoardsAndBlocks (line 83) | func (m *MockStore) CreateBoardsAndBlocks(arg0 *model.BoardsAndBlocks,...
method CreateBoardsAndBlocksWithAdmin (line 98) | func (m *MockStore) CreateBoardsAndBlocksWithAdmin(arg0 *model.BoardsA...
method CreateCategory (line 114) | func (m *MockStore) CreateCategory(arg0 model.Category) error {
method CreateSession (line 128) | func (m *MockStore) CreateSession(arg0 *model.Session) error {
method CreateSubscription (line 142) | func (m *MockStore) CreateSubscription(arg0 *model.Subscription) (*mod...
method CreateUser (line 157) | func (m *MockStore) CreateUser(arg0 *model.User) (*model.User, error) {
method DBType (line 172) | func (m *MockStore) DBType() string {
method DBVersion (line 186) | func (m *MockStore) DBVersion() string {
method DeleteBlock (line 200) | func (m *MockStore) DeleteBlock(arg0, arg1 string) error {
method DeleteBlockRecord (line 214) | func (m *MockStore) DeleteBlockRecord(arg0, arg1 string) error {
method DeleteBoard (line 228) | func (m *MockStore) DeleteBoard(arg0, arg1 string) error {
method DeleteBoardRecord (line 242) | func (m *MockStore) DeleteBoardRecord(arg0, arg1 string) error {
method DeleteBoardsAndBlocks (line 256) | func (m *MockStore) DeleteBoardsAndBlocks(arg0 *model.DeleteBoardsAndB...
method DeleteCategory (line 270) | func (m *MockStore) DeleteCategory(arg0, arg1, arg2 string) error {
method DeleteMember (line 284) | func (m *MockStore) DeleteMember(arg0, arg1 string) error {
method DeleteNotificationHint (line 298) | func (m *MockStore) DeleteNotificationHint(arg0 string) error {
method DeleteSession (line 312) | func (m *MockStore) DeleteSession(arg0 string) error {
method DeleteSubscription (line 326) | func (m *MockStore) DeleteSubscription(arg0, arg1 string) error {
method DuplicateBlock (line 340) | func (m *MockStore) DuplicateBlock(arg0, arg1, arg2 string, arg3 bool)...
method DuplicateBoard (line 355) | func (m *MockStore) DuplicateBoard(arg0, arg1, arg2 string, arg3 bool)...
method GetActiveUserCount (line 371) | func (m *MockStore) GetActiveUserCount(arg0 int64) (int, error) {
method GetAllTeams (line 386) | func (m *MockStore) GetAllTeams() ([]*model.Team, error) {
method GetBlock (line 401) | func (m *MockStore) GetBlock(arg0 string) (*model.Block, error) {
method GetBlockCountsByType (line 416) | func (m *MockStore) GetBlockCountsByType() (map[string]int64, error) {
method GetBlockHistory (line 431) | func (m *MockStore) GetBlockHistory(arg0 string, arg1 model.QueryBlock...
method GetBlockHistoryDescendants (line 446) | func (m *MockStore) GetBlockHistoryDescendants(arg0 string, arg1 model...
method GetBlockHistoryNewestChildren (line 461) | func (m *MockStore) GetBlockHistoryNewestChildren(arg0 string, arg1 mo...
method GetBlocks (line 477) | func (m *MockStore) GetBlocks(arg0 model.QueryBlocksOptions) ([]*model...
method GetBlocksByIDs (line 492) | func (m *MockStore) GetBlocksByIDs(arg0 []string) ([]*model.Block, err...
method GetBlocksComplianceHistory (line 507) | func (m *MockStore) GetBlocksComplianceHistory(arg0 model.QueryBlocksC...
method GetBlocksForBoard (line 523) | func (m *MockStore) GetBlocksForBoard(arg0 string) ([]*model.Block, er...
method GetBlocksWithParent (line 538) | func (m *MockStore) GetBlocksWithParent(arg0, arg1 string) ([]*model.B...
method GetBlocksWithParentAndType (line 553) | func (m *MockStore) GetBlocksWithParentAndType(arg0, arg1, arg2 string...
method GetBlocksWithType (line 568) | func (m *MockStore) GetBlocksWithType(arg0, arg1 string) ([]*model.Blo...
method GetBoard (line 583) | func (m *MockStore) GetBoard(arg0 string) (*model.Board, error) {
method GetBoardAndCard (line 598) | func (m *MockStore) GetBoardAndCard(arg0 *model.Block) (*model.Board, ...
method GetBoardAndCardByID (line 614) | func (m *MockStore) GetBoardAndCardByID(arg0 string) (*model.Board, *m...
method GetBoardCount (line 630) | func (m *MockStore) GetBoardCount() (int64, error) {
method GetBoardHistory (line 645) | func (m *MockStore) GetBoardHistory(arg0 string, arg1 model.QueryBoard...
method GetBoardMemberHistory (line 660) | func (m *MockStore) GetBoardMemberHistory(arg0, arg1 string, arg2 uint...
method GetBoardsComplianceHistory (line 675) | func (m *MockStore) GetBoardsComplianceHistory(arg0 model.QueryBoardsC...
method GetBoardsForCompliance (line 691) | func (m *MockStore) GetBoardsForCompliance(arg0 model.QueryBoardsForCo...
method GetBoardsForUserAndTeam (line 707) | func (m *MockStore) GetBoardsForUserAndTeam(arg0, arg1 string, arg2 bo...
method GetBoardsInTeamByIds (line 722) | func (m *MockStore) GetBoardsInTeamByIds(arg0 []string, arg1 string) (...
method GetCardLimitTimestamp (line 737) | func (m *MockStore) GetCardLimitTimestamp() (int64, error) {
method GetCategory (line 752) | func (m *MockStore) GetCategory(arg0 string) (*model.Category, error) {
method GetChannel (line 767) | func (m *MockStore) GetChannel(arg0, arg1 string) (*model0.Channel, er...
method GetFileInfo (line 782) | func (m *MockStore) GetFileInfo(arg0 string) (*model0.FileInfo, error) {
method GetLicense (line 797) | func (m *MockStore) GetLicense() *model0.License {
method GetMemberForBoard (line 811) | func (m *MockStore) GetMemberForBoard(arg0, arg1 string) (*model.Board...
method GetMembersForBoard (line 826) | func (m *MockStore) GetMembersForBoard(arg0 string) ([]*model.BoardMem...
method GetMembersForUser (line 841) | func (m *MockStore) GetMembersForUser(arg0 string) ([]*model.BoardMemb...
method GetNextNotificationHint (line 856) | func (m *MockStore) GetNextNotificationHint(arg0 bool) (*model.Notific...
method GetNotificationHint (line 871) | func (m *MockStore) GetNotificationHint(arg0 string) (*model.Notificat...
method GetRegisteredUserCount (line 886) | func (m *MockStore) GetRegisteredUserCount() (int, error) {
method GetSession (line 901) | func (m *MockStore) GetSession(arg0 string, arg1 int64) (*model.Sessio...
method GetSharing (line 916) | func (m *MockStore) GetSharing(arg0 string) (*model.Sharing, error) {
method GetSubTree2 (line 931) |
Copy disabled (too large)
Download .json
Condensed preview — 1547 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (12,349K chars).
[
{
"path": ".dockerignore",
"chars": 96,
"preview": "CHANGELOG.md\nREADME.md\n\nnode_modules\n.github/\nmac/\nwin-wpf/\nwebsite/\nlinux/\ngo.work\ngo.work.sum\n"
},
{
"path": ".editorconfig",
"chars": 385,
"preview": "# http://editorconfig.org/\n\nroot = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = tru"
},
{
"path": ".gitattributes",
"chars": 71,
"preview": "website/** linguist-documentation\nserver/swagger/** linguist-generated\n"
},
{
"path": ".github/CODEOWNERS",
"chars": 0,
"preview": ""
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 907,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: 'Bug: '\nlabels: Bug, Triage\nassignees: ''\n\n---\n\n##"
},
{
"path": ".github/ISSUE_TEMPLATE/doc_improvement.md",
"chars": 579,
"preview": "---\nname: Documentation Request\nabout: Request improvement to our documentation\ntitle: 'Doc: '\nlabels: Documentation, Tr"
},
{
"path": ".github/ISSUE_TEMPLATE/enhancement.md",
"chars": 367,
"preview": "---\nname: Enhancement/Feature Idea\nabout: Suggest a new capability\ntitle: 'Feature Idea: '\nlabels: Enhancement, Triage\na"
},
{
"path": ".github/codeql/codeql-config.yml",
"chars": 289,
"preview": "name: \"CodeQL config\"\n\nquery-filters:\n - exclude:\n problem.severity:\n - warning\n - recommendation\n "
},
{
"path": ".github/dependabot.yml",
"chars": 417,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directories:\n - \"**/*\"\n reviewers:\n - \"matt"
},
{
"path": ".github/workflows/ci.yml",
"chars": 2885,
"preview": "name: Check-in tests\n\non:\n push:\n branches:\n - 'main'\n - 'releases-**'\n pull_request:\n workflow_dispatch"
},
{
"path": ".github/workflows/codeql-analysis.yml",
"chars": 1249,
"preview": "name: \"CodeQL\"\n\non:\n push:\n branches: [ main, release-** ]\n pull_request:\n # The branches below must be a subset"
},
{
"path": ".github/workflows/dev-release.yml",
"chars": 4823,
"preview": "name: Dev-Release\n\non:\n push:\n branches: [ main, release-** ]\n pull_request:\n branches: [ main, release-** ]\n w"
},
{
"path": ".github/workflows/lint-server.yml",
"chars": 1222,
"preview": "name: golangci-lint\n\non:\n push:\n branches: [ main, release-** ]\n pull_request:\n branches: [ main, release-** ]\n "
},
{
"path": ".github/workflows/prod-release.yml",
"chars": 4947,
"preview": "name: Production-Release\n\non: workflow_dispatch\n\nenv:\n EXCLUDE_ENTERPRISE: true\n BRANCH_NAME: ${{ github.head_ref || git"
},
{
"path": ".github/workflows/scorecards-analysis.yml",
"chars": 1875,
"preview": "name: Scorecards supply-chain security\non:\n # Only the default branch is supported.\n branch_protection_rule:\n schedul"
},
{
"path": ".gitignore",
"chars": 1174,
"preview": "# Created by https://www.gitignore.io/api/node\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid"
},
{
"path": ".gitlab-ci.yml",
"chars": 220,
"preview": "stages:\n - build\n - s3\n\nvariables:\n BUILD: \"yes\"\n IMAGE_BUILDER: $CI_REGISTRY/mattermost/ci/images/builder:go-1.19.5"
},
{
"path": ".gitpod.yml",
"chars": 74,
"preview": "mainConfiguration: https://github.com/mattermost/mattermost-gitpod-config\n"
},
{
"path": "CHANGELOG.md",
"chars": 7710,
"preview": "# Focalboard Changelog\n\nFocalboard is an open source, self-hosted alternative to Trello, Notion, Asana and Jira for proj"
},
{
"path": "CONTRIBUTING.md",
"chars": 1273,
"preview": "# Disclaimer\n\n> [!WARNING]\n> **Effective September 15th, 2023, Mattermost, Inc. staff are no longer reviewing or merging"
},
{
"path": "Dockerfile.build",
"chars": 1491,
"preview": "# This Dockerfile is used to build Focalboard for Linux. It builds all the parts inside the image\n# and the last stage j"
},
{
"path": "LICENSE.txt",
"chars": 47761,
"preview": "Mattermost Licensing\n\nSOFTWARE LICENSING\n\nYou are licensed to use compiled versions of Focalboard produced by Mattermost"
},
{
"path": "Makefile",
"chars": 11446,
"preview": ".PHONY: prebuild clean cleanall ci server server-mac server-linux server-win server-linux-package generate watch-server "
},
{
"path": "NOTICE.txt",
"chars": 31554,
"preview": "Focalboard\n© 2015-present Mattermost, Inc. All Rights Reserved. See LICENSE.txt for license information.\n\nNOTICES:\n---"
},
{
"path": "README.md",
"chars": 6453,
"preview": "> [!WARNING]\n> This repository is currently not maintained. If you're interested in becoming a maintainer please [let us"
},
{
"path": "SECURITY.md",
"chars": 1965,
"preview": "Security\n========\n\nSafety and data security is of the utmost priority for the Mattermost community. If you are a securit"
},
{
"path": "app-config.json",
"chars": 217,
"preview": "{\n\t\"serverRoot\": \"http://localhost:8088\",\n\t\"port\": 8088,\n\t\"dbtype\": \"sqlite3\",\n\t\"dbconfig\": \"./focalboard.db\",\n\t\"useSSL\""
},
{
"path": "config.json",
"chars": 688,
"preview": "{\n\t\"serverRoot\": \"http://localhost:8000\",\n\t\"port\": 8000,\n\t\"dbtype\": \"sqlite3\",\n\t\"dbconfig\": \"./focalboard.db?_busy_timeo"
},
{
"path": "docker/Dockerfile",
"chars": 1484,
"preview": "### Webapp build\nFROM node:16.3.0@sha256:ca6daf1543242acb0ca59ff425509eab7defb9452f6ae07c156893db06c7a9a4 as nodebuild\n\n"
},
{
"path": "docker/README.md",
"chars": 1383,
"preview": "# Deploy Focalboard with Docker\n\n## Docker\n\nThe Dockerfile gives a quick and easy way to build the latest Focalboard ser"
},
{
"path": "docker/config.json",
"chars": 592,
"preview": "{\n \"serverRoot\": \"http://localhost:8000\",\n \"port\": 8000,\n \"dbtype\": \"postgres\",\n \"dbconfig\": \"postgres://boa"
},
{
"path": "docker/docker-compose-db-nginx.yml",
"chars": 1006,
"preview": "version: \"3\"\n\nservices:\n app:\n build:\n context: ../\n dockerfile: docker/Dockerfile\n container_name: foc"
},
{
"path": "docker/docker-compose.yml",
"chars": 303,
"preview": "version: \"3\"\nservices:\n app:\n build:\n context: ../\n dockerfile: docker/Dockerfile\n container_name: foca"
},
{
"path": "docker/server_config.json",
"chars": 456,
"preview": "{\n \"serverRoot\": \"http://localhost:8000\",\n \"port\": 8000,\n \"dbtype\": \"sqlite3\",\n \"dbconfig\": \"./data/focalboard.db\",\n"
},
{
"path": "docker-testing/docker-compose-mariadb.yml",
"chars": 583,
"preview": "version: '2.4'\nservices:\n mariadb:\n image: \"mariadb:10.9.3\"\n restart: always\n environment:\n MARIADB_ROOT_"
},
{
"path": "docker-testing/docker-compose-mysql.yml",
"chars": 542,
"preview": "version: '2.4'\nservices:\n mysql:\n image: \"mysql/mysql-server:8.0.32\"\n restart: always\n environment:\n MYSQ"
},
{
"path": "docker-testing/docker-compose-postgres.yml",
"chars": 490,
"preview": "version: '2.4'\nservices:\n postgres:\n image: \"postgres:10\"\n restart: always\n environment:\n POSTGRES_USER: "
},
{
"path": "docs/README.md",
"chars": 682,
"preview": "# Disclaimer\n\n> [!WARNING]\n> **Effective September 15th, 2023, Mattermost, Inc. staff are no longer reviewing or merging"
},
{
"path": "docs/_config.yml",
"chars": 90,
"preview": "title: Focalboard Developers\ngoogle_analytics: UA-64458817-2\ntheme: jekyll-theme-architect"
},
{
"path": "docs/code-review.md",
"chars": 3942,
"preview": "# Code Review Checklist\n\nCurrently, all changes to the product must be reviewed by a [core committer](core-committers.md"
},
{
"path": "docs/contribution-checklist.md",
"chars": 1508,
"preview": "# Contribution Checklist\n\nThanks for your interest in contributing code!\n\nFollow this checklist for submitting a pull re"
},
{
"path": "docs/contributions-without-ticket.md",
"chars": 1682,
"preview": "# Contributions Without Ticket\n\nContributions for minor corrections and improvements without a corresponding `Help Wante"
},
{
"path": "docs/core-committers.md",
"chars": 1708,
"preview": "# Core Committers\n\nA core committer is a maintainer on the Focalboard project who has merge access to the repositories. "
},
{
"path": "docs/dev-tips.md",
"chars": 4593,
"preview": "# Developer Tips and Tricks\n\nThese tips and tricks apply to developing the standalone Personal Server of Focalboard. For"
},
{
"path": "docs/focalboard-dev-guide.md",
"chars": 3325,
"preview": "# Focalboard Plugin Developer's Guide\n\n**Important**: Effective September 15th, 2023, Mattermost Boards transitions to b"
},
{
"path": "docs/index.md",
"chars": 2119,
"preview": "# Focalboard Plugin Documentation\n\nWelcome to the Focalboard plugin project! We're very glad you want to check it out an"
},
{
"path": "experiments/webext/.gitignore",
"chars": 32,
"preview": ".parcel-cache\nweb-ext-artifacts\n"
},
{
"path": "experiments/webext/.parcelrc",
"chars": 47,
"preview": "{\n \"extends\": \"@parcel/config-webextension\"\n}\n"
},
{
"path": "experiments/webext/README.md",
"chars": 2531,
"preview": "# Focalboard Web Clipper Browser Extension ✂️\n\nThis is the Focalboard Web Clipper browser extension. It aims at supporti"
},
{
"path": "experiments/webext/manifest.json",
"chars": 760,
"preview": "{\n \"manifest_version\": 2,\n \"name\": \"Focalboard Web Clipper\",\n \"version\": \"0.1.0\",\n \"description\": \"Save websites dir"
},
{
"path": "experiments/webext/package.json",
"chars": 870,
"preview": "{\n \"name\": \"focalboard-web-clipper\",\n \"version\": \"0.0.0\",\n \"targets\": {\n \"dev\": {\n \"sourceMap\": {\n \"in"
},
{
"path": "experiments/webext/src/utils/Board.ts",
"chars": 135,
"preview": "interface BoardFields {\n isTemplate: boolean\n}\n\nexport default interface Board {\n id: string\n title: string\n fields:"
},
{
"path": "experiments/webext/src/utils/networking.ts",
"chars": 3615,
"preview": "// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "experiments/webext/src/utils/settings.ts",
"chars": 871,
"preview": "// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "experiments/webext/src/views/OptionsApp.scss",
"chars": 669,
"preview": "/* Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved. */\n/* See LICENSE.txt for license information. */\n\n."
},
{
"path": "experiments/webext/src/views/OptionsApp.tsx",
"chars": 3580,
"preview": "// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "experiments/webext/src/views/PopupApp.scss",
"chars": 385,
"preview": "/* Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved. */\n/* See LICENSE.txt for license information. */\n\n."
},
{
"path": "experiments/webext/src/views/PopupApp.tsx",
"chars": 2030,
"preview": "// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "experiments/webext/src/views/options.html",
"chars": 176,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\"/>\n </head>\n <body>\n <div id=\"app\"></div>\n <script type"
},
{
"path": "experiments/webext/src/views/options.tsx",
"chars": 291,
"preview": "// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "experiments/webext/src/views/popup.html",
"chars": 174,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\"/>\n </head>\n <body>\n <div id=\"app\"></div>\n <script type"
},
{
"path": "experiments/webext/src/views/popup.tsx",
"chars": 285,
"preview": "// Copyright (c) 2021-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "experiments/webext/tsconfig.json",
"chars": 482,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react\",\n\t\t\"target\": \"es2019\",\n\t\t\"module\": \"commonjs\",\n\t\t\"esModuleInterop\": true,\n\t\t\"no"
},
{
"path": "import/README.md",
"chars": 317,
"preview": "# Import scripts\n\nThis subfolder contains scripts to import data from other systems. It is at an early stage. At present"
},
{
"path": "import/asana/.eslintrc.json",
"chars": 2541,
"preview": "{\n \"extends\": [\n ],\n \"plugins\": [\n ],\n \"parser\": \"@typescript-eslint/parser\",\n \"env\": {\n \"jest\": true\n },\n \"s"
},
{
"path": "import/asana/.gitignore",
"chars": 6,
"preview": "test\n\n"
},
{
"path": "import/asana/README.md",
"chars": 734,
"preview": "# Asana importer\n\nThis node app converts an Asana json archive into a Focalboard archive. To use:\n1. From the Asana Boar"
},
{
"path": "import/asana/asana.ts",
"chars": 2967,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n// Gener"
},
{
"path": "import/asana/importAsana.ts",
"chars": 5434,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/asana/package.json",
"chars": 831,
"preview": "{\n \"name\": \"focalboard-asana-importer\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"description\": \"\",\n \"main\": \"import"
},
{
"path": "import/asana/tsconfig.json",
"chars": 482,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react\",\n\t\t\"target\": \"es2019\",\n\t\t\"module\": \"commonjs\",\n\t\t\"esModuleInterop\": true,\n\t\t\"no"
},
{
"path": "import/asana/utils.ts",
"chars": 578,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/jira/.gitignore",
"chars": 4,
"preview": "test"
},
{
"path": "import/jira/README.md",
"chars": 984,
"preview": "# Jira importer\n\nThis node app converts a Jira xml export into a Focalboard archive. To use:\n1. Open Jira advanced searc"
},
{
"path": "import/jira/importJira.ts",
"chars": 416,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "import/jira/jiraImporter.test.ts",
"chars": 1367,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "import/jira/jiraImporter.ts",
"chars": 7579,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/jira/package.json",
"chars": 1323,
"preview": "{\n \"name\": \"focalboard-jira-importer\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"description\": \"\",\n \"main\": \"importJ"
},
{
"path": "import/jira/tsconfig.json",
"chars": 482,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react\",\n\t\t\"target\": \"es2019\",\n\t\t\"module\": \"commonjs\",\n\t\t\"esModuleInterop\": true,\n\t\t\"no"
},
{
"path": "import/jira/utils.ts",
"chars": 578,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/nextcloud-deck/.eslintrc.json",
"chars": 2541,
"preview": "{\n \"extends\": [\n ],\n \"plugins\": [\n ],\n \"parser\": \"@typescript-eslint/parser\",\n \"env\": {\n \"jest\": true\n },\n \"s"
},
{
"path": "import/nextcloud-deck/.gitignore",
"chars": 23,
"preview": "test\noutput.focalboard\n"
},
{
"path": "import/nextcloud-deck/README.md",
"chars": 873,
"preview": "# Nextcloud Deck importer\n\nThis node app converts data from a Nextcloud Server with the [app Deck](https://apps.nextclou"
},
{
"path": "import/nextcloud-deck/deck.ts",
"chars": 4954,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n/* eslin"
},
{
"path": "import/nextcloud-deck/importDeck.ts",
"chars": 7495,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/nextcloud-deck/package.json",
"chars": 955,
"preview": "{\n \"name\": \"focalboard-nextcloud-deck-importer\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"description\": \"\",\n \"main\""
},
{
"path": "import/nextcloud-deck/tsconfig.json",
"chars": 482,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react\",\n\t\t\"target\": \"es2019\",\n\t\t\"module\": \"commonjs\",\n\t\t\"esModuleInterop\": true,\n\t\t\"no"
},
{
"path": "import/nextcloud-deck/utils.ts",
"chars": 578,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/notion/.eslintrc.json",
"chars": 2541,
"preview": "{\n \"extends\": [\n ],\n \"plugins\": [\n ],\n \"parser\": \"@typescript-eslint/parser\",\n \"env\": {\n \"jest\": true\n },\n \"s"
},
{
"path": "import/notion/.gitignore",
"chars": 5,
"preview": "test\n"
},
{
"path": "import/notion/README.md",
"chars": 1027,
"preview": "# Notion importer\n\nThis node app converts a Notion CSV and markdown export into a Focalboard archive. To use:\n1. From a "
},
{
"path": "import/notion/importNotion.ts",
"chars": 6196,
"preview": "import csv from 'csvtojson'\nimport * as fs from 'fs'\nimport minimist from 'minimist'\nimport path from 'path'\nimport {exi"
},
{
"path": "import/notion/package.json",
"chars": 857,
"preview": "{\n \"name\": \"focalboard-notion-importer\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"description\": \"\",\n \"main\": \"impor"
},
{
"path": "import/notion/tsconfig.json",
"chars": 482,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react\",\n\t\t\"target\": \"es2019\",\n\t\t\"module\": \"commonjs\",\n\t\t\"esModuleInterop\": true,\n\t\t\"no"
},
{
"path": "import/notion/utils.ts",
"chars": 466,
"preview": "import * as crypto from 'crypto'\n\nclass Utils {\n static createGuid(): string {\n function randomDigit() {\n "
},
{
"path": "import/todoist/.eslintrc.json",
"chars": 2541,
"preview": "{\n \"extends\": [\n ],\n \"plugins\": [\n ],\n \"parser\": \"@typescript-eslint/parser\",\n \"env\": {\n \"jest\": true\n },\n \"s"
},
{
"path": "import/todoist/.gitignore",
"chars": 5,
"preview": "test\n"
},
{
"path": "import/todoist/README.md",
"chars": 813,
"preview": "# Todoist importer\n\nThis node app converts a Todoist json archive into a Focalboard archive. To use:\n1. Visit the open s"
},
{
"path": "import/todoist/importTodoist.ts",
"chars": 5681,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/todoist/package.json",
"chars": 847,
"preview": "{\n \"name\": \"focalboard-todoist-importer\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"description\": \"\",\n \"main\": \"impo"
},
{
"path": "import/todoist/todoist.ts",
"chars": 7270,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n/* eslin"
},
{
"path": "import/todoist/tsconfig.json",
"chars": 482,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react\",\n\t\t\"target\": \"es2019\",\n\t\t\"module\": \"commonjs\",\n\t\t\"esModuleInterop\": true,\n\t\t\"no"
},
{
"path": "import/todoist/utils.ts",
"chars": 578,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/trello/.eslintrc.json",
"chars": 2541,
"preview": "{\n \"extends\": [\n ],\n \"plugins\": [\n ],\n \"parser\": \"@typescript-eslint/parser\",\n \"env\": {\n \"jest\": true\n },\n \"s"
},
{
"path": "import/trello/.gitignore",
"chars": 4,
"preview": "test"
},
{
"path": "import/trello/README.md",
"chars": 821,
"preview": "# Trello importer\n\nThis node app converts a Trello json archive into a Focalboard archive. To use:\n1. From the Trello Bo"
},
{
"path": "import/trello/importTrello.ts",
"chars": 5312,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/trello/package.json",
"chars": 839,
"preview": "{\n \"name\": \"focalboard-trello-importer\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"description\": \"\",\n \"main\": \"impor"
},
{
"path": "import/trello/trello.ts",
"chars": 15083,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n/* eslin"
},
{
"path": "import/trello/tsconfig.json",
"chars": 482,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react\",\n\t\t\"target\": \"es2019\",\n\t\t\"module\": \"commonjs\",\n\t\t\"esModuleInterop\": true,\n\t\t\"no"
},
{
"path": "import/trello/utils.ts",
"chars": 578,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport *"
},
{
"path": "import/util/archive.ts",
"chars": 2960,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\nimport {"
},
{
"path": "linux/Makefile",
"chars": 134,
"preview": ".PHONY: run\n\nrun:\n\tgo run -tags \"json1 sqlite3\" ./main.go\n\nbuild:\n\tmkdir -p bin\n\tgo build -tags \"json1 sqlite3\" -o bin/f"
},
{
"path": "linux/go.mod",
"chars": 5575,
"preview": "module github.com/mattermost/focalboard/linux\n\ngo 1.21\n\ntoolchain go1.21.8\n\nreplace github.com/mattermost/focalboard/ser"
},
{
"path": "linux/go.sum",
"chars": 42285,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.31.0/go.mod h1"
},
{
"path": "linux/main.go",
"chars": 3569,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"runtime\"\n\n\t\"github.com/google/uu"
},
{
"path": "mac/Focalboard/AppDelegate.swift",
"chars": 4881,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/Assets.xcassets/AccentColor.colorset/Contents.json",
"chars": 123,
"preview": "{\n \"colors\" : [\n {\n \"idiom\" : \"universal\"\n }\n ],\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }"
},
{
"path": "mac/Focalboard/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 987,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"mac\",\n \"scale\" : \"1x\",\n \"size\" : \"16x16\"\n },\n {\n \"idiom\" : "
},
{
"path": "mac/Focalboard/Assets.xcassets/Contents.json",
"chars": 63,
"preview": "{\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }\n}\n"
},
{
"path": "mac/Focalboard/AutoSaveWindowController.swift",
"chars": 451,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/Base.lproj/Main.storyboard",
"chars": 87249,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" t"
},
{
"path": "mac/Focalboard/CustomWKWebView.swift",
"chars": 592,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/DownloadHandler.swift",
"chars": 1410,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/Focalboard.entitlements",
"chars": 421,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "mac/Focalboard/Globals.swift",
"chars": 615,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/Info.plist",
"chars": 1409,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "mac/Focalboard/Inherit.entitlements",
"chars": 288,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "mac/Focalboard/PortUtils.swift",
"chars": 1415,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/ViewController.swift",
"chars": 7558,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/WhatsNewViewController.swift",
"chars": 1159,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/Focalboard/whatsnew.txt",
"chars": 683,
"preview": "Welcome to Focalboard v7.2!\n\nMattermost Boards is now availalbe as a Cloud service. Set up your free server via the butt"
},
{
"path": "mac/Focalboard.xcodeproj/project.pbxproj",
"chars": 26789,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "mac/Focalboard.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "mac/Focalboard.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "mac/Focalboard.xcodeproj/xcshareddata/xcschemes/Focalboard.xcscheme",
"chars": 2867,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1220\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "mac/Focalboard.xcworkspace/contents.xcworkspacedata",
"chars": 160,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"container:Focalboard"
},
{
"path": "mac/Focalboard.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "mac/FocalboardTests/FocalboardTests.swift",
"chars": 922,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/FocalboardTests/Info.plist",
"chars": 1090,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "mac/FocalboardUITests/FocalboardUITests.swift",
"chars": 1433,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\nimport "
},
{
"path": "mac/FocalboardUITests/Info.plist",
"chars": 727,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "mac/README.md",
"chars": 1055,
"preview": "# Focalboard Mac Personal Desktop\n\nThis folder contains the code for the Mac Personal Desktop. It packages a lightweight"
},
{
"path": "mac/export.plist",
"chars": 427,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "modd-servertest.conf",
"chars": 89,
"preview": "**/*.go {\n prep: cd server && go test -tags \"$FOCALBOARD_BUILD_TAGS\" -race -v ./...\n}\n"
},
{
"path": "modd.conf",
"chars": 239,
"preview": "**/*.go !**/*_test.go {\n prep: cd server && go build -tags \"$FOCALBOARD_BUILD_TAGS\" -o ../bin/focalboard-server ./mai"
},
{
"path": "noticegen/Readme.md",
"chars": 1389,
"preview": "# Notice.txt File Configuration\n\nWe are automatically generating Notice.txt by using first-level dependencies of the pro"
},
{
"path": "noticegen/config.yaml",
"chars": 369,
"preview": "---\n\ntitle: \"Mattermost Focalboard\"\ncopyright: \"©2015-present Mattermost,Inc. All Rights Reserved. See LICENSE for licen"
},
{
"path": "pull_request_template.md",
"chars": 1015,
"preview": "<!-- Thank you for contributing a pull request! Here are a few tips to help you:\n\n1. If this is your first contribution,"
},
{
"path": "responsible_disclosure_policy.md",
"chars": 1799,
"preview": "# Responsible Disclosure Policy\n\nSafety and data security are of utmost priority for the Focalboard community. If you ar"
},
{
"path": "server/.golangci.yml",
"chars": 998,
"preview": "run:\n timeout: 5m\n modules-download-mode: readonly\n skip-dirs:\n - services/store/sqlstore/migrations\n\nlinters-sett"
},
{
"path": "server/admin-scripts/reset-password.sh",
"chars": 278,
"preview": "#!/bin/bash\n\nif [[ $# < 2 ]] ; then\n echo 'reset-password.sh <username> <new password>'\n exit 1\nfi\n\ncurl --unix-so"
},
{
"path": "server/api/admin.go",
"chars": 1286,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/f"
},
{
"path": "server/api/api.go",
"chars": 6184,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"runtime/debug\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github"
},
{
"path": "server/api/api_test.go",
"chars": 3461,
"preview": "package api\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/mattermost/"
},
{
"path": "server/api/archive.go",
"chars": 6667,
"preview": "package api\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/server/mo"
},
{
"path": "server/api/audit.go",
"chars": 828,
"preview": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.com/mattermost/focalboard/s"
},
{
"path": "server/api/auth.go",
"chars": 10900,
"preview": "package api\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gorilla/mux\"\n\t\"githu"
},
{
"path": "server/api/blocks.go",
"chars": 20040,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/matte"
},
{
"path": "server/api/boards.go",
"chars": 16985,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/s"
},
{
"path": "server/api/boards_and_blocks.go",
"chars": 10590,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focal"
},
{
"path": "server/api/cards.go",
"chars": 9429,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/matte"
},
{
"path": "server/api/categories.go",
"chars": 17334,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focal"
},
{
"path": "server/api/channels.go",
"chars": 2681,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/"
},
{
"path": "server/api/compliance.go",
"chars": 12451,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/"
},
{
"path": "server/api/config.go",
"chars": 869,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\nfunc (a *API) registerConfigRoutes(r *m"
},
{
"path": "server/api/content_blocks.go",
"chars": 2606,
"preview": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.c"
},
{
"path": "server/api/context.go",
"chars": 566,
"preview": "package api\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/http\"\n)\n\ntype contextKey int\n\nconst (\n\thttpConnContextKey contextKey = iot"
},
{
"path": "server/api/files.go",
"chars": 10897,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\npackage"
},
{
"path": "server/api/members.go",
"chars": 13796,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/s"
},
{
"path": "server/api/onboarding.go",
"chars": 1876,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/server/"
},
{
"path": "server/api/search.go",
"chars": 8729,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/server/"
},
{
"path": "server/api/sharing.go",
"chars": 4419,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/fo"
},
{
"path": "server/api/statistics.go",
"chars": 1643,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/server/"
},
{
"path": "server/api/subscriptions.go",
"chars": 6115,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focal"
},
{
"path": "server/api/system.go",
"chars": 1173,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\nfunc (a *API) registerSystemRoutes(r *m"
},
{
"path": "server/api/system_test.go",
"chars": 3643,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/mattermost/f"
},
{
"path": "server/api/teams.go",
"chars": 8700,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/s"
},
{
"path": "server/api/templates.go",
"chars": 2412,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/server/"
},
{
"path": "server/api/users.go",
"chars": 10335,
"preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mattermost/focalboard/s"
},
{
"path": "server/app/app.go",
"chars": 3438,
"preview": "package app\n\nimport (\n\t\"io\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/mattermost/focalboard/server/auth\"\n\t\"github.com/mattermost/foc"
},
{
"path": "server/app/app_test.go",
"chars": 533,
"preview": "package app\n\nimport (\n\t\"testing\"\n\n\t\"github.com/mattermost/focalboard/server/services/config\"\n\t\"github.com/stretchr/testi"
},
{
"path": "server/app/auth.go",
"chars": 6182,
"preview": "package app\n\nimport (\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.com/mattermost/focalboard/server/service"
},
{
"path": "server/app/auth_test.go",
"chars": 5505,
"preview": "package app\n\nimport (\n\t\"testing\"\n\n\t\"github.com/golang/mock/gomock\"\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"gi"
},
{
"path": "server/app/blocks.go",
"chars": 9800,
"preview": "package app\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.com/mattermost/focalbo"
},
{
"path": "server/app/blocks_test.go",
"chars": 9957,
"preview": "package app\n\nimport (\n\t\"database/sql\"\n\t\"testing\"\n\n\t\"github.com/golang/mock/gomock\"\n\t\"github.com/stretchr/testify/require"
},
{
"path": "server/app/boards.go",
"chars": 19017,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\npackage"
},
{
"path": "server/app/boards_and_blocks.go",
"chars": 3464,
"preview": "package app\n\nimport (\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.com/mattermost/focalboard/server/service"
},
{
"path": "server/app/boards_test.go",
"chars": 22459,
"preview": "package app\n\nimport (\n\t\"testing\"\n\n\t\"github.com/mattermost/focalboard/server/utils\"\n\n\t\"github.com/stretchr/testify/assert"
},
{
"path": "server/app/cards.go",
"chars": 2252,
"preview": "// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n// See LICENSE.txt for license information.\n\npackage"
},
{
"path": "server/app/cards_test.go",
"chars": 7374,
"preview": "package app\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/golang/mock/gomock\"\n\t\"github.com/mattermost/focalboard/"
},
{
"path": "server/app/category.go",
"chars": 6487,
"preview": "package app\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.com/mattermost/focalbo"
},
{
"path": "server/app/category_boards.go",
"chars": 8101,
"preview": "package app\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/mattermost/focalboard/server/model\"\n)\n\nconst defaultCategoryBoards "
},
{
"path": "server/app/category_boards_test.go",
"chars": 11384,
"preview": "package app\n\nimport (\n\t\"testing\"\n\n\t\"github.com/mattermost/focalboard/server/utils\"\n\n\t\"github.com/mattermost/focalboard/s"
},
{
"path": "server/app/category_test.go",
"chars": 13229,
"preview": "package app\n\nimport (\n\t\"testing\"\n\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.com/mattermost/focalboard/se"
},
{
"path": "server/app/clientConfig.go",
"chars": 482,
"preview": "package app\n\nimport (\n\t\"github.com/mattermost/focalboard/server/model\"\n)\n\nfunc (a *App) GetClientConfig() *model.ClientC"
},
{
"path": "server/app/clientConfig_test.go",
"chars": 816,
"preview": "package app\n\nimport (\n\t\"testing\"\n\n\t\"github.com/mattermost/focalboard/server/services/config\"\n\t\"github.com/stretchr/testi"
},
{
"path": "server/app/compliance.go",
"chars": 589,
"preview": "package app\n\nimport \"github.com/mattermost/focalboard/server/model\"\n\nfunc (a *App) GetBoardsForCompliance(opts model.Que"
},
{
"path": "server/app/content_blocks.go",
"chars": 1824,
"preview": "package app\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/mattermost/focalboard/server/model\"\n\t\"github.com/pkg/errors\"\n)\n\nfunc (a *App)"
},
{
"path": "server/app/content_blocks_test.go",
"chars": 6937,
"preview": "package app\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/golang/mock/gomock\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/stretchr"
}
]
// ... and 1347 more files (download for full content)
About this extraction
This page contains the full source code of the mattermost-community/focalboard GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1547 files (11.1 MB), approximately 3.0M tokens, and a symbol index with 4318 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.