mirror of
https://github.com/mattermost/focalboard.git
synced 2025-04-07 21:18:42 +02:00
Merge branch 'main' into private-templates
This commit is contained in:
commit
5a8665d2a1
@ -1,24 +1,22 @@
|
||||
# Code Contribution Guidelines
|
||||
|
||||
Thank you for your interest in contributing! Please see the [Focalboard Contribution Guide](https://mattermost.github.io/focalboard/) which describes the process for making code contributions, and [join our Focalboard community channel](https://community.mattermost.com/core/channels/focalboard) to ask questions from community members and the core team.
|
||||
Thank you for your interest in contributing! Please read the [Focalboard Contribution Guide](https://developers.mattermost.com/contribute/focalboard/) to learn the process for making code contributions, and [join our Focalboard community channel](https://community.mattermost.com/core/channels/focalboard) to get help from community members and the core team.
|
||||
|
||||
When you submit a pull request, it goes through a [code review process outlined here](https://mattermost.github.io/focalboard/code-review).
|
||||
When you submit a pull request, it goes through a code review process outlined [here](https://developers.mattermost.com/contribute/getting-started/code-review/).
|
||||
|
||||
# Updating Changelog
|
||||
After a noteable bug fix or improvement is merged, submit a pull request to the [CHANGELOG](CHANGELOG.md) under the next release section.
|
||||
|
||||
After a noteable bug fix or an improvement you've submitted is merged, please consider making a pull request to the [CHANGELOG.md](https://github.com/mattermost/focalboard/blob/main/CHANGELOG.md) under the next release section.
|
||||
|
||||
# Bug reports
|
||||
## Bug Reports
|
||||
|
||||
Please file a [GitHub issue](https://github.com/mattermost/focalboard/issues) if anything isn't working the way you expect.
|
||||
|
||||
# Documentation
|
||||
## Documentation
|
||||
|
||||
You can contribute to our documentation in the [Mattermost Boards documentation](https://docs.mattermost.com/guides/boards.html). Read more about how the contribution process works in the repo [README](https://github.com/mattermost/docs/blob/master/README.md). Visit the [Documentation Working Group channel](https://community.mattermost.com/core/channels/dwg-documentation-working-group) on our Community server if you have any questions!
|
||||
You can contribute to the [Mattermost Boards documentation](https://docs.mattermost.com/guides/boards.html). Read more about how the contribution process works in the repository's [README](https://github.com/mattermost/docs/blob/master/README.md). Visit the [Documentation Working Group channel](https://community.mattermost.com/core/channels/dwg-documentation-working-group) on our community server if you have any questions!
|
||||
|
||||
# Contributors
|
||||
## Contributors
|
||||
|
||||
**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**: Maintains the Focalboard project and 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.
|
||||
|
||||
- **<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
|
||||
@ -38,12 +36,12 @@ You can contribute to our documentation in the [Mattermost Boards documentation]
|
||||
- **<a name="ogi.marusic">Ogi Marušić</a>**
|
||||
- @ogi.marusic on [community.mattermost.com](https://community.mattermost.com/core/messages/@ogi.marusic) and [@ogi-m](https://github.com/ogi-m) on GitHub
|
||||
|
||||
**Community Organizers**: Responds with comments to Bug Reports, Issues, and Pull Requests with tags, edits and mentions to Core Committers and contributors.
|
||||
**Community Organizers**: Responds with comments to bug reports, issues, and pull requests with tags, edits and mentions to core committers and contributors.
|
||||
|
||||
- **<a name="winson.wu">Winson Wu</a>**
|
||||
- @winson.wu on [community.mattermost.com](https://community.mattermost.com/core/messages/@winson.wu) and [@wuwinson](https://github.com/wuwinson) on GitHub
|
||||
|
||||
**Documentation**: Verifies documentation changes, and updates documentation for new features.
|
||||
**Documentation**: Verifies documentation changes and updates documentation for new features.
|
||||
|
||||
- **<a name="justine.geffen">Justine Geffen</a>**
|
||||
- @justine.geffen on [community.mattermost.com](https://community.mattermost.com/core/messages/@justine.geffen) and [@justinegeffen ](https://github.com/justinegeffen) on GitHub
|
||||
|
128
README.md
128
README.md
@ -16,108 +16,106 @@ Like what you see? :eyes: Give us a GitHub Star! :star:
|
||||
|
||||
It helps define, organize, track and manage work across individuals and teams. Focalboard comes in two main editions:
|
||||
|
||||
* **[Personal Desktop](https://www.focalboard.com/download/personal-edition/desktop/)**: A stand-alone single-user Mac, Windows, or Linux desktop app for your todos and personal projects.
|
||||
* **[Personal Desktop](https://www.focalboard.com/download/personal-edition/desktop/)**: A standalone, single-user Mac, Windows, or Linux desktop app for your own todos and personal projects.
|
||||
|
||||
* **[Mattermost Boards](https://www.focalboard.com/download/mattermost/)**: A self-hosted or cloud server for your team to plan and collaborate.
|
||||
|
||||
Focalboard can also be installed as a standalone [personal server](https://www.focalboard.com/download/personal-edition/ubuntu/) for development and personal use.
|
||||
Focalboard can also be installed as a standalone **[Personal Server](https://www.focalboard.com/download/personal-edition/ubuntu/)** for development and personal use.
|
||||
|
||||
## Try out Focalboard
|
||||
## Try Focalboard
|
||||
|
||||
### Focalboard Personal Desktop (Windows, Mac or Linux Desktop)
|
||||
### Personal Desktop (Windows, Mac or Linux Desktop)
|
||||
|
||||
Try out the single-user **Focalboard Personal Desktop**:
|
||||
* macOS: Download from the [Mac App Store](https://apps.apple.com/us/app/focalboard-insiders/id1556908618?mt=12).
|
||||
* 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`
|
||||
* Linux Desktop: Download `focalboard-linux.tar.gz` from the [latest release](https://github.com/mattermost/focalboard/releases), unpack, and open `focalboard-app`
|
||||
* **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`.
|
||||
|
||||
### Mattermost Boards
|
||||
|
||||
Mattermost Boards combines project management tools with messaging and collaboration for teams of all sizes. To access and use Boards, install or upgrade to Mattermost v6.0 or later as a [self-hosted server](https://docs.mattermost.com/guides/deployment.html?utm_source=focalboard&utm_campaign=focalboard) or [Cloud server](https://mattermost.com/get-started/?utm_source=focalboard&utm_campaign=focalboard). After logging into Mattermost, select the menu in the top left corner of Mattermost and choose **Boards**.
|
||||
**Mattermost Boards** is the Mattermost plugin version of Focalboard that combines project management tools with messaging and collaboration for teams of all sizes. To access and use **Mattermost Boards**, install or upgrade to Mattermost v6.0 or later as a [self-hosted server](https://docs.mattermost.com/guides/deployment.html?utm_source=focalboard&utm_campaign=focalboard) or [Cloud server](https://mattermost.com/get-started/?utm_source=focalboard&utm_campaign=focalboard). After logging into Mattermost, select the menu in the top left corner and select **Boards**.
|
||||
|
||||
See the [setup guide](https://www.focalboard.com/download/mattermost/) for more details.
|
||||
***Mattermost Boards** is installed and enabled by default in Mattermost v6.0 and later.*
|
||||
|
||||
### Focalboard Personal Server (Ubuntu)
|
||||
See the [plugin setup guide](https://www.focalboard.com/download/mattermost/) for more details.
|
||||
|
||||
You can download and run the compiled **Focalboard Personal Server** by following [our latest install guide](https://www.focalboard.com/download/personal-edition/ubuntu/).
|
||||
### Personal Server
|
||||
|
||||
Download the latest server release from [GitHub releases](https://github.com/mattermost/focalboard/releases)
|
||||
**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/).
|
||||
|
||||
## Building the server
|
||||
## Contribute to Focalboard
|
||||
|
||||
Most development can be done on the Personal Server edition. Please refer to the [Developer's Tips & Tricks](https://mattermost.github.io/focalboard/dev-tips) for more detailed steps. Here's a summary:
|
||||
Contribute code, bug reports, and ideas to the future of the Focalboard project. We welcome your input! Please see [CONTRIBUTING](CONTRIBUTING.md) for details on how to get involved.
|
||||
|
||||
First, install basic dependencies:
|
||||
* Go 1.15+
|
||||
* Node 16.3+ and npm
|
||||
* Mingw64 on Windows
|
||||
### 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**. It also provides more information about contributing to our open source community.
|
||||
|
||||
To build the server:
|
||||
|
||||
```
|
||||
make prebuild
|
||||
make
|
||||
```
|
||||
|
||||
## Running and testing the server
|
||||
To run the server:
|
||||
|
||||
To start the server, run `./bin/focalboard-server`
|
||||
```
|
||||
./bin/focalboard-server
|
||||
```
|
||||
|
||||
Server settings are in config.json (or the path specified with --config).
|
||||
Then navigate your browser to [`http://localhost:8000`](http://localhost:8000) to access your Focalboard server. The port is configured in `config.json`.
|
||||
|
||||
Open a browser to [http://localhost:8000](http://localhost:8000) to start.
|
||||
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
|
||||
### Building and running standalone desktop apps
|
||||
|
||||
You can build standalone apps that package the server to run locally against SQLite:
|
||||
|
||||
* Mac:
|
||||
* **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 win-wpf-app`
|
||||
* Run `cd win-wpf/msix && focalboard.exe`
|
||||
* **Mac**:
|
||||
* *Requires macOS 11.3+ and Xcode 13.2.1+*
|
||||
* `make mac-app`
|
||||
* run `mac/dist/Focalboard.app`
|
||||
* *Requires: macOS 11.3+, Xcode 13.2.1+*
|
||||
* Linux:
|
||||
* Install webgtk dependencies
|
||||
* `open mac/dist/Focalboard.app`
|
||||
* **Linux**:
|
||||
* *Tested on Ubuntu 18.04*
|
||||
* Install `webgtk` dependencies
|
||||
* `sudo apt-get install libgtk-3-dev`
|
||||
* `sudo apt-get install libwebkit2gtk-4.0-dev`
|
||||
* `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
|
||||
* *Tested with: Ubuntu 18.04*
|
||||
* Windows:
|
||||
* Open a git-bash prompt
|
||||
* `make win-wpf-app`
|
||||
* run `cd win-wpf/msix && focalboard.exe`
|
||||
* *Requires: Windows 10, [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/) 10.0.19041.0, .NET 4.8 developer pack*
|
||||
* 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 .`
|
||||
* 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.
|
||||
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 tests
|
||||
### Unit testing
|
||||
|
||||
Before checking-in commits, run: `make ci`, which is similar to the ci.yml workflow and includes:
|
||||
* Server unit tests: `make server-test`
|
||||
* Webapp eslint: `cd webapp; npm run check`
|
||||
* Webapp unit tests: `cd webapp; npm run test`
|
||||
* Webapp UI tests: `cd webapp; npm run cypress:ci`
|
||||
Before checking in commits, run `make ci`, which is similar to the `.gitlab-ci.yml` workflow and includes:
|
||||
|
||||
## Stay informed on progress
|
||||
* **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`
|
||||
|
||||
* **Changelog**: See [CHANGELOG.md](CHANGELOG.md) for the latest updates
|
||||
* **Developer Discussion**: Join the [Developer Discussion](https://github.com/mattermost/focalboard/discussions) board
|
||||
* **Chat**: Join the [Focalboard community channel](https://community.mattermost.com/core/channels/focalboard)
|
||||
|
||||
## Share your feedback
|
||||
|
||||
File bugs, suggest features, join our forum, learn more [here](https://github.com/mattermost/focalboard/wiki/Share-your-feedback)!
|
||||
|
||||
## Contributing
|
||||
|
||||
Contribute code, bug reports, and ideas to the future of the Focalboard project. We welcome your input! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to get involved.
|
||||
|
||||
## Translating
|
||||
### Translating
|
||||
|
||||
Help translate Focalboard! The app is already translated into several languages. We welcome corrections and new language translations! You can add new languages or improve existing translations at [Weblate](https://translate.mattermost.com/engage/focalboard/).
|
||||
|
||||
### Staying informed
|
||||
|
||||
Are you interested in influencing the future of the Focalboard open source project? Here's how you can get involved:
|
||||
|
||||
* **Changes**: See the [CHANGELOG](CHANGELOG.md) for the latest updates
|
||||
* **GitHub Discussions**: Join the [Developer Discussion](https://github.com/mattermost/focalboard/discussions) board
|
||||
* **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)
|
||||
|
@ -1,3 +1,7 @@
|
||||
# Focalboard Plugin for Mattermost
|
||||
# Mattermost Boards (Focalboard Plugin)
|
||||
|
||||
This plugin allows to run focalboard inside your mattermost instance as a plugin.
|
||||
**[Mattermost Boards](https://mattermost.com/boards/)** is the Mattermost plugin version of Focalboard that combines project management tools with messaging and collaboration for teams of all sizes. To access and use **Mattermost Boards**, install or upgrade to Mattermost v6.0 or later as a [self-hosted server](https://docs.mattermost.com/guides/deployment.html?utm_source=focalboard&utm_campaign=focalboard) or [Cloud server](https://mattermost.com/get-started/?utm_source=focalboard&utm_campaign=focalboard). After logging into Mattermost, select the menu in the top left corner of Mattermost and select **Boards**.
|
||||
|
||||
***Mattermost Boards** is installed and enabled by default in Mattermost v6.0 and later.*
|
||||
|
||||
To build your own version of Matterboard Boards and upload it to your own Mattermost server, follow the instructions [here](https://developers.mattermost.com/contribute/focalboard/mattermost-boards-setup-guide/).
|
||||
|
@ -189,8 +189,11 @@ export default class Plugin {
|
||||
if (currentTeamID && currentTeamID !== prevTeamID) {
|
||||
prevTeamID = currentTeamID
|
||||
store.dispatch(setTeam(currentTeamID))
|
||||
browserHistory.push(`/team/${currentTeamID}`)
|
||||
wsClient.subscribeToTeam(currentTeamID)
|
||||
if (window.location.pathname.startsWith(windowAny.frontendBaseURL || '')) {
|
||||
console.log("REDIRECTING HERE")
|
||||
browserHistory.push(`/team/${currentTeamID}`)
|
||||
wsClient.subscribeToTeam(currentTeamID)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -89,6 +89,7 @@ func (a *API) RegisterRoutes(r *mux.Router) {
|
||||
apiv1.HandleFunc("/boards/{boardID}/blocks/{blockID}/undelete", a.sessionRequired(a.handleUndeleteBlock)).Methods("POST")
|
||||
apiv1.HandleFunc("/boards/{boardID}/blocks/{blockID}/subtree", a.attachSession(a.handleGetSubTree, false)).Methods("GET")
|
||||
apiv1.HandleFunc("/boards/{boardID}/blocks/{blockID}/duplicate", a.attachSession(a.handleDuplicateBlock, false)).Methods("POST")
|
||||
apiv1.HandleFunc("/boards/{boardID}/metadata", a.sessionRequired(a.handleGetBoardMetadata)).Methods("GET")
|
||||
|
||||
// Import&Export APIs
|
||||
apiv1.HandleFunc("/boards/{boardID}/blocks/export", a.sessionRequired(a.handleExport)).Methods("GET")
|
||||
@ -99,6 +100,7 @@ func (a *API) RegisterRoutes(r *mux.Router) {
|
||||
apiv1.HandleFunc("/boards/{boardID}/members", a.sessionRequired(a.handleAddMember)).Methods("POST")
|
||||
apiv1.HandleFunc("/boards/{boardID}/members/{userID}", a.sessionRequired(a.handleUpdateMember)).Methods("PUT")
|
||||
apiv1.HandleFunc("/boards/{boardID}/members/{userID}", a.sessionRequired(a.handleDeleteMember)).Methods("DELETE")
|
||||
apiv1.HandleFunc("/boards/{boardID}/join", a.sessionRequired(a.handleJoinBoard)).Methods("POST")
|
||||
|
||||
// Sharing APIs
|
||||
apiv1.HandleFunc("/boards/{boardID}/sharing", a.sessionRequired(a.handlePostSharing)).Methods("POST")
|
||||
@ -2968,6 +2970,81 @@ func (a *API) handleDuplicateBlock(w http.ResponseWriter, r *http.Request) {
|
||||
auditRec.Success()
|
||||
}
|
||||
|
||||
func (a *API) handleGetBoardMetadata(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation GET /api/v1/boards/{boardID}/metadata getBoardMetadata
|
||||
//
|
||||
// Returns a board's metadata
|
||||
//
|
||||
// ---
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: boardID
|
||||
// in: path
|
||||
// description: Board ID
|
||||
// required: true
|
||||
// type: string
|
||||
// security:
|
||||
// - BearerAuth: []
|
||||
// responses:
|
||||
// '200':
|
||||
// description: success
|
||||
// schema:
|
||||
// "$ref": "#/definitions/BoardMetadata"
|
||||
// '404':
|
||||
// description: board not found
|
||||
// '501':
|
||||
// description: required license not found
|
||||
// default:
|
||||
// description: internal error
|
||||
// schema:
|
||||
// "$ref": "#/definitions/ErrorResponse"
|
||||
|
||||
boardID := mux.Vars(r)["boardID"]
|
||||
userID := getUserID(r)
|
||||
|
||||
board, boardMetadata, err := a.app.GetBoardMetadata(boardID)
|
||||
if errors.Is(err, app.ErrInsufficientLicense) {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusNotImplemented, "", err)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
}
|
||||
if board == nil || boardMetadata == nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusNotFound, "", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if board.Type == model.BoardTypePrivate {
|
||||
if !a.permissions.HasPermissionToBoard(userID, boardID, model.PermissionViewBoard) {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", PermissionError{"access denied to board"})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !a.permissions.HasPermissionToTeam(userID, board.TeamID, model.PermissionViewTeam) {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", PermissionError{"access denied to board"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
auditRec := a.makeAuditRecord(r, "getBoardMetadata", audit.Fail)
|
||||
defer a.audit.LogRecord(audit.LevelRead, auditRec)
|
||||
auditRec.AddMeta("boardID", boardID)
|
||||
|
||||
data, err := json.Marshal(boardMetadata)
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
}
|
||||
|
||||
// response
|
||||
jsonBytesResponse(w, http.StatusOK, data)
|
||||
|
||||
auditRec.Success()
|
||||
}
|
||||
|
||||
func (a *API) handleSearchBoards(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation GET /api/v1/teams/{teamID}/boards/search searchBoards
|
||||
//
|
||||
@ -3214,6 +3291,98 @@ func (a *API) handleAddMember(w http.ResponseWriter, r *http.Request) {
|
||||
auditRec.Success()
|
||||
}
|
||||
|
||||
func (a *API) handleJoinBoard(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation POST /boards/{boardID}/join joinBoard
|
||||
//
|
||||
// Become a member of a board
|
||||
//
|
||||
// ---
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: boardID
|
||||
// in: path
|
||||
// description: Board ID
|
||||
// required: true
|
||||
// type: string
|
||||
// security:
|
||||
// - BearerAuth: []
|
||||
// responses:
|
||||
// '200':
|
||||
// description: success
|
||||
// schema:
|
||||
// $ref: '#/definitions/BoardMember'
|
||||
// '404':
|
||||
// description: board not found
|
||||
// '503':
|
||||
// description: access denied
|
||||
// default:
|
||||
// description: internal error
|
||||
// schema:
|
||||
// "$ref": "#/definitions/ErrorResponse"
|
||||
|
||||
userID := getUserID(r)
|
||||
if userID == "" {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusBadRequest, "", nil)
|
||||
return
|
||||
}
|
||||
|
||||
boardID := mux.Vars(r)["boardID"]
|
||||
board, err := a.app.GetBoard(boardID)
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
}
|
||||
if board == nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusNotFound, "", nil)
|
||||
return
|
||||
}
|
||||
if board.Type != model.BoardTypeOpen {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if !a.permissions.HasPermissionToTeam(userID, board.TeamID, model.PermissionViewTeam) {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// currently all memberships are created as editors by default
|
||||
// TODO: Support different public roles
|
||||
newBoardMember := &model.BoardMember{
|
||||
UserID: userID,
|
||||
BoardID: boardID,
|
||||
SchemeEditor: true,
|
||||
}
|
||||
|
||||
auditRec := a.makeAuditRecord(r, "joinBoard", audit.Fail)
|
||||
defer a.audit.LogRecord(audit.LevelModify, auditRec)
|
||||
auditRec.AddMeta("boardID", boardID)
|
||||
auditRec.AddMeta("addedUserID", userID)
|
||||
|
||||
member, err := a.app.AddMemberToBoard(newBoardMember)
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
}
|
||||
|
||||
a.logger.Debug("AddMember",
|
||||
mlog.String("boardID", board.ID),
|
||||
mlog.String("addedUserID", userID),
|
||||
)
|
||||
|
||||
data, err := json.Marshal(member)
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
}
|
||||
|
||||
// response
|
||||
jsonBytesResponse(w, http.StatusOK, data)
|
||||
|
||||
auditRec.Success()
|
||||
}
|
||||
|
||||
func (a *API) handleUpdateMember(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation PUT /boards/{boardID}/members/{userID} updateMember
|
||||
//
|
||||
|
@ -3,6 +3,7 @@ package app
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mattermost/focalboard/server/model"
|
||||
"github.com/mattermost/focalboard/server/utils"
|
||||
@ -11,6 +12,7 @@ import (
|
||||
var (
|
||||
ErrBoardMemberIsLastAdmin = errors.New("cannot leave a board with no admins")
|
||||
ErrNewBoardCannotHaveID = errors.New("new board cannot have an ID")
|
||||
ErrInsufficientLicense = errors.New("appropriate license required")
|
||||
)
|
||||
|
||||
func (a *App) GetBoard(boardID string) (*model.Board, error) {
|
||||
@ -24,6 +26,105 @@ func (a *App) GetBoard(boardID string) (*model.Board, error) {
|
||||
return board, nil
|
||||
}
|
||||
|
||||
func (a *App) GetBoardMetadata(boardID string) (*model.Board, *model.BoardMetadata, error) {
|
||||
license := a.store.GetLicense()
|
||||
if license == nil || !(*license.Features.Compliance) {
|
||||
return nil, nil, ErrInsufficientLicense
|
||||
}
|
||||
|
||||
board, err := a.GetBoard(boardID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if board == nil {
|
||||
// Board may have been deleted, retrieve most recent history instead
|
||||
board, err = a.getBoardHistory(boardID, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if board == nil {
|
||||
// Board not found
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
earliestTime, _, err := a.getBoardDescendantModifiedInfo(boardID, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
latestTime, lastModifiedBy, err := a.getBoardDescendantModifiedInfo(boardID, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
boardMetadata := model.BoardMetadata{
|
||||
BoardID: boardID,
|
||||
DescendantFirstUpdateAt: earliestTime,
|
||||
DescendantLastUpdateAt: latestTime,
|
||||
CreatedBy: board.CreatedBy,
|
||||
LastModifiedBy: lastModifiedBy,
|
||||
}
|
||||
return board, &boardMetadata, nil
|
||||
}
|
||||
|
||||
func (a *App) getBoardHistory(boardID string, latest bool) (*model.Board, error) {
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Limit: 1,
|
||||
Descending: latest,
|
||||
}
|
||||
boards, err := a.store.GetBoardHistory(boardID, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get history for board: %w", err)
|
||||
}
|
||||
if len(boards) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return boards[0], nil
|
||||
}
|
||||
|
||||
func (a *App) getBoardDescendantModifiedInfo(boardID string, latest bool) (int64, string, error) {
|
||||
board, err := a.getBoardHistory(boardID, latest)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
if board == nil {
|
||||
return 0, "", fmt.Errorf("history not found for board: %w", err)
|
||||
}
|
||||
|
||||
var timestamp int64
|
||||
modifiedBy := board.ModifiedBy
|
||||
if latest {
|
||||
timestamp = board.UpdateAt
|
||||
} else {
|
||||
timestamp = board.CreateAt
|
||||
}
|
||||
|
||||
// use block_history to fetch blocks in case they were deleted and no longer exist in blocks table.
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Limit: 1,
|
||||
Descending: latest,
|
||||
}
|
||||
blocks, err := a.store.GetBlockHistoryDescendants(boardID, opts)
|
||||
if err != nil {
|
||||
return 0, "", fmt.Errorf("could not get blocks history descendants for board: %w", err)
|
||||
}
|
||||
if len(blocks) > 0 {
|
||||
// Compare the board history info with the descendant block info, if it exists
|
||||
block := &blocks[0]
|
||||
if latest && block.UpdateAt > timestamp {
|
||||
timestamp = block.UpdateAt
|
||||
modifiedBy = block.ModifiedBy
|
||||
} else if !latest && block.CreateAt < timestamp {
|
||||
timestamp = block.CreateAt
|
||||
modifiedBy = block.ModifiedBy
|
||||
}
|
||||
}
|
||||
return timestamp, modifiedBy, nil
|
||||
}
|
||||
|
||||
func (a *App) DuplicateBoard(boardID, userID, toTeam string, asTemplate bool) (*model.BoardsAndBlocks, []*model.BoardMember, error) {
|
||||
bab, members, err := a.store.DuplicateBoard(boardID, userID, toTeam, asTemplate)
|
||||
if err != nil {
|
||||
|
@ -176,10 +176,22 @@ func (c *Client) GetBoardRoute(boardID string) string {
|
||||
return fmt.Sprintf("%s/%s", c.GetBoardsRoute(), boardID)
|
||||
}
|
||||
|
||||
func (c *Client) GetBoardMetadataRoute(boardID string) string {
|
||||
return fmt.Sprintf("%s/%s/metadata", c.GetBoardsRoute(), boardID)
|
||||
}
|
||||
|
||||
func (c *Client) GetJoinBoardRoute(boardID string) string {
|
||||
return fmt.Sprintf("%s/%s/join", c.GetBoardsRoute(), boardID)
|
||||
}
|
||||
|
||||
func (c *Client) GetBlocksRoute(boardID string) string {
|
||||
return fmt.Sprintf("%s/blocks", c.GetBoardRoute(boardID))
|
||||
}
|
||||
|
||||
func (c *Client) GetAllBlocksRoute(boardID string) string {
|
||||
return fmt.Sprintf("%s/blocks?all=true", c.GetBoardRoute(boardID))
|
||||
}
|
||||
|
||||
func (c *Client) GetBoardsAndBlocksRoute() string {
|
||||
return "/boards-and-blocks"
|
||||
}
|
||||
@ -204,6 +216,16 @@ func (c *Client) GetBlocksForBoard(boardID string) ([]model.Block, *Response) {
|
||||
return model.BlocksFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) GetAllBlocksForBoard(boardID string) ([]model.Block, *Response) {
|
||||
r, err := c.DoAPIGet(c.GetAllBlocksRoute(boardID), "")
|
||||
if err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
|
||||
return model.BlocksFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) PatchBlock(boardID, blockID string, blockPatch *model.BlockPatch) (bool, *Response) {
|
||||
r, err := c.DoAPIPatch(c.GetBlockRoute(boardID, blockID), toJSON(blockPatch))
|
||||
if err != nil {
|
||||
@ -214,18 +236,21 @@ func (c *Client) PatchBlock(boardID, blockID string, blockPatch *model.BlockPatc
|
||||
return true, BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) DuplicateBoard(boardID string, asTemplate bool, teamID string) (bool, *Response) {
|
||||
func (c *Client) DuplicateBoard(boardID string, asTemplate bool, teamID string) (*model.BoardsAndBlocks, *Response) {
|
||||
queryParams := "?asTemplate=false&"
|
||||
if asTemplate {
|
||||
queryParams = "?asTemplate=true"
|
||||
}
|
||||
if len(teamID) > 0 {
|
||||
queryParams = queryParams + "&toTeam=" + teamID
|
||||
}
|
||||
r, err := c.DoAPIPost(c.GetBoardRoute(boardID)+"/duplicate"+queryParams, "")
|
||||
if err != nil {
|
||||
return false, BuildErrorResponse(r, err)
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
|
||||
return true, BuildResponse(r)
|
||||
return model.BoardsAndBlocksFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) DuplicateBlock(boardID, blockID string, asTemplate bool) (bool, *Response) {
|
||||
@ -472,6 +497,21 @@ func (c *Client) GetBoard(boardID, readToken string) (*model.Board, *Response) {
|
||||
return model.BoardFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) GetBoardMetadata(boardID, readToken string) (*model.BoardMetadata, *Response) {
|
||||
url := c.GetBoardMetadataRoute(boardID)
|
||||
if readToken != "" {
|
||||
url += fmt.Sprintf("?read_token=%s", readToken)
|
||||
}
|
||||
|
||||
r, err := c.DoAPIGet(url, "")
|
||||
if err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
|
||||
return model.BoardMetadataFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) GetBoardsForTeam(teamID string) ([]*model.Board, *Response) {
|
||||
r, err := c.DoAPIGet(c.GetTeamRoute(teamID)+"/boards", "")
|
||||
if err != nil {
|
||||
@ -512,6 +552,16 @@ func (c *Client) AddMemberToBoard(member *model.BoardMember) (*model.BoardMember
|
||||
return model.BoardMemberFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) JoinBoard(boardID string) (*model.BoardMember, *Response) {
|
||||
r, err := c.DoAPIPost(c.GetJoinBoardRoute(boardID), "")
|
||||
if err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
|
||||
return model.BoardMemberFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) UpdateBoardMember(member *model.BoardMember) (*model.BoardMember, *Response) {
|
||||
r, err := c.DoAPIPut(c.GetBoardRoute(member.BoardID)+"/members/"+member.UserID, toJSON(member))
|
||||
if err != nil {
|
||||
@ -613,3 +663,13 @@ func (c *Client) GetSubscriptions(subscriberID string) ([]*model.Subscription, *
|
||||
|
||||
return subs, BuildResponse(r)
|
||||
}
|
||||
|
||||
func (c *Client) GetTemplatesForTeam(teamID string) ([]*model.Board, *Response) {
|
||||
r, err := c.DoAPIGet(c.GetTeamRoute(teamID)+"/templates", "")
|
||||
if err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
|
||||
return model.BoardsFromJSON(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package integrationtests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/focalboard/server/client"
|
||||
"github.com/mattermost/focalboard/server/model"
|
||||
@ -468,6 +470,185 @@ func TestGetBoard(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetBoardMetadata(t *testing.T) {
|
||||
t.Run("a non authenticated user should be rejected", func(t *testing.T) {
|
||||
th := SetupTestHelperWithLicense(t, LicenseEnterprise).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.Logout(th.Client)
|
||||
|
||||
boardMetadata, resp := th.Client.GetBoardMetadata("boar-id", "")
|
||||
th.CheckUnauthorized(resp)
|
||||
require.Nil(t, boardMetadata)
|
||||
})
|
||||
|
||||
t.Run("getBoardMetadata query is correct", func(t *testing.T) {
|
||||
th := SetupTestHelperWithLicense(t, LicenseEnterprise).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.Server.Config().EnablePublicSharedBoards = true
|
||||
|
||||
teamID := testTeamID
|
||||
|
||||
board := &model.Board{
|
||||
Title: "public board where user1 is admin",
|
||||
Type: model.BoardTypeOpen,
|
||||
TeamID: teamID,
|
||||
}
|
||||
rBoard, err := th.Server.App().CreateBoard(board, th.GetUser1().ID, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check metadata
|
||||
boardMetadata, resp := th.Client.GetBoardMetadata(rBoard.ID, "")
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, boardMetadata)
|
||||
|
||||
require.Equal(t, rBoard.CreatedBy, boardMetadata.CreatedBy)
|
||||
require.Equal(t, rBoard.CreateAt, boardMetadata.DescendantFirstUpdateAt)
|
||||
require.Equal(t, rBoard.UpdateAt, boardMetadata.DescendantLastUpdateAt)
|
||||
require.Equal(t, rBoard.ModifiedBy, boardMetadata.LastModifiedBy)
|
||||
|
||||
// Insert card1
|
||||
card1 := model.Block{
|
||||
ID: "card1",
|
||||
BoardID: rBoard.ID,
|
||||
Title: "Card 1",
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
require.NoError(t, th.Server.App().InsertBlock(card1, th.GetUser2().ID))
|
||||
rCard1, err := th.Server.App().GetBlockByID(card1.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check updated metadata
|
||||
boardMetadata, resp = th.Client.GetBoardMetadata(rBoard.ID, "")
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, boardMetadata)
|
||||
|
||||
require.Equal(t, rBoard.CreatedBy, boardMetadata.CreatedBy)
|
||||
require.Equal(t, rBoard.CreateAt, boardMetadata.DescendantFirstUpdateAt)
|
||||
require.Equal(t, rCard1.UpdateAt, boardMetadata.DescendantLastUpdateAt)
|
||||
require.Equal(t, rCard1.ModifiedBy, boardMetadata.LastModifiedBy)
|
||||
|
||||
// Insert card2
|
||||
card2 := model.Block{
|
||||
ID: "card2",
|
||||
BoardID: rBoard.ID,
|
||||
Title: "Card 2",
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
require.NoError(t, th.Server.App().InsertBlock(card2, th.GetUser1().ID))
|
||||
rCard2, err := th.Server.App().GetBlockByID(card2.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check updated metadata
|
||||
boardMetadata, resp = th.Client.GetBoardMetadata(rBoard.ID, "")
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, boardMetadata)
|
||||
require.Equal(t, rBoard.CreatedBy, boardMetadata.CreatedBy)
|
||||
require.Equal(t, rBoard.CreateAt, boardMetadata.DescendantFirstUpdateAt)
|
||||
require.Equal(t, rCard2.UpdateAt, boardMetadata.DescendantLastUpdateAt)
|
||||
require.Equal(t, rCard2.ModifiedBy, boardMetadata.LastModifiedBy)
|
||||
|
||||
t.Run("After delete board", func(t *testing.T) {
|
||||
// Delete board
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
require.NoError(t, th.Server.App().DeleteBoard(rBoard.ID, th.GetUser1().ID))
|
||||
|
||||
// Check updated metadata
|
||||
boardMetadata, resp = th.Client.GetBoardMetadata(rBoard.ID, "")
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, boardMetadata)
|
||||
require.Equal(t, rBoard.CreatedBy, boardMetadata.CreatedBy)
|
||||
require.Equal(t, rBoard.CreateAt, boardMetadata.DescendantFirstUpdateAt)
|
||||
require.Greater(t, boardMetadata.DescendantLastUpdateAt, rCard2.UpdateAt)
|
||||
require.Equal(t, th.GetUser1().ID, boardMetadata.LastModifiedBy)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("getBoardMetadata should fail with no license", func(t *testing.T) {
|
||||
th := SetupTestHelperWithLicense(t, LicenseNone).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.Server.Config().EnablePublicSharedBoards = true
|
||||
|
||||
teamID := testTeamID
|
||||
|
||||
board := &model.Board{
|
||||
Title: "public board where user1 is admin",
|
||||
Type: model.BoardTypeOpen,
|
||||
TeamID: teamID,
|
||||
}
|
||||
rBoard, err := th.Server.App().CreateBoard(board, th.GetUser1().ID, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check metadata
|
||||
boardMetadata, resp := th.Client.GetBoardMetadata(rBoard.ID, "")
|
||||
th.CheckNotImplemented(resp)
|
||||
require.Nil(t, boardMetadata)
|
||||
})
|
||||
|
||||
t.Run("getBoardMetadata should fail on Professional license", func(t *testing.T) {
|
||||
th := SetupTestHelperWithLicense(t, LicenseProfessional).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.Server.Config().EnablePublicSharedBoards = true
|
||||
|
||||
teamID := testTeamID
|
||||
|
||||
board := &model.Board{
|
||||
Title: "public board where user1 is admin",
|
||||
Type: model.BoardTypeOpen,
|
||||
TeamID: teamID,
|
||||
}
|
||||
rBoard, err := th.Server.App().CreateBoard(board, th.GetUser1().ID, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check metadata
|
||||
boardMetadata, resp := th.Client.GetBoardMetadata(rBoard.ID, "")
|
||||
th.CheckNotImplemented(resp)
|
||||
require.Nil(t, boardMetadata)
|
||||
})
|
||||
|
||||
t.Run("valid read token should not get the board metadata", func(t *testing.T) {
|
||||
th := SetupTestHelperWithLicense(t, LicenseEnterprise).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.Server.Config().EnablePublicSharedBoards = true
|
||||
|
||||
teamID := testTeamID
|
||||
sharingToken := utils.NewID(utils.IDTypeToken)
|
||||
userID := th.GetUser1().ID
|
||||
|
||||
board := &model.Board{
|
||||
Title: "public board where user1 is admin",
|
||||
Type: model.BoardTypeOpen,
|
||||
TeamID: teamID,
|
||||
}
|
||||
rBoard, err := th.Server.App().CreateBoard(board, userID, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
sharing := &model.Sharing{
|
||||
ID: rBoard.ID,
|
||||
Enabled: true,
|
||||
Token: sharingToken,
|
||||
UpdateAt: 1,
|
||||
}
|
||||
|
||||
success, resp := th.Client.PostSharing(sharing)
|
||||
th.CheckOK(resp)
|
||||
require.True(t, success)
|
||||
|
||||
// the client logs out
|
||||
th.Logout(th.Client)
|
||||
|
||||
// we make sure that the client cannot currently retrieve the
|
||||
// board with no session
|
||||
boardMetadata, resp := th.Client.GetBoardMetadata(rBoard.ID, "")
|
||||
th.CheckUnauthorized(resp)
|
||||
require.Nil(t, boardMetadata)
|
||||
|
||||
// it should not be able to retrieve it with the read token either
|
||||
boardMetadata, resp = th.Client.GetBoardMetadata(rBoard.ID, sharingToken)
|
||||
th.CheckUnauthorized(resp)
|
||||
require.Nil(t, boardMetadata)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPatchBoard(t *testing.T) {
|
||||
teamID := testTeamID
|
||||
|
||||
@ -1268,3 +1449,128 @@ func TestDeleteMember(t *testing.T) {
|
||||
require.True(t, members[0].SchemeAdmin)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetTemplates(t *testing.T) {
|
||||
t.Run("should be able to retrieve built-in templates", func(t *testing.T) {
|
||||
th := SetupTestHelper(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
teamID := "my-team-id"
|
||||
rBoards, resp := th.Client.GetTemplatesForTeam("0")
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, rBoards)
|
||||
require.GreaterOrEqual(t, len(rBoards), 6)
|
||||
|
||||
t.Log("\n\n")
|
||||
for _, board := range rBoards {
|
||||
t.Logf("Test get template: %s - %s\n", board.Title, board.ID)
|
||||
rBoard, resp := th.Client.GetBoard(board.ID, "")
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, rBoard)
|
||||
require.Equal(t, board, rBoard)
|
||||
|
||||
rBlocks, resp := th.Client.GetAllBlocksForBoard(board.ID)
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, rBlocks)
|
||||
require.Greater(t, len(rBlocks), 0)
|
||||
t.Logf("Got %d block(s)\n", len(rBlocks))
|
||||
|
||||
rBoardsAndBlock, resp := th.Client.DuplicateBoard(board.ID, false, teamID)
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, rBoardsAndBlock)
|
||||
require.Greater(t, len(rBoardsAndBlock.Boards), 0)
|
||||
require.Greater(t, len(rBoardsAndBlock.Blocks), 0)
|
||||
|
||||
rBoard2 := rBoardsAndBlock.Boards[0]
|
||||
require.Contains(t, board.Title, rBoard2.Title)
|
||||
require.False(t, rBoard2.IsTemplate)
|
||||
|
||||
t.Logf("Duplicate template: %s - %s, %d block(s)\n", rBoard2.Title, rBoard2.ID, len(rBoardsAndBlock.Blocks))
|
||||
rBoard3, resp := th.Client.GetBoard(rBoard2.ID, "")
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, rBoard3)
|
||||
require.Equal(t, rBoard2, rBoard3)
|
||||
|
||||
rBlocks2, resp := th.Client.GetAllBlocksForBoard(rBoard2.ID)
|
||||
th.CheckOK(resp)
|
||||
require.NotNil(t, rBlocks2)
|
||||
require.Equal(t, len(rBoardsAndBlock.Blocks), len(rBlocks2))
|
||||
}
|
||||
t.Log("\n\n")
|
||||
})
|
||||
}
|
||||
|
||||
func TestJoinBoard(t *testing.T) {
|
||||
t.Run("create and join public board", func(t *testing.T) {
|
||||
th := SetupTestHelper(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
me := th.GetUser1()
|
||||
|
||||
title := "Public board"
|
||||
teamID := testTeamID
|
||||
newBoard := &model.Board{
|
||||
Title: title,
|
||||
Type: model.BoardTypeOpen,
|
||||
TeamID: teamID,
|
||||
}
|
||||
board, resp := th.Client.CreateBoard(newBoard)
|
||||
th.CheckOK(resp)
|
||||
require.NoError(t, resp.Error)
|
||||
require.NotNil(t, board)
|
||||
require.NotNil(t, board.ID)
|
||||
require.Equal(t, title, board.Title)
|
||||
require.Equal(t, model.BoardTypeOpen, board.Type)
|
||||
require.Equal(t, teamID, board.TeamID)
|
||||
require.Equal(t, me.ID, board.CreatedBy)
|
||||
require.Equal(t, me.ID, board.ModifiedBy)
|
||||
|
||||
member, resp := th.Client2.JoinBoard(board.ID)
|
||||
th.CheckOK(resp)
|
||||
require.NoError(t, resp.Error)
|
||||
require.NotNil(t, member)
|
||||
require.Equal(t, board.ID, member.BoardID)
|
||||
require.Equal(t, th.GetUser2().ID, member.UserID)
|
||||
|
||||
s, _ := json.MarshalIndent(member, "", "\t")
|
||||
t.Log(string(s))
|
||||
})
|
||||
|
||||
t.Run("create and join private board (should not succeed)", func(t *testing.T) {
|
||||
th := SetupTestHelper(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
me := th.GetUser1()
|
||||
|
||||
title := "Private board"
|
||||
teamID := testTeamID
|
||||
newBoard := &model.Board{
|
||||
Title: title,
|
||||
Type: model.BoardTypePrivate,
|
||||
TeamID: teamID,
|
||||
}
|
||||
board, resp := th.Client.CreateBoard(newBoard)
|
||||
th.CheckOK(resp)
|
||||
require.NoError(t, resp.Error)
|
||||
require.NotNil(t, board)
|
||||
require.NotNil(t, board.ID)
|
||||
require.Equal(t, title, board.Title)
|
||||
require.Equal(t, model.BoardTypePrivate, board.Type)
|
||||
require.Equal(t, teamID, board.TeamID)
|
||||
require.Equal(t, me.ID, board.CreatedBy)
|
||||
require.Equal(t, me.ID, board.ModifiedBy)
|
||||
|
||||
member, resp := th.Client2.JoinBoard(board.ID)
|
||||
th.CheckForbidden(resp)
|
||||
require.Nil(t, member)
|
||||
})
|
||||
|
||||
t.Run("join invalid board", func(t *testing.T) {
|
||||
th := SetupTestHelper(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
member, resp := th.Client2.JoinBoard("nonexistent-board-ID")
|
||||
th.CheckNotFound(resp)
|
||||
require.Nil(t, member)
|
||||
})
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/mattermost/focalboard/server/server"
|
||||
"github.com/mattermost/focalboard/server/services/config"
|
||||
"github.com/mattermost/focalboard/server/services/permissions/localpermissions"
|
||||
"github.com/mattermost/focalboard/server/services/store"
|
||||
"github.com/mattermost/focalboard/server/services/store/sqlstore"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
@ -26,6 +27,14 @@ const (
|
||||
password = "Pa$$word"
|
||||
)
|
||||
|
||||
type LicenseType int
|
||||
|
||||
const (
|
||||
LicenseNone LicenseType = iota // 0
|
||||
LicenseProfessional // 1
|
||||
LicenseEnterprise // 2
|
||||
)
|
||||
|
||||
type TestHelper struct {
|
||||
T *testing.T
|
||||
Server *server.Server
|
||||
@ -77,6 +86,10 @@ func getTestConfig() (*config.Configuration, error) {
|
||||
}
|
||||
|
||||
func newTestServer(singleUserToken string) *server.Server {
|
||||
return newTestServerWithLicense(singleUserToken, LicenseNone)
|
||||
}
|
||||
|
||||
func newTestServerWithLicense(singleUserToken string, licenseType LicenseType) *server.Server {
|
||||
cfg, err := getTestConfig()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -86,11 +99,24 @@ func newTestServer(singleUserToken string) *server.Server {
|
||||
if err = logger.Configure("", cfg.LoggingCfgJSON, nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
db, err := server.NewStore(cfg, logger)
|
||||
innerStore, err := server.NewStore(cfg, logger)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var db store.Store
|
||||
|
||||
switch licenseType {
|
||||
case LicenseProfessional:
|
||||
db = NewTestProfessionalStore(innerStore)
|
||||
case LicenseEnterprise:
|
||||
db = NewTestEnterpriseStore(innerStore)
|
||||
case LicenseNone:
|
||||
fallthrough
|
||||
default:
|
||||
db = innerStore
|
||||
}
|
||||
|
||||
permissionsService := localpermissions.New(db, logger)
|
||||
|
||||
params := server.Params{
|
||||
@ -119,8 +145,12 @@ func SetupTestHelperWithToken(t *testing.T) *TestHelper {
|
||||
}
|
||||
|
||||
func SetupTestHelper(t *testing.T) *TestHelper {
|
||||
return SetupTestHelperWithLicense(t, LicenseNone)
|
||||
}
|
||||
|
||||
func SetupTestHelperWithLicense(t *testing.T, licenseType LicenseType) *TestHelper {
|
||||
th := &TestHelper{T: t}
|
||||
th.Server = newTestServer("")
|
||||
th.Server = newTestServerWithLicense("", licenseType)
|
||||
th.Client = client.NewClient(th.Server.Config().ServerRoot, "")
|
||||
th.Client2 = client.NewClient(th.Server.Config().ServerRoot, "")
|
||||
return th
|
||||
@ -285,3 +315,8 @@ func (th *TestHelper) CheckForbidden(r *client.Response) {
|
||||
require.Equal(th.T, http.StatusForbidden, r.StatusCode)
|
||||
require.Error(th.T, r.Error)
|
||||
}
|
||||
|
||||
func (th *TestHelper) CheckNotImplemented(r *client.Response) {
|
||||
require.Equal(th.T, http.StatusNotImplemented, r.StatusCode)
|
||||
require.Error(th.T, r.Error)
|
||||
}
|
||||
|
110
server/integrationtests/teststore.go
Normal file
110
server/integrationtests/teststore.go
Normal file
@ -0,0 +1,110 @@
|
||||
package integrationtests
|
||||
|
||||
import (
|
||||
"github.com/mattermost/focalboard/server/services/store"
|
||||
|
||||
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
type TestStore struct {
|
||||
store.Store
|
||||
license *mmModel.License
|
||||
}
|
||||
|
||||
func NewTestEnterpriseStore(store store.Store) *TestStore {
|
||||
usersValue := 10000
|
||||
trueValue := true
|
||||
falseValue := false
|
||||
license := &mmModel.License{
|
||||
Features: &mmModel.Features{
|
||||
Users: &usersValue,
|
||||
LDAP: &trueValue,
|
||||
LDAPGroups: &trueValue,
|
||||
MFA: &trueValue,
|
||||
GoogleOAuth: &trueValue,
|
||||
Office365OAuth: &trueValue,
|
||||
OpenId: &trueValue,
|
||||
Compliance: &trueValue,
|
||||
Cluster: &trueValue,
|
||||
Metrics: &trueValue,
|
||||
MHPNS: &trueValue,
|
||||
SAML: &trueValue,
|
||||
Elasticsearch: &trueValue,
|
||||
Announcement: &trueValue,
|
||||
ThemeManagement: &trueValue,
|
||||
EmailNotificationContents: &trueValue,
|
||||
DataRetention: &trueValue,
|
||||
MessageExport: &trueValue,
|
||||
CustomPermissionsSchemes: &trueValue,
|
||||
CustomTermsOfService: &trueValue,
|
||||
GuestAccounts: &trueValue,
|
||||
GuestAccountsPermissions: &trueValue,
|
||||
IDLoadedPushNotifications: &trueValue,
|
||||
LockTeammateNameDisplay: &trueValue,
|
||||
EnterprisePlugins: &trueValue,
|
||||
AdvancedLogging: &trueValue,
|
||||
Cloud: &falseValue,
|
||||
SharedChannels: &trueValue,
|
||||
RemoteClusterService: &trueValue,
|
||||
FutureFeatures: &trueValue,
|
||||
},
|
||||
}
|
||||
|
||||
testStore := &TestStore{
|
||||
Store: store,
|
||||
license: license,
|
||||
}
|
||||
|
||||
return testStore
|
||||
}
|
||||
|
||||
func NewTestProfessionalStore(store store.Store) *TestStore {
|
||||
usersValue := 10000
|
||||
trueValue := true
|
||||
falseValue := false
|
||||
license := &mmModel.License{
|
||||
Features: &mmModel.Features{
|
||||
Users: &usersValue,
|
||||
LDAP: &falseValue,
|
||||
LDAPGroups: &falseValue,
|
||||
MFA: &trueValue,
|
||||
GoogleOAuth: &trueValue,
|
||||
Office365OAuth: &trueValue,
|
||||
OpenId: &trueValue,
|
||||
Compliance: &falseValue,
|
||||
Cluster: &falseValue,
|
||||
Metrics: &trueValue,
|
||||
MHPNS: &trueValue,
|
||||
SAML: &trueValue,
|
||||
Elasticsearch: &trueValue,
|
||||
Announcement: &trueValue,
|
||||
ThemeManagement: &trueValue,
|
||||
EmailNotificationContents: &trueValue,
|
||||
DataRetention: &trueValue,
|
||||
MessageExport: &trueValue,
|
||||
CustomPermissionsSchemes: &trueValue,
|
||||
CustomTermsOfService: &trueValue,
|
||||
GuestAccounts: &trueValue,
|
||||
GuestAccountsPermissions: &trueValue,
|
||||
IDLoadedPushNotifications: &trueValue,
|
||||
LockTeammateNameDisplay: &trueValue,
|
||||
EnterprisePlugins: &falseValue,
|
||||
AdvancedLogging: &trueValue,
|
||||
Cloud: &falseValue,
|
||||
SharedChannels: &trueValue,
|
||||
RemoteClusterService: &falseValue,
|
||||
FutureFeatures: &trueValue,
|
||||
},
|
||||
}
|
||||
|
||||
testStore := &TestStore{
|
||||
Store: store,
|
||||
license: license,
|
||||
}
|
||||
|
||||
return testStore
|
||||
}
|
||||
|
||||
func (s *TestStore) GetLicense() *mmModel.License {
|
||||
return s.license
|
||||
}
|
@ -168,6 +168,30 @@ type BoardMember struct {
|
||||
SchemeViewer bool `json:"schemeViewer"`
|
||||
}
|
||||
|
||||
// BoardMetadata contains metadata for a Board
|
||||
// swagger:model
|
||||
type BoardMetadata struct {
|
||||
// The ID for the board
|
||||
// required: true
|
||||
BoardID string `json:"boardId"`
|
||||
|
||||
// The most recent time a descendant of this board was added, modified, or deleted
|
||||
// required: true
|
||||
DescendantLastUpdateAt int64 `json:"descendantLastUpdateAt"`
|
||||
|
||||
// The earliest time a descendant of this board was added, modified, or deleted
|
||||
// required: true
|
||||
DescendantFirstUpdateAt int64 `json:"descendantFirstUpdateAt"`
|
||||
|
||||
// The ID of the user that created the board
|
||||
// required: true
|
||||
CreatedBy string `json:"createdBy"`
|
||||
|
||||
// The ID of the user that last modified the most recently modified descendant
|
||||
// required: true
|
||||
LastModifiedBy string `json:"lastModifiedBy"`
|
||||
}
|
||||
|
||||
func BoardFromJSON(data io.Reader) *Board {
|
||||
var board *Board
|
||||
_ = json.NewDecoder(data).Decode(&board)
|
||||
@ -192,6 +216,12 @@ func BoardMembersFromJSON(data io.Reader) []*BoardMember {
|
||||
return boardMembers
|
||||
}
|
||||
|
||||
func BoardMetadataFromJSON(data io.Reader) *BoardMetadata {
|
||||
var boardMetadata *BoardMetadata
|
||||
_ = json.NewDecoder(data).Decode(&boardMetadata)
|
||||
return boardMetadata
|
||||
}
|
||||
|
||||
// Patch returns an updated version of the board.
|
||||
func (p *BoardPatch) Patch(board *Board) *Board {
|
||||
if p.Type != nil {
|
||||
@ -311,3 +341,23 @@ func (b *Board) IsValid() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BoardMemberHistoryEntry stores the information of the membership of a user on a board
|
||||
// swagger:model
|
||||
type BoardMemberHistoryEntry struct {
|
||||
// The ID of the board
|
||||
// required: true
|
||||
BoardID string `json:"boardId"`
|
||||
|
||||
// The ID of the user
|
||||
// required: true
|
||||
UserID string `json:"userId"`
|
||||
|
||||
// The action that added this history entry (created or deleted)
|
||||
// required: false
|
||||
Action string `json:"action"`
|
||||
|
||||
// The insertion time
|
||||
// required: true
|
||||
InsertAt int64 `json:"insertAt"`
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/mattermost/focalboard/server/model"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
{{range $index, $element := .Methods}}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/mattermost/focalboard/server/services/store"
|
||||
"github.com/mattermost/focalboard/server/utils"
|
||||
|
||||
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
)
|
||||
|
||||
@ -385,3 +386,7 @@ func (s *MattermostAuthLayer) CreatePrivateWorkspace(userID string) (string, err
|
||||
|
||||
return channel.Id, nil
|
||||
}
|
||||
|
||||
func (s *MattermostAuthLayer) GetLicense() *mmModel.License {
|
||||
return s.pluginAPI.GetLicense()
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
model "github.com/mattermost/focalboard/server/model"
|
||||
model0 "github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
// MockStore is a mock of Store interface.
|
||||
@ -383,6 +384,21 @@ func (mr *MockStoreMockRecorder) GetBlockHistory(arg0, arg1 interface{}) *gomock
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockHistory", reflect.TypeOf((*MockStore)(nil).GetBlockHistory), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetBlockHistoryDescendants mocks base method.
|
||||
func (m *MockStore) GetBlockHistoryDescendants(arg0 string, arg1 model.QueryBlockHistoryOptions) ([]model.Block, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBlockHistoryDescendants", arg0, arg1)
|
||||
ret0, _ := ret[0].([]model.Block)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetBlockHistoryDescendants indicates an expected call of GetBlockHistoryDescendants.
|
||||
func (mr *MockStoreMockRecorder) GetBlockHistoryDescendants(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockHistoryDescendants", reflect.TypeOf((*MockStore)(nil).GetBlockHistoryDescendants), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetBlocksForBoard mocks base method.
|
||||
func (m *MockStore) GetBlocksForBoard(arg0 string) ([]model.Block, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -505,6 +521,36 @@ func (mr *MockStoreMockRecorder) GetBoardAndCardByID(arg0 interface{}) *gomock.C
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBoardAndCardByID", reflect.TypeOf((*MockStore)(nil).GetBoardAndCardByID), arg0)
|
||||
}
|
||||
|
||||
// GetBoardHistory mocks base method.
|
||||
func (m *MockStore) GetBoardHistory(arg0 string, arg1 model.QueryBlockHistoryOptions) ([]*model.Board, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBoardHistory", arg0, arg1)
|
||||
ret0, _ := ret[0].([]*model.Board)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetBoardHistory indicates an expected call of GetBoardHistory.
|
||||
func (mr *MockStoreMockRecorder) GetBoardHistory(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBoardHistory", reflect.TypeOf((*MockStore)(nil).GetBoardHistory), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetBoardMemberHistory mocks base method.
|
||||
func (m *MockStore) GetBoardMemberHistory(arg0, arg1 string, arg2 uint64) ([]*model.BoardMemberHistoryEntry, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBoardMemberHistory", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]*model.BoardMemberHistoryEntry)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetBoardMemberHistory indicates an expected call of GetBoardMemberHistory.
|
||||
func (mr *MockStoreMockRecorder) GetBoardMemberHistory(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBoardMemberHistory", reflect.TypeOf((*MockStore)(nil).GetBoardMemberHistory), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// GetBoardsForUserAndTeam mocks base method.
|
||||
func (m *MockStore) GetBoardsForUserAndTeam(arg0, arg1 string) ([]*model.Board, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -535,6 +581,20 @@ func (mr *MockStoreMockRecorder) GetCategory(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCategory", reflect.TypeOf((*MockStore)(nil).GetCategory), arg0)
|
||||
}
|
||||
|
||||
// GetLicense mocks base method.
|
||||
func (m *MockStore) GetLicense() *model0.License {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetLicense")
|
||||
ret0, _ := ret[0].(*model0.License)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetLicense indicates an expected call of GetLicense.
|
||||
func (mr *MockStoreMockRecorder) GetLicense() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLicense", reflect.TypeOf((*MockStore)(nil).GetLicense))
|
||||
}
|
||||
|
||||
// GetMemberForBoard mocks base method.
|
||||
func (m *MockStore) GetMemberForBoard(arg0, arg1 string) (*model.BoardMember, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
|
||||
const (
|
||||
maxSearchDepth = 50
|
||||
descClause = " DESC "
|
||||
)
|
||||
|
||||
type BoardIDNilError struct{}
|
||||
@ -588,6 +589,7 @@ func (s *SQLStore) getBlock(db sq.BaseRunner, blockID string) (*model.Block, err
|
||||
s.logger.Error(`GetBlock ERROR`, mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
defer s.CloseRows(rows)
|
||||
|
||||
blocks, err := s.blocksFromRows(rows)
|
||||
if err != nil {
|
||||
@ -604,7 +606,7 @@ func (s *SQLStore) getBlock(db sq.BaseRunner, blockID string) (*model.Block, err
|
||||
func (s *SQLStore) getBlockHistory(db sq.BaseRunner, blockID string, opts model.QueryBlockHistoryOptions) ([]model.Block, error) {
|
||||
var order string
|
||||
if opts.Descending {
|
||||
order = " DESC "
|
||||
order = descClause
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder(db).
|
||||
@ -630,6 +632,41 @@ func (s *SQLStore) getBlockHistory(db sq.BaseRunner, blockID string, opts model.
|
||||
s.logger.Error(`GetBlockHistory ERROR`, mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
defer s.CloseRows(rows)
|
||||
|
||||
return s.blocksFromRows(rows)
|
||||
}
|
||||
|
||||
func (s *SQLStore) getBlockHistoryDescendants(db sq.BaseRunner, boardID string, opts model.QueryBlockHistoryOptions) ([]model.Block, error) {
|
||||
var order string
|
||||
if opts.Descending {
|
||||
order = descClause
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder(db).
|
||||
Select(s.blockFields()...).
|
||||
From(s.tablePrefix + "blocks_history").
|
||||
Where(sq.Eq{"board_id": boardID}).
|
||||
OrderBy("insert_at " + order + ", update_at" + order)
|
||||
|
||||
if opts.BeforeUpdateAt != 0 {
|
||||
query = query.Where(sq.Lt{"update_at": opts.BeforeUpdateAt})
|
||||
}
|
||||
|
||||
if opts.AfterUpdateAt != 0 {
|
||||
query = query.Where(sq.Gt{"update_at": opts.AfterUpdateAt})
|
||||
}
|
||||
|
||||
if opts.Limit != 0 {
|
||||
query = query.Limit(opts.Limit)
|
||||
}
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
s.logger.Error(`GetBlockHistory ERROR`, mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
defer s.CloseRows(rows)
|
||||
|
||||
return s.blocksFromRows(rows)
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func boardFields(prefix string) []string {
|
||||
"is_template",
|
||||
"template_version",
|
||||
"COALESCE(properties, '{}')",
|
||||
"COALESCE(card_properties, '{}')",
|
||||
"COALESCE(card_properties, '[]')",
|
||||
"COALESCE(column_calculations, '{}')",
|
||||
"create_at",
|
||||
"update_at",
|
||||
@ -60,6 +60,31 @@ func boardFields(prefix string) []string {
|
||||
return prefixedFields
|
||||
}
|
||||
|
||||
func boardHistoryFields() []string {
|
||||
fields := []string{
|
||||
"id",
|
||||
"team_id",
|
||||
"COALESCE(channel_id, '')",
|
||||
"COALESCE(created_by, '')",
|
||||
"COALESCE(modified_by, '')",
|
||||
"type",
|
||||
"COALESCE(title, '')",
|
||||
"COALESCE(description, '')",
|
||||
"COALESCE(icon, '')",
|
||||
"COALESCE(show_description, false)",
|
||||
"COALESCE(is_template, false)",
|
||||
"template_version",
|
||||
"COALESCE(properties, '{}')",
|
||||
"COALESCE(card_properties, '[]')",
|
||||
"COALESCE(column_calculations, '{}')",
|
||||
"COALESCE(create_at, 0)",
|
||||
"COALESCE(update_at, 0)",
|
||||
"COALESCE(delete_at, 0)",
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
var boardMemberFields = []string{
|
||||
"board_id",
|
||||
"user_id",
|
||||
@ -151,6 +176,28 @@ func (s *SQLStore) boardMembersFromRows(rows *sql.Rows) ([]*model.BoardMember, e
|
||||
return boardMembers, nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) boardMemberHistoryEntriesFromRows(rows *sql.Rows) ([]*model.BoardMemberHistoryEntry, error) {
|
||||
boardMemberHistoryEntries := []*model.BoardMemberHistoryEntry{}
|
||||
|
||||
for rows.Next() {
|
||||
var boardMemberHistoryEntry model.BoardMemberHistoryEntry
|
||||
|
||||
err := rows.Scan(
|
||||
&boardMemberHistoryEntry.BoardID,
|
||||
&boardMemberHistoryEntry.UserID,
|
||||
&boardMemberHistoryEntry.Action,
|
||||
&boardMemberHistoryEntry.InsertAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
boardMemberHistoryEntries = append(boardMemberHistoryEntries, &boardMemberHistoryEntry)
|
||||
}
|
||||
|
||||
return boardMemberHistoryEntries, nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) getBoardByCondition(db sq.BaseRunner, conditions ...interface{}) (*model.Board, error) {
|
||||
boards, err := s.getBoardsByCondition(db, conditions...)
|
||||
if err != nil {
|
||||
@ -252,6 +299,8 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
||||
insertQuery := s.getQueryBuilder(db).Insert("").
|
||||
Columns(boardFields("")...)
|
||||
|
||||
now := utils.GetMillis()
|
||||
|
||||
insertQueryValues := map[string]interface{}{
|
||||
"id": board.ID,
|
||||
"team_id": board.TeamID,
|
||||
@ -269,12 +318,10 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
||||
"card_properties": cardPropertiesBytes,
|
||||
"column_calculations": columnCalculationsBytes,
|
||||
"create_at": board.CreateAt,
|
||||
"update_at": board.UpdateAt,
|
||||
"update_at": now,
|
||||
"delete_at": board.DeleteAt,
|
||||
}
|
||||
|
||||
now := utils.GetMillis()
|
||||
|
||||
if existingBoard != nil {
|
||||
query := s.getQueryBuilder(db).Update(s.tablePrefix+"boards").
|
||||
Where(sq.Eq{"id": board.ID}).
|
||||
@ -335,29 +382,49 @@ func (s *SQLStore) deleteBoard(db sq.BaseRunner, boardID, userID string) error {
|
||||
|
||||
board, err := s.getBoard(db, boardID)
|
||||
if err != nil {
|
||||
fmt.Printf("error on get board: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
insertQuery := s.getQueryBuilder(db).Insert(s.tablePrefix+"boards_history").
|
||||
Columns(
|
||||
"team_id",
|
||||
"id",
|
||||
"type",
|
||||
"modified_by",
|
||||
"update_at",
|
||||
"delete_at",
|
||||
).
|
||||
Values(
|
||||
board.TeamID,
|
||||
boardID,
|
||||
board.Type,
|
||||
userID,
|
||||
now,
|
||||
now,
|
||||
)
|
||||
propertiesBytes, err := json.Marshal(board.Properties)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cardPropertiesBytes, err := json.Marshal(board.CardProperties)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
columnCalculationsBytes, err := json.Marshal(board.ColumnCalculations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := insertQuery.Exec(); err != nil {
|
||||
insertQueryValues := map[string]interface{}{
|
||||
"id": board.ID,
|
||||
"team_id": board.TeamID,
|
||||
"channel_id": board.ChannelID,
|
||||
"created_by": board.CreatedBy,
|
||||
"modified_by": userID,
|
||||
"type": board.Type,
|
||||
"title": board.Title,
|
||||
"description": board.Description,
|
||||
"icon": board.Icon,
|
||||
"show_description": board.ShowDescription,
|
||||
"is_template": board.IsTemplate,
|
||||
"template_version": board.TemplateVersion,
|
||||
"properties": propertiesBytes,
|
||||
"card_properties": cardPropertiesBytes,
|
||||
"column_calculations": columnCalculationsBytes,
|
||||
"create_at": board.CreateAt,
|
||||
"update_at": now,
|
||||
"delete_at": now,
|
||||
}
|
||||
|
||||
// writing board history
|
||||
insertQuery := s.getQueryBuilder(db).Insert("").
|
||||
Columns(boardHistoryFields()...)
|
||||
|
||||
query := insertQuery.SetMap(insertQueryValues).Into(s.tablePrefix + "boards_history")
|
||||
if _, err := query.Exec(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -405,6 +472,11 @@ func (s *SQLStore) saveMember(db sq.BaseRunner, bm *model.BoardMember) (*model.B
|
||||
"scheme_viewer": bm.SchemeViewer,
|
||||
}
|
||||
|
||||
oldMember, err := s.getMemberForBoard(db, bm.BoardID, bm.UserID)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder(db).
|
||||
Insert(s.tablePrefix + "board_members").
|
||||
SetMap(queryValues)
|
||||
@ -425,6 +497,17 @@ func (s *SQLStore) saveMember(db sq.BaseRunner, bm *model.BoardMember) (*model.B
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if oldMember == nil {
|
||||
addToMembersHistory := s.getQueryBuilder(db).
|
||||
Insert(s.tablePrefix+"board_members_history").
|
||||
Columns("board_id", "user_id", "action", "insert_at").
|
||||
Values(bm.BoardID, bm.UserID, "created", model.GetMillis())
|
||||
|
||||
if _, err := addToMembersHistory.Exec(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return bm, nil
|
||||
}
|
||||
|
||||
@ -434,10 +517,27 @@ func (s *SQLStore) deleteMember(db sq.BaseRunner, boardID, userID string) error
|
||||
Where(sq.Eq{"board_id": boardID}).
|
||||
Where(sq.Eq{"user_id": userID})
|
||||
|
||||
if _, err := deleteQuery.Exec(); err != nil {
|
||||
result, err := deleteQuery.Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rowsAffected > 0 {
|
||||
addToMembersHistory := s.getQueryBuilder(db).
|
||||
Insert(s.tablePrefix+"board_members_history").
|
||||
Columns("board_id", "user_id", "action", "insert_at").
|
||||
Values(boardID, userID, "deleted", model.GetMillis())
|
||||
|
||||
if _, err := addToMembersHistory.Exec(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -549,3 +649,64 @@ func (s *SQLStore) searchBoardsForUserAndTeam(db sq.BaseRunner, term, userID, te
|
||||
|
||||
return s.boardsFromRows(rows)
|
||||
}
|
||||
|
||||
func (s *SQLStore) getBoardHistory(db sq.BaseRunner, boardID string, opts model.QueryBlockHistoryOptions) ([]*model.Board, error) {
|
||||
var order string
|
||||
if opts.Descending {
|
||||
order = " DESC "
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder(db).
|
||||
Select(boardHistoryFields()...).
|
||||
From(s.tablePrefix + "boards_history").
|
||||
Where(sq.Eq{"id": boardID}).
|
||||
OrderBy("insert_at " + order + ", update_at" + order)
|
||||
|
||||
if opts.BeforeUpdateAt != 0 {
|
||||
query = query.Where(sq.Lt{"update_at": opts.BeforeUpdateAt})
|
||||
}
|
||||
|
||||
if opts.AfterUpdateAt != 0 {
|
||||
query = query.Where(sq.Gt{"update_at": opts.AfterUpdateAt})
|
||||
}
|
||||
|
||||
if opts.Limit != 0 {
|
||||
query = query.Limit(opts.Limit)
|
||||
}
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
s.logger.Error(`getBoardHistory ERROR`, mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
defer s.CloseRows(rows)
|
||||
|
||||
return s.boardsFromRows(rows)
|
||||
}
|
||||
|
||||
func (s *SQLStore) getBoardMemberHistory(db sq.BaseRunner, boardID, userID string, limit uint64) ([]*model.BoardMemberHistoryEntry, error) {
|
||||
query := s.getQueryBuilder(db).
|
||||
Select("board_id", "user_id", "action", "insert_at").
|
||||
From(s.tablePrefix + "board_members_history").
|
||||
Where(sq.Eq{"board_id": boardID}).
|
||||
Where(sq.Eq{"user_id": userID}).
|
||||
OrderBy("insert_at DESC")
|
||||
|
||||
if limit > 0 {
|
||||
query = query.Limit(limit)
|
||||
}
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
s.logger.Error(`getBoardMemberHistory ERROR`, mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
defer s.CloseRows(rows)
|
||||
|
||||
memberHistory, err := s.boardMemberHistoryEntriesFromRows(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return memberHistory, nil
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
DROP TABLE {{.prefix}}board_members_history;
|
@ -0,0 +1,18 @@
|
||||
CREATE TABLE {{.prefix}}board_members_history (
|
||||
{{if .postgres}}id SERIAL PRIMARY KEY,{{end}}
|
||||
{{if .sqlite}}id INTEGER PRIMARY KEY AUTOINCREMENT,{{end}}
|
||||
{{if .mysql}}id INT PRIMARY KEY AUTO_INCREMENT,{{end}}
|
||||
board_id VARCHAR(36) NOT NULL,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
action VARCHAR(10),
|
||||
insert_at BIGINT NOT NULL
|
||||
) {{if .mysql}}DEFAULT CHARACTER SET utf8mb4{{end}};
|
||||
|
||||
CREATE INDEX idx_boardmembershistory_user_id ON {{.prefix}}board_members_history(user_id);
|
||||
CREATE INDEX idx_boardmembershistory_board_id_userid ON {{.prefix}}board_members_history(board_id, user_id);
|
||||
|
||||
INSERT INTO {{.prefix}}board_members_history (board_id, user_id, action, insert_at) SELECT board_id, user_id, 'created',
|
||||
{{if .postgres}}CAST(extract(epoch from now()) * 1000 AS BIGINT){{end}}
|
||||
{{if .sqlite}}strftime('%s')*1000{{end}}
|
||||
{{if .mysql}}UNIX_TIMESTAMP(now())*1000{{end}}
|
||||
from {{.prefix}}board_members;
|
@ -18,6 +18,7 @@ import (
|
||||
|
||||
"github.com/mattermost/focalboard/server/model"
|
||||
|
||||
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
)
|
||||
|
||||
@ -269,6 +270,11 @@ func (s *SQLStore) GetBlockHistory(blockID string, opts model.QueryBlockHistoryO
|
||||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetBlockHistoryDescendants(boardID string, opts model.QueryBlockHistoryOptions) ([]model.Block, error) {
|
||||
return s.getBlockHistoryDescendants(s.db, boardID, opts)
|
||||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetBlocksForBoard(boardID string) ([]model.Block, error) {
|
||||
return s.getBlocksForBoard(s.db, boardID)
|
||||
|
||||
@ -309,6 +315,16 @@ func (s *SQLStore) GetBoardAndCardByID(blockID string) (*model.Board, *model.Blo
|
||||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetBoardHistory(boardID string, opts model.QueryBlockHistoryOptions) ([]*model.Board, error) {
|
||||
return s.getBoardHistory(s.db, boardID, opts)
|
||||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetBoardMemberHistory(boardID string, userID string, limit uint64) ([]*model.BoardMemberHistoryEntry, error) {
|
||||
return s.getBoardMemberHistory(s.db, boardID, userID, limit)
|
||||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetBoardsForUserAndTeam(userID string, teamID string) ([]*model.Board, error) {
|
||||
return s.getBoardsForUserAndTeam(s.db, userID, teamID)
|
||||
|
||||
@ -319,6 +335,11 @@ func (s *SQLStore) GetCategory(id string) (*model.Category, error) {
|
||||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetLicense() *mmModel.License {
|
||||
return s.getLicense(s.db)
|
||||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetMemberForBoard(boardID string, userID string) (*model.BoardMember, error) {
|
||||
return s.getMemberForBoard(s.db, boardID, userID)
|
||||
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/mattermost/focalboard/server/model"
|
||||
"github.com/mattermost/mattermost-plugin-api/cluster"
|
||||
|
||||
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
)
|
||||
|
||||
@ -92,3 +93,7 @@ func (s *SQLStore) escapeField(fieldName string) string { //nolint:unparam
|
||||
}
|
||||
return fieldName
|
||||
}
|
||||
|
||||
func (s *SQLStore) getLicense(db sq.BaseRunner) *mmModel.License {
|
||||
return nil
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/focalboard/server/model"
|
||||
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
// Store represents the abstraction of the data storage.
|
||||
@ -32,6 +33,8 @@ type Store interface {
|
||||
// @withTransaction
|
||||
PatchBlock(blockID string, blockPatch *model.BlockPatch, userID string) error
|
||||
GetBlockHistory(blockID string, opts model.QueryBlockHistoryOptions) ([]model.Block, error)
|
||||
GetBlockHistoryDescendants(boardID string, opts model.QueryBlockHistoryOptions) ([]model.Block, error)
|
||||
GetBoardHistory(boardID string, opts model.QueryBlockHistoryOptions) ([]*model.Board, error)
|
||||
GetBoardAndCardByID(blockID string) (board *model.Board, card *model.Block, err error)
|
||||
GetBoardAndCard(block *model.Block) (board *model.Board, card *model.Block, err error)
|
||||
// @withTransaction
|
||||
@ -90,6 +93,7 @@ type Store interface {
|
||||
SaveMember(bm *model.BoardMember) (*model.BoardMember, error)
|
||||
DeleteMember(boardID, userID string) error
|
||||
GetMemberForBoard(boardID, userID string) (*model.BoardMember, error)
|
||||
GetBoardMemberHistory(boardID, userID string, limit uint64) ([]*model.BoardMemberHistoryEntry, error)
|
||||
GetMembersForBoard(boardID string) ([]*model.BoardMember, error)
|
||||
GetMembersForUser(userID string) ([]*model.BoardMember, error)
|
||||
SearchBoardsForUserAndTeam(term, userID, teamID string) ([]*model.Board, error)
|
||||
@ -130,6 +134,8 @@ type Store interface {
|
||||
DBType() string
|
||||
|
||||
IsErrNotFound(err error) bool
|
||||
|
||||
GetLicense() *mmModel.License
|
||||
}
|
||||
|
||||
// ErrNotFound is an error type that can be returned by store APIs when a query unexpectedly fetches no records.
|
||||
|
@ -75,6 +75,11 @@ func StoreTestBlocksStore(t *testing.T, setup func(t *testing.T) (store.Store, f
|
||||
defer tearDown()
|
||||
testDuplicateBlock(t, store)
|
||||
})
|
||||
t.Run("GetBlockMetadata", func(t *testing.T) {
|
||||
store, tearDown := setup(t)
|
||||
defer tearDown()
|
||||
testGetBlockMetadata(t, store)
|
||||
})
|
||||
}
|
||||
|
||||
func testInsertBlock(t *testing.T, store store.Store) {
|
||||
@ -873,3 +878,188 @@ func testDuplicateBlock(t *testing.T, store store.Store) {
|
||||
require.Nil(t, blocks)
|
||||
})
|
||||
}
|
||||
|
||||
func testGetBlockMetadata(t *testing.T, store store.Store) {
|
||||
boardID := testBoardID
|
||||
blocks, err := store.GetBlocksForBoard(boardID)
|
||||
require.NoError(t, err)
|
||||
|
||||
blocksToInsert := []model.Block{
|
||||
{
|
||||
ID: "block1",
|
||||
BoardID: boardID,
|
||||
ParentID: "",
|
||||
ModifiedBy: testUserID,
|
||||
Type: "test",
|
||||
},
|
||||
{
|
||||
ID: "block2",
|
||||
BoardID: boardID,
|
||||
ParentID: "block1",
|
||||
ModifiedBy: testUserID,
|
||||
Type: "test",
|
||||
},
|
||||
{
|
||||
ID: "block3",
|
||||
BoardID: boardID,
|
||||
ParentID: "block1",
|
||||
ModifiedBy: testUserID,
|
||||
Type: "test",
|
||||
},
|
||||
{
|
||||
ID: "block4",
|
||||
BoardID: boardID,
|
||||
ParentID: "block1",
|
||||
ModifiedBy: testUserID,
|
||||
Type: "test2",
|
||||
},
|
||||
{
|
||||
ID: "block5",
|
||||
BoardID: boardID,
|
||||
ParentID: "block2",
|
||||
ModifiedBy: testUserID,
|
||||
Type: "test",
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range blocksToInsert {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
subBlocks := []model.Block{v}
|
||||
InsertBlocks(t, store, subBlocks, testUserID)
|
||||
}
|
||||
defer DeleteBlocks(t, store, blocksToInsert, "test")
|
||||
|
||||
t.Run("get full block history", func(t *testing.T) {
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Descending: false,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 5)
|
||||
expectedBlock := blocksToInsert[0]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
|
||||
t.Run("get full block history descending", func(t *testing.T) {
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Descending: true,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 5)
|
||||
expectedBlock := blocksToInsert[len(blocksToInsert)-1]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
|
||||
t.Run("get limited block history", func(t *testing.T) {
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Limit: 3,
|
||||
Descending: false,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 3)
|
||||
})
|
||||
|
||||
t.Run("get first block history", func(t *testing.T) {
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Limit: 1,
|
||||
Descending: false,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 1)
|
||||
expectedBlock := blocksToInsert[0]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
|
||||
t.Run("get last block history", func(t *testing.T) {
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Limit: 1,
|
||||
Descending: true,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 1)
|
||||
expectedBlock := blocksToInsert[len(blocksToInsert)-1]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
|
||||
t.Run("get block history after updateAt", func(t *testing.T) {
|
||||
rBlocks, err2 := store.GetBlocksWithType(boardID, "test")
|
||||
require.NoError(t, err2)
|
||||
require.NotZero(t, rBlocks[2].UpdateAt)
|
||||
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
AfterUpdateAt: rBlocks[2].UpdateAt,
|
||||
Descending: false,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 2)
|
||||
expectedBlock := blocksToInsert[3]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
|
||||
t.Run("get block history before updateAt", func(t *testing.T) {
|
||||
rBlocks, err2 := store.GetBlocksWithType(boardID, "test")
|
||||
require.NoError(t, err2)
|
||||
require.NotZero(t, rBlocks[2].UpdateAt)
|
||||
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
BeforeUpdateAt: rBlocks[2].UpdateAt,
|
||||
Descending: true,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 2)
|
||||
expectedBlock := blocksToInsert[1]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
|
||||
t.Run("get full block history after delete", func(t *testing.T) {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
err = store.DeleteBlock(blocksToInsert[0].ID, testUserID)
|
||||
require.NoError(t, err)
|
||||
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Descending: true,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 6)
|
||||
expectedBlock := blocksToInsert[0]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
|
||||
t.Run("get full block history after undelete", func(t *testing.T) {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
err = store.UndeleteBlock(blocksToInsert[0].ID, testUserID)
|
||||
require.NoError(t, err)
|
||||
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Descending: true,
|
||||
}
|
||||
blocks, err = store.GetBlockHistoryDescendants(boardID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, blocks, 7)
|
||||
expectedBlock := blocksToInsert[0]
|
||||
block := blocks[0]
|
||||
|
||||
require.Equal(t, expectedBlock.ID, block.ID)
|
||||
})
|
||||
}
|
||||
|
@ -69,6 +69,11 @@ func StoreTestBoardStore(t *testing.T, setup func(t *testing.T) (store.Store, fu
|
||||
defer tearDown()
|
||||
testSearchBoardsForUserAndTeam(t, store)
|
||||
})
|
||||
t.Run("GetBoardHistory", func(t *testing.T) {
|
||||
store, tearDown := setup(t)
|
||||
defer tearDown()
|
||||
testGetBoardHistory(t, store)
|
||||
})
|
||||
}
|
||||
|
||||
func testGetBoard(t *testing.T, store store.Store) {
|
||||
@ -517,12 +522,20 @@ func testSaveMember(t *testing.T, store store.Store) {
|
||||
SchemeAdmin: true,
|
||||
}
|
||||
|
||||
memberHistory, err := store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
initialMemberHistory := len(memberHistory)
|
||||
|
||||
nbm, err := store.SaveMember(bm)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, userID, nbm.UserID)
|
||||
require.Equal(t, boardID, nbm.BoardID)
|
||||
|
||||
require.True(t, nbm.SchemeAdmin)
|
||||
|
||||
memberHistory, err = store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, memberHistory, initialMemberHistory+1)
|
||||
})
|
||||
|
||||
t.Run("should correctly update a member", func(t *testing.T) {
|
||||
@ -533,6 +546,10 @@ func testSaveMember(t *testing.T, store store.Store) {
|
||||
SchemeViewer: true,
|
||||
}
|
||||
|
||||
memberHistory, err := store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
initialMemberHistory := len(memberHistory)
|
||||
|
||||
nbm, err := store.SaveMember(bm)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, userID, nbm.UserID)
|
||||
@ -541,6 +558,10 @@ func testSaveMember(t *testing.T, store store.Store) {
|
||||
require.False(t, nbm.SchemeAdmin)
|
||||
require.True(t, nbm.SchemeEditor)
|
||||
require.True(t, nbm.SchemeViewer)
|
||||
|
||||
memberHistory, err = store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, memberHistory, initialMemberHistory)
|
||||
})
|
||||
}
|
||||
|
||||
@ -626,7 +647,15 @@ func testDeleteMember(t *testing.T, store store.Store) {
|
||||
boardID := testBoardID
|
||||
|
||||
t.Run("should return nil if deleting a nonexistent member", func(t *testing.T) {
|
||||
memberHistory, err := store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
initialMemberHistory := len(memberHistory)
|
||||
|
||||
require.NoError(t, store.DeleteMember(boardID, userID))
|
||||
|
||||
memberHistory, err = store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, memberHistory, initialMemberHistory)
|
||||
})
|
||||
|
||||
t.Run("should correctly delete a member", func(t *testing.T) {
|
||||
@ -640,11 +669,19 @@ func testDeleteMember(t *testing.T, store store.Store) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, nbm)
|
||||
|
||||
memberHistory, err := store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
initialMemberHistory := len(memberHistory)
|
||||
|
||||
require.NoError(t, store.DeleteMember(boardID, userID))
|
||||
|
||||
rbm, err := store.GetMemberForBoard(boardID, userID)
|
||||
require.ErrorIs(t, err, sql.ErrNoRows)
|
||||
require.Nil(t, rbm)
|
||||
|
||||
memberHistory, err = store.GetBoardMemberHistory(boardID, userID, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, memberHistory, initialMemberHistory+1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -768,3 +805,107 @@ func testSearchBoardsForUserAndTeam(t *testing.T, store store.Store) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testGetBoardHistory(t *testing.T, store store.Store) {
|
||||
userID := testUserID
|
||||
|
||||
t.Run("testGetBoardHistory: create board", func(t *testing.T) {
|
||||
originalTitle := "Board: original title"
|
||||
boardID := utils.NewID(utils.IDTypeBoard)
|
||||
board := &model.Board{
|
||||
ID: boardID,
|
||||
Title: originalTitle,
|
||||
TeamID: testTeamID,
|
||||
Type: model.BoardTypeOpen,
|
||||
}
|
||||
|
||||
rBoard1, err := store.InsertBoard(board, userID)
|
||||
require.NoError(t, err)
|
||||
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Limit: 0,
|
||||
Descending: false,
|
||||
}
|
||||
|
||||
boards, err := store.GetBoardHistory(board.ID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, boards, 1)
|
||||
|
||||
// wait to avoid hitting pk uniqueness constraint in history
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
userID2 := "user-id-2"
|
||||
newTitle := "Board: A new title"
|
||||
newDescription := "A new description"
|
||||
patch := &model.BoardPatch{Title: &newTitle, Description: &newDescription}
|
||||
patchedBoard, err := store.PatchBoard(boardID, patch, userID2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Updated history
|
||||
boards, err = store.GetBoardHistory(board.ID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, boards, 2)
|
||||
require.Equal(t, boards[0].Title, originalTitle)
|
||||
require.Equal(t, boards[1].Title, newTitle)
|
||||
require.Equal(t, boards[1].Description, newDescription)
|
||||
|
||||
// Check history against latest board
|
||||
rBoard2, err := store.GetBoard(board.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, rBoard2.Title, newTitle)
|
||||
require.Equal(t, rBoard2.Title, boards[1].Title)
|
||||
require.NotZero(t, rBoard2.UpdateAt)
|
||||
require.Equal(t, rBoard1.UpdateAt, boards[0].UpdateAt)
|
||||
require.Equal(t, rBoard2.UpdateAt, patchedBoard.UpdateAt)
|
||||
require.Equal(t, rBoard2.UpdateAt, boards[1].UpdateAt)
|
||||
require.Equal(t, rBoard1, boards[0])
|
||||
require.Equal(t, rBoard2, boards[1])
|
||||
|
||||
// wait to avoid hitting pk uniqueness constraint in history
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
newTitle2 := "Board: A new title 2"
|
||||
patch2 := &model.BoardPatch{Title: &newTitle2}
|
||||
patchBoard2, err := store.PatchBoard(boardID, patch2, userID2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Updated history
|
||||
opts = model.QueryBlockHistoryOptions{
|
||||
Limit: 1,
|
||||
Descending: true,
|
||||
}
|
||||
boards, err = store.GetBoardHistory(board.ID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, boards, 1)
|
||||
require.Equal(t, boards[0].Title, newTitle2)
|
||||
require.Equal(t, boards[0], patchBoard2)
|
||||
|
||||
// Delete board
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
err = store.DeleteBoard(boardID, userID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Updated history after delete
|
||||
opts = model.QueryBlockHistoryOptions{
|
||||
Limit: 0,
|
||||
Descending: true,
|
||||
}
|
||||
boards, err = store.GetBoardHistory(board.ID, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, boards, 4)
|
||||
require.NotZero(t, boards[0].UpdateAt)
|
||||
require.Greater(t, boards[0].UpdateAt, patchBoard2.UpdateAt)
|
||||
require.NotZero(t, boards[0].DeleteAt)
|
||||
require.Greater(t, boards[0].DeleteAt, patchBoard2.UpdateAt)
|
||||
})
|
||||
|
||||
t.Run("testGetBoardHistory: nonexisting board", func(t *testing.T) {
|
||||
opts := model.QueryBlockHistoryOptions{
|
||||
Limit: 0,
|
||||
Descending: false,
|
||||
}
|
||||
boards, err := store.GetBoardHistory("nonexistent-id", opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, boards, 0)
|
||||
})
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
5.3.0
|
||||
5.4.0
|
@ -260,6 +260,39 @@ definitions:
|
||||
- schemeViewer
|
||||
type: object
|
||||
x-go-package: github.com/mattermost/focalboard/server/model
|
||||
BoardMetadata:
|
||||
description: BoardMetadata contains metadata for a Board
|
||||
properties:
|
||||
boardId:
|
||||
description: The ID for the board
|
||||
type: string
|
||||
x-go-name: BoardID
|
||||
createdBy:
|
||||
description: The ID of the user that created the board
|
||||
type: string
|
||||
x-go-name: CreatedBy
|
||||
descendantFirstUpdateAt:
|
||||
description: The earliest time a descendant of this board was added, modified, or deleted
|
||||
format: int64
|
||||
type: integer
|
||||
x-go-name: DescendantFirstUpdateAt
|
||||
descendantLastUpdateAt:
|
||||
description: The most recent time a descendant of this board was added, modified, or deleted
|
||||
format: int64
|
||||
type: integer
|
||||
x-go-name: DescendantLastUpdateAt
|
||||
lastModifiedBy:
|
||||
description: The ID of the user that last modified the most recently modified descendant
|
||||
type: string
|
||||
x-go-name: LastModifiedBy
|
||||
required:
|
||||
- boardId
|
||||
- descendantLastUpdateAt
|
||||
- descendantFirstUpdateAt
|
||||
- createdBy
|
||||
- lastModifiedBy
|
||||
type: object
|
||||
x-go-package: github.com/mattermost/focalboard/server/model
|
||||
BoardPatch:
|
||||
description: BoardPatch is a patch for modify boards
|
||||
properties:
|
||||
@ -1300,6 +1333,33 @@ paths:
|
||||
$ref: '#/definitions/ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
/api/v1/boards/{boardID}/metadata:
|
||||
get:
|
||||
description: Returns a board's metadata
|
||||
operationId: getBoardMetadata
|
||||
parameters:
|
||||
- description: Board ID
|
||||
in: path
|
||||
name: boardID
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: success
|
||||
schema:
|
||||
$ref: '#/definitions/BoardMetadata'
|
||||
"404":
|
||||
description: board not found
|
||||
"501":
|
||||
description: required license not found
|
||||
default:
|
||||
description: internal error
|
||||
schema:
|
||||
$ref: '#/definitions/ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
/api/v1/boards/{boardID}/sharing:
|
||||
get:
|
||||
description: Returns sharing information for a board
|
||||
@ -1840,6 +1900,25 @@ paths:
|
||||
$ref: '#/definitions/ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
/api/v1/users/me/memberships:
|
||||
get:
|
||||
description: Returns the currently users board memberships
|
||||
operationId: getMyMemberships
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: success
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/BoardMember'
|
||||
type: array
|
||||
default:
|
||||
description: internal error
|
||||
schema:
|
||||
$ref: '#/definitions/ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
/api/v1/workspaces/{workspaceID}/blocks/{blockID}/undelete:
|
||||
post:
|
||||
description: Undeletes a block
|
||||
@ -1900,6 +1979,33 @@ paths:
|
||||
$ref: '#/definitions/ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
/boards/{boardID}/join:
|
||||
post:
|
||||
description: Become a member of a board
|
||||
operationId: joinBoard
|
||||
parameters:
|
||||
- description: Board ID
|
||||
in: path
|
||||
name: boardID
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: success
|
||||
schema:
|
||||
$ref: '#/definitions/BoardMember'
|
||||
"404":
|
||||
description: board not found
|
||||
"503":
|
||||
description: access denied
|
||||
default:
|
||||
description: internal error
|
||||
schema:
|
||||
$ref: '#/definitions/ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
/boards/{boardID}/members:
|
||||
post:
|
||||
description: Adds a new member to a board
|
||||
|
2
webapp/cypress/global.d.ts
vendored
2
webapp/cypress/global.d.ts
vendored
@ -15,7 +15,7 @@ declare namespace Cypress {
|
||||
apiGetMe: () => Chainable<string>
|
||||
apiChangePassword: (userId: string, oldPassword: string, newPassword: string) => Chainable
|
||||
apiInitServer: () => Chainable
|
||||
apiDeleteBlock: (id: string) => Chainable
|
||||
apiDeleteBoard: (id: string) => Chainable
|
||||
apiResetBoards: () => Chainable
|
||||
apiSkipTour: (userID: string) => Chainable
|
||||
|
||||
|
@ -97,7 +97,7 @@ describe('Card URL Property', () => {
|
||||
const addView = (type: ViewType) => {
|
||||
cy.log(`**Add ${type} view**`)
|
||||
cy.findByRole('button', {name: 'View menu'}).click()
|
||||
cy.findByText('Add view').click()
|
||||
cy.findByText('Add view').realHover()
|
||||
cy.findByRole('button', {name: type}).click()
|
||||
cy.findByRole('textbox', {name: `${type} view`}).should('exist')
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ describe('Create and delete board / card', () => {
|
||||
// Create table view
|
||||
cy.log('**Create table view**')
|
||||
cy.get('.ViewHeader').get('.DropdownIcon').first().parent().click()
|
||||
cy.get('.ViewHeader').contains('Add view').click()
|
||||
cy.get('.ViewHeader').contains('Add view').realHover()
|
||||
cy.get('.ViewHeader').
|
||||
contains('Add view').
|
||||
parent().
|
||||
|
@ -52,32 +52,32 @@ Cypress.Commands.add('apiInitServer', () => {
|
||||
return cy.apiRegisterUser(data, '', false).apiLoginUser(data)
|
||||
})
|
||||
|
||||
Cypress.Commands.add('apiDeleteBlock', (id: string) => {
|
||||
Cypress.Commands.add('apiDeleteBoard', (id: string) => {
|
||||
return cy.request({
|
||||
method: 'DELETE',
|
||||
url: `/api/v1/workspaces/0/blocks/${encodeURIComponent(id)}`,
|
||||
url: `/api/v1/boards/${encodeURIComponent(id)}`,
|
||||
...headers(),
|
||||
})
|
||||
})
|
||||
|
||||
const deleteBlocks = (ids: string[]) => {
|
||||
const deleteBoards = (ids: string[]) => {
|
||||
if (ids.length === 0) {
|
||||
return
|
||||
}
|
||||
const [id, ...other] = ids
|
||||
cy.apiDeleteBlock(id).then(() => deleteBlocks(other))
|
||||
cy.apiDeleteBoard(id).then(() => deleteBoards(other))
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiResetBoards', () => {
|
||||
return cy.request({
|
||||
method: 'GET',
|
||||
url: '/api/v1/workspaces/0/blocks?type=board',
|
||||
url: '/api/v1/teams/0/boards',
|
||||
...headers(),
|
||||
}).then((response) => {
|
||||
if (Array.isArray(response.body)) {
|
||||
const boards = response.body as Board[]
|
||||
const toDelete = boards.filter((b) => !b.isTemplate).map((b) => b.id)
|
||||
deleteBlocks(toDelete)
|
||||
deleteBoards(toDelete)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -24,7 +24,6 @@
|
||||
"ContentBlock.DeleteAction": "حذف",
|
||||
"ContentBlock.addElement": "إضافة {type}",
|
||||
"ContentBlock.text": "نص",
|
||||
"DashboardPage.title": "أهلًا بك إلى Focalboard (تجريبي)!",
|
||||
"EditableDayPicker.today": "اليوم",
|
||||
"Filter.is-empty": "فارغ",
|
||||
"Filter.is-not-empty": "ليس فارغًا",
|
||||
|
@ -45,9 +45,7 @@
|
||||
"KanbanCard.delete": "Eliminar",
|
||||
"KanbanCard.duplicate": "Duplicar",
|
||||
"KanbanCard.untitled": "Sense títol",
|
||||
"Mutator.duplicate-board": "duplicar tauler",
|
||||
"Mutator.new-card-from-template": "nova targeta des de plantilla",
|
||||
"Mutator.new-template-from-board": "nova plantilla des de tauler",
|
||||
"Mutator.new-template-from-card": "nova plantilla des de targeta",
|
||||
"PropertyMenu.Delete": "Eliminar",
|
||||
"PropertyMenu.changeType": "Canviar el tipus de propietat",
|
||||
@ -81,19 +79,15 @@
|
||||
"Sidebar.add-board": "+ Afegir tauler",
|
||||
"Sidebar.changePassword": "Canvi de contrasenya",
|
||||
"Sidebar.delete-board": "Eliminar el tauler",
|
||||
"Sidebar.duplicate-board": "Duplicar el tauler",
|
||||
"Sidebar.export-archive": "Arxiu d'exportació",
|
||||
"Sidebar.import-archive": "Arxiu d'importació",
|
||||
"Sidebar.invite-users": "Convida usuaris",
|
||||
"Sidebar.logout": "Tanca sessió",
|
||||
"Sidebar.no-views-in-board": "Cap pàgina a l'interior",
|
||||
"Sidebar.random-icons": "Icones aleatòries",
|
||||
"Sidebar.set-language": "Seleccionar idioma",
|
||||
"Sidebar.set-theme": "Definir un tema",
|
||||
"Sidebar.settings": "Paràmetres",
|
||||
"Sidebar.template-from-board": "Nova plantilla desde tauler",
|
||||
"Sidebar.untitled-board": "(Tauler sense títol)",
|
||||
"Sidebar.untitled-view": "(Vista sense títol)",
|
||||
"TableComponent.add-icon": "Afegeix icona",
|
||||
"TableComponent.name": "Nom",
|
||||
"TableComponent.plus-new": "+ Nou",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "Keine {property}",
|
||||
"BoardComponent.no-property-title": "Elemente mit einer leeren {property} Eigenschaft erscheinen hier. Diese Spalte kann nicht entfernt werden.",
|
||||
"BoardComponent.show": "Anzeigen",
|
||||
"BoardMember.schemeAdmin": "Administrator",
|
||||
"BoardMember.schemeEditor": "Bearbeiter",
|
||||
"BoardMember.schemeNone": "Keine",
|
||||
"BoardPage.newVersion": "Eine neue Version von Boards ist verfügbar, klicke hier, um neu zu laden.",
|
||||
"BoardPage.syncFailed": "Das Board kann gelöscht oder der Zugang entzogen werden.",
|
||||
"BoardTemplateSelector.add-template": "Neue Vorlage",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "Löschen",
|
||||
"BoardTemplateSelector.description": "Wähle eine Vorlage um zu starten. Passe die Vorlage einfach an deine Anforderungen an oder erstelle ein leeres Board.",
|
||||
"BoardTemplateSelector.edit-template": "Bearbeiten",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Füge ein Board zur Seitenleiste hinzu, indem du eine der Vorlagen unten verwendest oder starte mit einem leeren Board.{lineBreak} Mitglieder von \"{workspaceName}\" werden Zugriff auf die Boards haben, die hier erstellt werden.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Erstelle ein Board in {workspaceName}",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Füge ein Board zur Seitenleiste hinzu, indem du eine der Vorlagen unten verwendest oder starte mit einem leeren Board.{lineBreak} Mitglieder von \"{teamName}\" werden Zugriff auf die Boards haben, die hier erstellt werden.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Erstelle ein Board in {teamName}",
|
||||
"BoardTemplateSelector.title": "Erstelle ein Board",
|
||||
"BoardTemplateSelector.use-this-template": "Verwende diese Vorlage",
|
||||
"BoardsSwitcher.Title": "Finde Boards",
|
||||
"BoardsUnfurl.Remainder": "+{remainder} mehr",
|
||||
"BoardsUnfurl.Updated": "Aktualisiert {time}",
|
||||
"Calculations.Options.average.displayName": "Durchschnitt",
|
||||
@ -81,6 +85,10 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "Karte wirklich löschen!",
|
||||
"CardDialog.editing-template": "Du bearbeitest eine Vorlage.",
|
||||
"CardDialog.nocard": "Diese Karte existiert nicht oder ist nicht verfügbar.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "Abbrechen",
|
||||
"Categories.CreateCategoryDialog.CreateText": "Erstellen",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "Benenne deine Kategorie",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "Aktualisieren",
|
||||
"CenterPanel.Share": "Teilen",
|
||||
"ColorOption.selectColor": "Wähle Farbe {color}",
|
||||
"Comment.delete": "Löschen",
|
||||
@ -101,11 +109,6 @@
|
||||
"ContentBlock.moveDown": "Nach unten bewegen",
|
||||
"ContentBlock.moveUp": "Nach oben bewegen",
|
||||
"ContentBlock.text": "Text",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Verwende den Umschalter zum einfachen Wechseln der Kanäle",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Leider konnten wir keine Kanäle finden, die diesem Begriff entsprechen",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Bitte versuche nach einem anderen Begriff zu suchen",
|
||||
"DashboardPage.showEmpty": "Kanäle ohne Boards anzeigen",
|
||||
"DashboardPage.title": "Dashboard",
|
||||
"DeleteBoardDialog.confirm-cancel": "Abbrechen",
|
||||
"DeleteBoardDialog.confirm-delete": "Löschen",
|
||||
"DeleteBoardDialog.confirm-info": "Bist du sicher, dass du das Board \"{boardTitle}\" löschen möchtest? Wenn du es löschen, werden allen Karten auf diesem Board gelöscht.",
|
||||
@ -121,6 +124,11 @@
|
||||
"Filter.not-includes": "beinhaltet nicht",
|
||||
"FilterComponent.add-filter": "+ Filter hinzufügen",
|
||||
"FilterComponent.delete": "Löschen",
|
||||
"FindBoFindBoardsDialog.IntroText": "Suche nach Boards",
|
||||
"FindBoardsDialog.NoResultsFor": "Keine Ergebnisse für \"{searchQuery}\"",
|
||||
"FindBoardsDialog.NoResultsSubtext": "Prüfe die Schreibweise oder versuche eine weitere Suche.",
|
||||
"FindBoardsDialog.SubTitle": "Tippe um ein Board zu finden. Benutze <b>HOCH/RUNTER</b> zum Browsen. <b>ENTER</b> zur Auswahl, <b>ESC</b> zum Schließen",
|
||||
"FindBoardsDialog.Title": "Finde Boards",
|
||||
"GalleryCard.copiedLink": "Kopiert!",
|
||||
"GalleryCard.copyLink": "Link kopieren",
|
||||
"GalleryCard.delete": "Löschen",
|
||||
@ -134,9 +142,7 @@
|
||||
"KanbanCard.delete": "Löschen",
|
||||
"KanbanCard.duplicate": "Duplizieren",
|
||||
"KanbanCard.untitled": "Unbenannt",
|
||||
"Mutator.duplicate-board": "Board duplizieren",
|
||||
"Mutator.new-card-from-template": "neue Karte aus Vorlage",
|
||||
"Mutator.new-template-from-board": "neue Vorlage aus Board",
|
||||
"Mutator.new-template-from-card": "neue Vorlage aus Karte",
|
||||
"OnboardingTour.AddComments.Body": "Du kannst Themen kommentieren und sogar deine Mattermost-Kollegen @erwähnen, um deren Aufmerksamkeit zu erhalten.",
|
||||
"OnboardingTour.AddComments.Title": "Kommentare hinzufügen",
|
||||
@ -185,26 +191,31 @@
|
||||
"ShareBoard.copiedLink": "Kopiert!",
|
||||
"ShareBoard.copyLink": "Link kopieren",
|
||||
"ShareBoard.regenerate": "Token neu erstellen",
|
||||
"ShareBoard.teamPermissionsText": "Jeder im {teamName} Team",
|
||||
"ShareBoard.tokenRegenrated": "Token neu generiert",
|
||||
"ShareBoard.userPermissionsRemoveMemberText": "Mitglied entfernen",
|
||||
"ShareBoard.userPermissionsYouText": "(Du)",
|
||||
"Sidebar.about": "Über Focalboard",
|
||||
"Sidebar.add-board": "+ Board hinzufügen",
|
||||
"Sidebar.changePassword": "Passwort ändern",
|
||||
"Sidebar.delete-board": "Board löschen",
|
||||
"Sidebar.duplicate-board": "Board duplizieren",
|
||||
"Sidebar.export-archive": "Archiv exportieren",
|
||||
"Sidebar.import": "Importieren",
|
||||
"Sidebar.import-archive": "Archiv importieren",
|
||||
"Sidebar.invite-users": "Nutzer einladen",
|
||||
"Sidebar.logout": "Ausloggen",
|
||||
"Sidebar.no-more-workspaces": "Keine Arbeitsbereiche mehr",
|
||||
"Sidebar.no-views-in-board": "Keine Seiten enthalten",
|
||||
"Sidebar.no-boards-in-category": "Keine Boards vorhanden",
|
||||
"Sidebar.random-icons": "Zufällige Icons",
|
||||
"Sidebar.set-language": "Sprache übernehmen",
|
||||
"Sidebar.set-theme": "Theme übernehmen",
|
||||
"Sidebar.settings": "Einstellungen",
|
||||
"Sidebar.template-from-board": "Neue Vorlage aus Board",
|
||||
"Sidebar.untitled-board": "(Unbenanntes Board)",
|
||||
"Sidebar.untitled-view": "(Unbenannte Ansicht)",
|
||||
"SidebarCategories.BlocksMenu.Move": "Bewege nach...",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "Erstelle neue Kategorie",
|
||||
"SidebarCategories.CategoryMenu.Delete": "Lösche Kategorie",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "Boards in <b>{categoryName}</b> werden zurück zu den Board-Kategorien bewegt. Du wirst von keinen Boards entfernt.",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "Diese Kategorie löschen?",
|
||||
"SidebarCategories.CategoryMenu.Update": "Kategorie umbenennen",
|
||||
"TableComponent.add-icon": "Symbol hinzufügen",
|
||||
"TableComponent.name": "Name",
|
||||
"TableComponent.plus-new": "+ Neu",
|
||||
@ -282,6 +293,7 @@
|
||||
"login.register-button": "oder erstelle einen Account wenn du noch keines hast",
|
||||
"register.login-button": "oder melde dich an, wenn du bereits ein Konto hast",
|
||||
"register.signup-title": "Registriere dich für deinen Account",
|
||||
"shareBoard.lastAdmin": "Boards müssen mindestens eine Administrator haben",
|
||||
"tutorial_tip.finish_tour": "Erledigt",
|
||||
"tutorial_tip.got_it": "Alles klar",
|
||||
"tutorial_tip.ok": "Weiter",
|
||||
|
@ -20,7 +20,6 @@
|
||||
"ContentBlock.moveDown": "Μετακίνηση κάτω",
|
||||
"ContentBlock.moveUp": "Μετακίνηση επάνω",
|
||||
"ContentBlock.text": "κείμενο",
|
||||
"DashboardPage.showEmpty": "Προβολή άδειου",
|
||||
"EditableDayPicker.today": "Σήμερα",
|
||||
"Filter.includes": "περιέχει",
|
||||
"Filter.is-empty": "είναι άδειο",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "No {property}",
|
||||
"BoardComponent.no-property-title": "Items with an empty {property} property will go here. This column cannot be removed.",
|
||||
"BoardComponent.show": "Show",
|
||||
"BoardMember.schemeAdmin": "Admin",
|
||||
"BoardMember.schemeEditor": "Editor",
|
||||
"BoardMember.schemeNone": "None",
|
||||
"BoardPage.newVersion": "A new version of Boards is available, click here to reload.",
|
||||
"BoardPage.syncFailed": "Board may be deleted or access revoked.",
|
||||
"BoardTemplateSelector.add-template": "New template",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "Delete",
|
||||
"BoardTemplateSelector.description": "Choose a template to help you get started. Easily customise the template to fit your needs, or create an empty board to start from scratch.",
|
||||
"BoardTemplateSelector.edit-template": "Edit",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Add a board to the sidebar using any of the templates defined below or start from scratch.{lineBreak} Members of '{workspaceName}' will have access to boards created here.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Create a Board in {workspaceName}",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Add a board to the sidebar using any of the templates defined below or start from scratch.{lineBreak} Members of '\\{teamName}'\\ will have access to boards created here.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Create a Board in {teamName}",
|
||||
"BoardTemplateSelector.title": "Create a Board",
|
||||
"BoardTemplateSelector.use-this-template": "Use this template",
|
||||
"BoardsSwitcher.Title": "Find Boards",
|
||||
"BoardsUnfurl.Remainder": "+{remainder} more",
|
||||
"BoardsUnfurl.Updated": "Updated {time}",
|
||||
"Calculations.Options.average.displayName": "Average",
|
||||
@ -81,6 +85,10 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "Confirm card deletion?",
|
||||
"CardDialog.editing-template": "You're editing a template.",
|
||||
"CardDialog.nocard": "This card doesn't exist or is inaccessible.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "Cancel",
|
||||
"Categories.CreateCategoryDialog.CreateText": "Create",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "Name your category",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "Update",
|
||||
"CenterPanel.Share": "Share",
|
||||
"ColorOption.selectColor": "Select {color} Colour",
|
||||
"Comment.delete": "Delete",
|
||||
@ -101,11 +109,6 @@
|
||||
"ContentBlock.moveDown": "Move down",
|
||||
"ContentBlock.moveUp": "Move up",
|
||||
"ContentBlock.text": "text",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Use the switcher to easily change channels",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "No channels matching that term could be found",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Please try searching for another term",
|
||||
"DashboardPage.showEmpty": "Show empty",
|
||||
"DashboardPage.title": "Dashboard",
|
||||
"DeleteBoardDialog.confirm-cancel": "Cancel",
|
||||
"DeleteBoardDialog.confirm-delete": "Delete",
|
||||
"DeleteBoardDialog.confirm-info": "Are you sure you want to delete the board '{boardTitle}'? This will remove all cards in the board.",
|
||||
@ -121,6 +124,11 @@
|
||||
"Filter.not-includes": "doesn't include",
|
||||
"FilterComponent.add-filter": "+ Add filter",
|
||||
"FilterComponent.delete": "Delete",
|
||||
"FindBoFindBoardsDialog.IntroText": "Search for boards",
|
||||
"FindBoardsDialog.NoResultsFor": "No results for '\\{searchQuery}'\\",
|
||||
"FindBoardsDialog.NoResultsSubtext": "Check the spelling or try another search.",
|
||||
"FindBoardsDialog.SubTitle": "Type to find a board. Use <b>UP/DOWN</b> to browse. <b>ENTER</b> to select, <b>ESC</b> to dismiss",
|
||||
"FindBoardsDialog.Title": "Find Boards",
|
||||
"GalleryCard.copiedLink": "Copied!",
|
||||
"GalleryCard.copyLink": "Copy link",
|
||||
"GalleryCard.delete": "Delete",
|
||||
@ -134,9 +142,7 @@
|
||||
"KanbanCard.delete": "Delete",
|
||||
"KanbanCard.duplicate": "Duplicate",
|
||||
"KanbanCard.untitled": "Untitled",
|
||||
"Mutator.duplicate-board": "duplicate board",
|
||||
"Mutator.new-card-from-template": "new card from template",
|
||||
"Mutator.new-template-from-board": "new template from board",
|
||||
"Mutator.new-template-from-card": "new template from card",
|
||||
"OnboardingTour.AddComments.Body": "You can comment on issues, and even @mention your fellow Mattermost users to get their attention.",
|
||||
"OnboardingTour.AddComments.Title": "Add comments",
|
||||
@ -185,26 +191,31 @@
|
||||
"ShareBoard.copiedLink": "Copied!",
|
||||
"ShareBoard.copyLink": "Copy link",
|
||||
"ShareBoard.regenerate": "Regenerate token",
|
||||
"ShareBoard.teamPermissionsText": "Everyone at {teamName} Team",
|
||||
"ShareBoard.tokenRegenrated": "Token regenerated",
|
||||
"ShareBoard.userPermissionsRemoveMemberText": "Remove member",
|
||||
"ShareBoard.userPermissionsYouText": "(You)",
|
||||
"Sidebar.about": "About Focalboard",
|
||||
"Sidebar.add-board": "+ Add board",
|
||||
"Sidebar.changePassword": "Change password",
|
||||
"Sidebar.delete-board": "Delete board",
|
||||
"Sidebar.duplicate-board": "Duplicate board",
|
||||
"Sidebar.export-archive": "Export archive",
|
||||
"Sidebar.import": "Import",
|
||||
"Sidebar.import-archive": "Import archive",
|
||||
"Sidebar.invite-users": "Invite users",
|
||||
"Sidebar.logout": "Log out",
|
||||
"Sidebar.no-more-workspaces": "No more workspaces",
|
||||
"Sidebar.no-views-in-board": "No pages contained within",
|
||||
"Sidebar.no-boards-in-category": "No boards inside",
|
||||
"Sidebar.random-icons": "Random icons",
|
||||
"Sidebar.set-language": "Set language",
|
||||
"Sidebar.set-theme": "Set theme",
|
||||
"Sidebar.settings": "Settings",
|
||||
"Sidebar.template-from-board": "New template from board",
|
||||
"Sidebar.untitled-board": "(Untitled Board)",
|
||||
"Sidebar.untitled-view": "(Untitled View)",
|
||||
"SidebarCategories.BlocksMenu.Move": "Move To...",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "Create New Category",
|
||||
"SidebarCategories.CategoryMenu.Delete": "Delete Category",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "Boards in <b>{categoryName}</b> will move back to the Boards categories. You're not removed from any boards.",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "Delete this category?",
|
||||
"SidebarCategories.CategoryMenu.Update": "Rename Category",
|
||||
"TableComponent.add-icon": "Add icon",
|
||||
"TableComponent.name": "Name",
|
||||
"TableComponent.plus-new": "+ New",
|
||||
@ -282,6 +293,7 @@
|
||||
"login.register-button": "or create an account if you don't have one",
|
||||
"register.login-button": "or log in if you already have an account",
|
||||
"register.signup-title": "Sign up for your account",
|
||||
"shareBoard.lastAdmin": "Boards must have at least one Administrator",
|
||||
"tutorial_tip.finish_tour": "Done",
|
||||
"tutorial_tip.got_it": "Got it",
|
||||
"tutorial_tip.ok": "Next",
|
||||
|
@ -7,11 +7,34 @@
|
||||
"BoardComponent.no-property": "Sin {property}",
|
||||
"BoardComponent.no-property-title": "Elementos sin la propiedad {property} irán aquí. Esta columna no se puede eliminar.",
|
||||
"BoardComponent.show": "Mostrar",
|
||||
"BoardMember.schemeAdmin": "Administrador",
|
||||
"BoardMember.schemeEditor": "Editor",
|
||||
"BoardMember.schemeNone": "Ninguno",
|
||||
"BoardPage.newVersion": "Una nueva versión de Board está disponible, haz click aquí para recargar.",
|
||||
"BoardPage.syncFailed": "El tablero puede estar eliminado o el acceso fue revocado.",
|
||||
"BoardTemplateSelector.add-template": "Nueva plantilla",
|
||||
"BoardTemplateSelector.create-empty-board": "Crear pizarra vacía",
|
||||
"BoardTemplateSelector.delete-template": "Suprimir",
|
||||
"BoardTemplateSelector.edit-template": "Editar",
|
||||
"BoardTemplateSelector.use-this-template": "Utiliza esta plantilla",
|
||||
"BoardsUnfurl.Updated": "Actualizado {time}",
|
||||
"Calculations.Options.count.displayName": "Cantidad",
|
||||
"Calculations.Options.count.label": "Cantidad",
|
||||
"Calculations.Options.countChecked.displayName": "Marcado",
|
||||
"Calculations.Options.countUnchecked.displayName": "Deseleccionado",
|
||||
"Calculations.Options.countValue.displayName": "Valores",
|
||||
"Calculations.Options.dateRange.displayName": "Rango",
|
||||
"Calculations.Options.dateRange.label": "Rango",
|
||||
"Calculations.Options.max.displayName": "Máx",
|
||||
"Calculations.Options.max.label": "Máx",
|
||||
"Calculations.Options.median.displayName": "Mediana",
|
||||
"Calculations.Options.median.label": "Mediana",
|
||||
"Calculations.Options.min.displayName": "Mín",
|
||||
"Calculations.Options.min.label": "Mín",
|
||||
"Calculations.Options.none.displayName": "Calcular",
|
||||
"Calculations.Options.none.label": "Ninguna",
|
||||
"Calculations.Options.percentChecked.displayName": "Marcado",
|
||||
"Calculations.Options.range.displayName": "Rango",
|
||||
"CardDetail.add-content": "Añadir contenido",
|
||||
"CardDetail.add-icon": "Añadir icono",
|
||||
"CardDetail.add-property": "+ Añadir propiedad",
|
||||
@ -41,11 +64,6 @@
|
||||
"ContentBlock.moveDown": "Mover hacia abajo",
|
||||
"ContentBlock.moveUp": "Mover hacia arriba",
|
||||
"ContentBlock.text": "texto",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Usa el selector para cambiar fácilmente de canal",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Lo sentimos, no pudimos encontrar ningún canal que coincida con ese término",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Por favor, intenta buscar otro término",
|
||||
"DashboardPage.showEmpty": "Mostrar vacío",
|
||||
"DashboardPage.title": "Tablero",
|
||||
"Dialog.closeDialog": "Cerrar diálogo",
|
||||
"EditableDayPicker.today": "Hoy",
|
||||
"Error.websocket-closed": "Conexión de Websocket cerrada, conexión interrumpida. Si esto persiste, verifique la configuración de su servidor o proxy web.",
|
||||
@ -66,9 +84,7 @@
|
||||
"KanbanCard.delete": "Eliminar",
|
||||
"KanbanCard.duplicate": "Duplicar",
|
||||
"KanbanCard.untitled": "Sin título",
|
||||
"Mutator.duplicate-board": "duplicar panel",
|
||||
"Mutator.new-card-from-template": "nueva tarjeta desde una plantilla",
|
||||
"Mutator.new-template-from-board": "nueva plantilla a partir de un panel",
|
||||
"Mutator.new-template-from-card": "nueva plantilla desde una tarjeta",
|
||||
"PropertyMenu.Delete": "Borrar",
|
||||
"PropertyMenu.changeType": "Cambiar el tipo de propiedad",
|
||||
@ -102,20 +118,15 @@
|
||||
"Sidebar.add-board": "+ Añadir panel",
|
||||
"Sidebar.changePassword": "Cambiar contraseña",
|
||||
"Sidebar.delete-board": "Borrar Panel",
|
||||
"Sidebar.duplicate-board": "Duplicar panel",
|
||||
"Sidebar.export-archive": "Exportar Archivo",
|
||||
"Sidebar.import-archive": "Importar Archivo",
|
||||
"Sidebar.invite-users": "Invitar usuarios",
|
||||
"Sidebar.logout": "Cerrar sesión",
|
||||
"Sidebar.no-more-workspaces": "No hay más espacios de trabajo",
|
||||
"Sidebar.no-views-in-board": "No hay páginas dentro",
|
||||
"Sidebar.random-icons": "Íconos random",
|
||||
"Sidebar.set-language": "Establecer idioma",
|
||||
"Sidebar.set-theme": "Establecer apariencia",
|
||||
"Sidebar.settings": "Configuración",
|
||||
"Sidebar.template-from-board": "Nueva plantilla desde un panel",
|
||||
"Sidebar.untitled-board": "(Panel sin titulo)",
|
||||
"Sidebar.untitled-view": "(Vista sin titulo)",
|
||||
"TableComponent.add-icon": "Añadir Icono",
|
||||
"TableComponent.name": "Nombre",
|
||||
"TableComponent.plus-new": "+ Nueva",
|
||||
|
@ -60,8 +60,6 @@
|
||||
"ContentBlock.moveDown": "Liiguta alla",
|
||||
"ContentBlock.moveUp": "Liiguta üles",
|
||||
"ContentBlock.text": "tekst",
|
||||
"DashboardPage.showEmpty": "Näita tühja",
|
||||
"DashboardPage.title": "Töölaud",
|
||||
"DeleteBoardDialog.confirm-cancel": "Loobu",
|
||||
"DeleteBoardDialog.confirm-delete": "Kustuta",
|
||||
"EditableDayPicker.today": "Täna",
|
||||
|
@ -66,10 +66,6 @@
|
||||
"ContentBlock.moveDown": "Déplacer vers le bas",
|
||||
"ContentBlock.moveUp": "Déplacer vers le haut",
|
||||
"ContentBlock.text": "texte",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Utiliser le sélecteur pour changer de canal",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Essayez de rechercher un autre terme",
|
||||
"DashboardPage.showEmpty": "Tout afficher",
|
||||
"DashboardPage.title": "Bienvenue dans Focalboard !",
|
||||
"DeleteBoardDialog.confirm-cancel": "Annuler",
|
||||
"DeleteBoardDialog.confirm-delete": "Supprimer",
|
||||
"DeleteBoardDialog.confirm-info": "Êtes-vous sûr de vouloir supprimer le tableau «{boardTitle}» ? Cela supprimera toutes les cartes dans ce tableau.",
|
||||
@ -96,9 +92,7 @@
|
||||
"KanbanCard.delete": "Supprimer",
|
||||
"KanbanCard.duplicate": "Dupliquer",
|
||||
"KanbanCard.untitled": "Sans titre",
|
||||
"Mutator.duplicate-board": "dupliquer le tableau",
|
||||
"Mutator.new-card-from-template": "nouvelle carte depuis un modèle",
|
||||
"Mutator.new-template-from-board": "nouveau modèle depuis un tableau",
|
||||
"Mutator.new-template-from-card": "nouveau modèle depuis une carte",
|
||||
"OnboardingTour.AddComments.Body": "Vous pouvez commenter les bugs et même @mentionner les utilisateurs de Mattermost pour attirer leur attention.",
|
||||
"OnboardingTour.AddComments.Title": "Ajouter des commentaires",
|
||||
@ -152,21 +146,16 @@
|
||||
"Sidebar.add-board": "+ Ajouter un tableau",
|
||||
"Sidebar.changePassword": "Modifier le mot de passe",
|
||||
"Sidebar.delete-board": "Supprimer le tableau",
|
||||
"Sidebar.duplicate-board": "Dupliquer le tableau",
|
||||
"Sidebar.export-archive": "Exporter une archive",
|
||||
"Sidebar.import": "Importer",
|
||||
"Sidebar.import-archive": "Importer une archive",
|
||||
"Sidebar.invite-users": "Inviter des utilisateurs",
|
||||
"Sidebar.logout": "Se déconnecter",
|
||||
"Sidebar.no-more-workspaces": "Plus d'espace de travail",
|
||||
"Sidebar.no-views-in-board": "Pas de page incluse",
|
||||
"Sidebar.random-icons": "Icônes aléatoires",
|
||||
"Sidebar.set-language": "Choisir la langue",
|
||||
"Sidebar.set-theme": "Choisir le thème",
|
||||
"Sidebar.settings": "Réglages",
|
||||
"Sidebar.template-from-board": "Nouveau modèle depuis le tableau",
|
||||
"Sidebar.untitled-board": "(Tableau sans titre)",
|
||||
"Sidebar.untitled-view": "(Vue sans titre)",
|
||||
"TableComponent.add-icon": "Ajouter une icône",
|
||||
"TableComponent.name": "Nom",
|
||||
"TableComponent.plus-new": "+ Nouveau",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "Bez svojstva {property}",
|
||||
"BoardComponent.no-property-title": "Elementi s praznim svojstvom {property} smjestit će se ovdje. Ovaj se stupac ne može ukloniti.",
|
||||
"BoardComponent.show": "Prikaži",
|
||||
"BoardMember.schemeAdmin": "Administrator",
|
||||
"BoardMember.schemeEditor": "Urednik",
|
||||
"BoardMember.schemeNone": "Ništa",
|
||||
"BoardPage.newVersion": "Dostupna je nova verzija za „Ploče”. Pritisni ovdje za ponovno učitavanje.",
|
||||
"BoardPage.syncFailed": "Ploča se može izbrisati ili pristup opozvati.",
|
||||
"BoardTemplateSelector.add-template": "Novi predložak",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "Izbriši",
|
||||
"BoardTemplateSelector.description": "Za početak odaberi predložak. Prilagodi predložak kako bi odgovarao tvojim potrebama ili stvori praznu ploču.",
|
||||
"BoardTemplateSelector.edit-template": "Uredi",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Dodaj ploču u bočnu traku koristeći bilo koji od niže dolje definiranih predložaka ili počni ispočetka.{lineBreak} „{workspaceName}” članovi imat će pristup ovdje stvorenim pločama.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Stvori ploču u {workspaceName}",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Dodaj ploču u bočnu traku koristeći bilo koji od niže dolje definiranih predložaka ili počni ispočetka.{lineBreak} Članovi tima „{teamName}” imat će pristup ovdje stvorenim pločama.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Stvori ploču u timu {teamName}",
|
||||
"BoardTemplateSelector.title": "Stvori ploču",
|
||||
"BoardTemplateSelector.use-this-template": "Koristi ovaj predložak",
|
||||
"BoardsSwitcher.Title": "Pronađi ploče",
|
||||
"BoardsUnfurl.Remainder": "+ još {remainder}",
|
||||
"BoardsUnfurl.Updated": "Aktulaizirano {time}",
|
||||
"Calculations.Options.average.displayName": "Prosjek",
|
||||
@ -67,20 +71,24 @@
|
||||
"CardDetail.new-comment-placeholder": "Dodaj komentar …",
|
||||
"CardDetailProperty.confirm-delete-heading": "Potvrdi brisanje svojstva",
|
||||
"CardDetailProperty.confirm-delete-subtext": "Stvarno želiš izbrisati svojstvo „{propertyName}”? Brisanjem će se izbrisati svojstvo sa svih kartica na ovoj ploči.",
|
||||
"CardDetailProperty.confirm-property-name-change-subtext": "Stvarno želiš promijeniti svojstvo „{propertyName}” {customText}? To će utjecati na vrijednosti u {numOfcards} kartica na ovoj ploči, a može rezultirati gubitkom podataka.",
|
||||
"CardDetailProperty.confirm-property-name-change-subtext": "Stvarno želiš promijeniti svojstvo „{propertyName}” {customText}? To će utjecati na vrijednosti na {numOfCards} kartica na ovoj ploči i može prouzročiti gubitak podataka.",
|
||||
"CardDetailProperty.confirm-property-type-change": "Potvrdi promjenu vrste svojstva!",
|
||||
"CardDetailProperty.delete-action-button": "Izbriši",
|
||||
"CardDetailProperty.property-change-action-button": "Promijeni svojstvo",
|
||||
"CardDetailProperty.property-changed": "Promjena svojstva uspjela!",
|
||||
"CardDetailProperty.property-deleted": "Svojstvo {propertyName} uspješno izbrisano!",
|
||||
"CardDetailProperty.property-name-change-subtext": "vrsta iz „{oldPropType}” u „{newPropType}”",
|
||||
"CardDetailProperty.property-type-change-subtext": "Ime u „{newPropName}”",
|
||||
"CardDetailProperty.property-name-change-subtext": "vrste „{oldPropType}” u „{newPropType}”",
|
||||
"CardDetailProperty.property-type-change-subtext": "ime u „{newPropName}”",
|
||||
"CardDialog.copiedLink": "Kopirano!",
|
||||
"CardDialog.copyLink": "Kopiraj poveznicu",
|
||||
"CardDialog.delete-confirmation-dialog-button-text": "Izbriši",
|
||||
"CardDialog.delete-confirmation-dialog-heading": "Potvrdi brisanje karte!",
|
||||
"CardDialog.editing-template": "Uređuješ predložak.",
|
||||
"CardDialog.nocard": "Ova kartica ne postoji ili nije dostupna.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "Odustani",
|
||||
"Categories.CreateCategoryDialog.CreateText": "Stvori",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "Zadaj ime kategoriji",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "Aktualiziraj",
|
||||
"CenterPanel.Share": "Dijeli",
|
||||
"ColorOption.selectColor": "Odaberi boju {color}",
|
||||
"Comment.delete": "Izbriši",
|
||||
@ -101,11 +109,6 @@
|
||||
"ContentBlock.moveDown": "Pomakni dolje",
|
||||
"ContentBlock.moveUp": "Pomakni gore",
|
||||
"ContentBlock.text": "tekst",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Koristi prekidač za jednostavno mijenjanja kanala",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Nažalost, nismo mogli pronaći nijedan kanal koji odgovara tom pojmu",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Pokušaj tražiti jedan drugi pojam",
|
||||
"DashboardPage.showEmpty": "Prikaži prazne",
|
||||
"DashboardPage.title": "Pregledna ploča",
|
||||
"DeleteBoardDialog.confirm-cancel": "Odustani",
|
||||
"DeleteBoardDialog.confirm-delete": "Izbriši",
|
||||
"DeleteBoardDialog.confirm-info": "Stvarno želiš izbrisati ploču „{boardTitle}”? Brisanjem će se izbrisati sve karte na ploči.",
|
||||
@ -121,20 +124,25 @@
|
||||
"Filter.not-includes": "ne uključuje",
|
||||
"FilterComponent.add-filter": "+ Dodaj filtar",
|
||||
"FilterComponent.delete": "Izbriši",
|
||||
"FindBoFindBoardsDialog.IntroText": "Traži ploče",
|
||||
"FindBoardsDialog.NoResultsFor": "Nema rezultata za „{searchQuery}”",
|
||||
"FindBoardsDialog.NoResultsSubtext": "Provjeri pravopis ili pretraži s jednim drugim pojmom.",
|
||||
"FindBoardsDialog.SubTitle": "Utipkaj ime za pronalaženje ploče. Koristi <b>GORE/DOLJE</b> za pretraživanje. <b>ENTER</b> za odabiranje, <b>ESC</b> za prekid",
|
||||
"FindBoardsDialog.Title": "Pronađi ploče",
|
||||
"GalleryCard.copiedLink": "Kopirano!",
|
||||
"GalleryCard.copyLink": "Kopiraj poveznicu",
|
||||
"GalleryCard.delete": "Izbriši",
|
||||
"GalleryCard.duplicate": "Dupliciraj",
|
||||
"General.BoardCount": "{count, plural, one {# ploča} few {# ploče} other {# ploča}}",
|
||||
"GroupBy.hideEmptyGroups": "Sakrij {count} prazne grupe",
|
||||
"GroupBy.showHiddenGroups": "Prikaži {count} skrivene grupe",
|
||||
"GroupBy.ungroup": "Razgrupiraj",
|
||||
"KanbanCard.copiedLink": "Kopirano!",
|
||||
"KanbanCard.copyLink": "Kopiraj poveznicu",
|
||||
"KanbanCard.delete": "Izbriši",
|
||||
"KanbanCard.duplicate": "Dupliciraj",
|
||||
"KanbanCard.untitled": "Bez naslova",
|
||||
"Mutator.duplicate-board": "dupliciraj ploču",
|
||||
"Mutator.new-card-from-template": "nova kartica iz predloška",
|
||||
"Mutator.new-template-from-board": "novi predložak iz ploče",
|
||||
"Mutator.new-template-from-card": "novi predložak iz kartice",
|
||||
"OnboardingTour.AddComments.Body": "Probleme možeš komentirati. Možeš čak i @spomenuti svoje Mattermost kolege za privlačenje njihove pozornosti.",
|
||||
"OnboardingTour.AddComments.Title": "Dodaj komentare",
|
||||
@ -183,26 +191,31 @@
|
||||
"ShareBoard.copiedLink": "Kopirano!",
|
||||
"ShareBoard.copyLink": "Kopiraj poveznicu",
|
||||
"ShareBoard.regenerate": "Ponovo generiraj token",
|
||||
"ShareBoard.teamPermissionsText": "Svatko u timu {teamName}",
|
||||
"ShareBoard.tokenRegenrated": "Token je ponovo generiran",
|
||||
"ShareBoard.userPermissionsRemoveMemberText": "Ukloni člana",
|
||||
"ShareBoard.userPermissionsYouText": "(Ti)",
|
||||
"Sidebar.about": "O programu Focalboard",
|
||||
"Sidebar.add-board": "+ Dodaj ploču",
|
||||
"Sidebar.changePassword": "Promijeni lozinku",
|
||||
"Sidebar.delete-board": "Izbriši ploču",
|
||||
"Sidebar.duplicate-board": "Dupliciraj ploču",
|
||||
"Sidebar.export-archive": "Izvezi arhivu",
|
||||
"Sidebar.import": "Uvezi",
|
||||
"Sidebar.import-archive": "Uvezi arhivu",
|
||||
"Sidebar.invite-users": "Pozovi korisnika",
|
||||
"Sidebar.logout": "Odjavi se",
|
||||
"Sidebar.no-more-workspaces": "Nema daljnjih radnih prostora",
|
||||
"Sidebar.no-views-in-board": "Unutra nema stranica",
|
||||
"Sidebar.no-boards-in-category": "Nema ploča u kategoriji",
|
||||
"Sidebar.random-icons": "Slučajne ikone",
|
||||
"Sidebar.set-language": "Postavi jezik",
|
||||
"Sidebar.set-theme": "Postavi temu",
|
||||
"Sidebar.settings": "Postavke",
|
||||
"Sidebar.template-from-board": "Novi predložak iz ploče",
|
||||
"Sidebar.untitled-board": "(Ploča bez naslova)",
|
||||
"Sidebar.untitled-view": "(Prikaz bez naslova)",
|
||||
"SidebarCategories.BlocksMenu.Move": "Premjesti u …",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "Stvori novu kategoriju",
|
||||
"SidebarCategories.CategoryMenu.Delete": "Izbriši kategoriju",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "Ploče u kategoriji <b>{categoryName}</b> vratit će se u kategorije ploča. Nećeš biti uklonjen/a s nijedne ploče.",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "Izbrisati ovu kategoriju?",
|
||||
"SidebarCategories.CategoryMenu.Update": "Preimenuj kategoriju",
|
||||
"TableComponent.add-icon": "Dodaj ikonu",
|
||||
"TableComponent.name": "Ime",
|
||||
"TableComponent.plus-new": "+ Novo",
|
||||
@ -266,6 +279,8 @@
|
||||
"calendar.week": "Tjedan",
|
||||
"default-properties.badges": "Komentari i opis",
|
||||
"default-properties.title": "Naslov",
|
||||
"error.back-to-boards": "Natrag na ploče",
|
||||
"error.back-to-home": "Natrag na početnu stranicu",
|
||||
"error.go-login": "Prijava",
|
||||
"error.not-logged-in": "Tvoja sesija je istekla ili nisi prijavljen/prijavljena.",
|
||||
"error.page.title": "Oprosti, dogodila se greška",
|
||||
@ -278,6 +293,7 @@
|
||||
"login.register-button": "ili stvori račun, ako ga još nemaš",
|
||||
"register.login-button": "ili se prijavi ako već imaš račun",
|
||||
"register.signup-title": "Prijavi se na svoj račun",
|
||||
"shareBoard.lastAdmin": "Ploče moraju imati barem jednog administratora",
|
||||
"tutorial_tip.finish_tour": "Gotovo",
|
||||
"tutorial_tip.got_it": "Razumijem",
|
||||
"tutorial_tip.ok": "Dalje",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "Nincs {property}",
|
||||
"BoardComponent.no-property-title": "Elemek üres {property} tulajdonsággal kerülnek ide. Ez az oszlop nem eltávolítható.",
|
||||
"BoardComponent.show": "Mutat",
|
||||
"BoardMember.schemeAdmin": "Admin",
|
||||
"BoardMember.schemeEditor": "Szerkesztő",
|
||||
"BoardMember.schemeNone": "Nincs",
|
||||
"BoardPage.newVersion": "Elérhető a Táblák egy új verziója, kattintson ide az újratöltéshez.",
|
||||
"BoardPage.syncFailed": "A tábla törölve lett vagy hozzáférés vissza lett vonva.",
|
||||
"BoardTemplateSelector.add-template": "Új sablon",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "Törlés",
|
||||
"BoardTemplateSelector.description": "Válasszon egy sablont, amely segít a kezdésben. Könnyedén testre szabhatja a sablont, hogy megfeleljen az Ön igényeinek, vagy létrehozhat egy üres táblát, hogy a nulláról kezdhesse.",
|
||||
"BoardTemplateSelector.edit-template": "Szerkesztés",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Adjon hozzá egy táblát az oldalsávhoz az alább definiált sablonok bármelyikével, vagy kezdje elölről.{lineBreak} A \"{workspaceName}\" tagjai hozzáférhetnek az itt létrehozott táblákhoz.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Tábla létrehozása a {workspaceName} munkaterületben",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Adjon hozzá egy táblát az oldalsávhoz az alább megadott sablonok bármelyikével, vagy kezdje elölről.{lineBreak} A \"{teamName}\" tagjai hozzáférhetnek az itt létrehozott táblákhoz.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Tábla létrehozása a {teamName} csapathoz",
|
||||
"BoardTemplateSelector.title": "Tábla létrehozása",
|
||||
"BoardTemplateSelector.use-this-template": "Használja ezt a sablont",
|
||||
"BoardsSwitcher.Title": "Táblák keresése",
|
||||
"BoardsUnfurl.Remainder": "+{remainder} további",
|
||||
"BoardsUnfurl.Updated": "Frissítve {time}",
|
||||
"Calculations.Options.average.displayName": "Átlag",
|
||||
@ -81,6 +85,10 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "Hagyja jóvá a kártya törlését!",
|
||||
"CardDialog.editing-template": "Ön egy sablont szerkeszt.",
|
||||
"CardDialog.nocard": "Ez a kártya nem létezik vagy elérhetetlen.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "Mégsem",
|
||||
"Categories.CreateCategoryDialog.CreateText": "Létrehozás",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "Nevezze el a kategóriáját",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "Frissítés",
|
||||
"CenterPanel.Share": "Megosztás",
|
||||
"ColorOption.selectColor": "{color} szín kiválasztása",
|
||||
"Comment.delete": "Törlés",
|
||||
@ -101,11 +109,6 @@
|
||||
"ContentBlock.moveDown": "Mozgatás le",
|
||||
"ContentBlock.moveUp": "Mozgatás fel",
|
||||
"ContentBlock.text": "szöveg",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Használja a váltót a beszélgetések könnyű váltásához",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Sajnáljuk, de nem találtunk egy beszélgetést sem ami ennek a kifejezésnek megfelelne",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Kérjük próbáljon keresni egy másik kifejezésre",
|
||||
"DashboardPage.showEmpty": "Mutassa az üreseket",
|
||||
"DashboardPage.title": "Vezérlőpult",
|
||||
"DeleteBoardDialog.confirm-cancel": "Mégsem",
|
||||
"DeleteBoardDialog.confirm-delete": "Törlés",
|
||||
"DeleteBoardDialog.confirm-info": "Biztos benne, hogy törölni szeretné a “{boardTitle}” táblát? A törlésével az összes benne lévő kártya is törlődni fog.",
|
||||
@ -121,6 +124,11 @@
|
||||
"Filter.not-includes": "nem tartalmazza",
|
||||
"FilterComponent.add-filter": "+ Szűrő hozzáadása",
|
||||
"FilterComponent.delete": "Törlés",
|
||||
"FindBoFindBoardsDialog.IntroText": "Táblák keresése",
|
||||
"FindBoardsDialog.NoResultsFor": "Nincs találat a \"{searchQuery}\" kereséshez",
|
||||
"FindBoardsDialog.NoResultsSubtext": "Ellenőrizze az elgépelést vagy próbáljon egy új keresést.",
|
||||
"FindBoardsDialog.SubTitle": "Gépeljen, hogy megtalálja a táblát. Használja a <b>FEL/LE</b> gombokat a böngészéshez. <b>ENTER</b> gombot a kiválasztáshoz és <b>ESC</b> gombot az eldobáshoz",
|
||||
"FindBoardsDialog.Title": "Táblák keresése",
|
||||
"GalleryCard.copiedLink": "Másolva!",
|
||||
"GalleryCard.copyLink": "Link másolása",
|
||||
"GalleryCard.delete": "Törlés",
|
||||
@ -134,9 +142,7 @@
|
||||
"KanbanCard.delete": "Törlés",
|
||||
"KanbanCard.duplicate": "Duplikálás",
|
||||
"KanbanCard.untitled": "Névtelen",
|
||||
"Mutator.duplicate-board": "tábla duplikálása",
|
||||
"Mutator.new-card-from-template": "új kártya sablonból",
|
||||
"Mutator.new-template-from-board": "új sablon táblából",
|
||||
"Mutator.new-template-from-card": "új sablon kártyából",
|
||||
"OnboardingTour.AddComments.Body": "Hozzászólhat a témákhoz, sőt, más Mattermost felhasználó társát is @megemlítheti, hogy felhívja a figyelmüket.",
|
||||
"OnboardingTour.AddComments.Title": "Megjegyzés hozzáadása",
|
||||
@ -185,26 +191,31 @@
|
||||
"ShareBoard.copiedLink": "Másolt!",
|
||||
"ShareBoard.copyLink": "Link másolása",
|
||||
"ShareBoard.regenerate": "Token újragenerálása",
|
||||
"ShareBoard.teamPermissionsText": "Mindenki a {teamName} Csapatban",
|
||||
"ShareBoard.tokenRegenrated": "Token újragenerálva",
|
||||
"ShareBoard.userPermissionsRemoveMemberText": "Tag eltávolítása",
|
||||
"ShareBoard.userPermissionsYouText": "(Ön)",
|
||||
"Sidebar.about": "Focalboard névjegye",
|
||||
"Sidebar.add-board": "+ Tábla hozzáadása",
|
||||
"Sidebar.changePassword": "Jelszó módosítása",
|
||||
"Sidebar.delete-board": "Tábla törlése",
|
||||
"Sidebar.duplicate-board": "Tábla duplikálása",
|
||||
"Sidebar.export-archive": "Archiváltak exportálása",
|
||||
"Sidebar.import": "Importálás",
|
||||
"Sidebar.import-archive": "Archiváltak importálása",
|
||||
"Sidebar.invite-users": "Felhasználók meghívása",
|
||||
"Sidebar.logout": "Kijelentkezés",
|
||||
"Sidebar.no-more-workspaces": "Nincs több munkaterület",
|
||||
"Sidebar.no-views-in-board": "Nincsennek benne lapok",
|
||||
"Sidebar.no-boards-in-category": "Nincsennek bent táblák",
|
||||
"Sidebar.random-icons": "Véletlen ikonok",
|
||||
"Sidebar.set-language": "Nyelv megadása",
|
||||
"Sidebar.set-theme": "Téma megadása",
|
||||
"Sidebar.settings": "Beállítások",
|
||||
"Sidebar.template-from-board": "Új sablon táblából",
|
||||
"Sidebar.untitled-board": "(Névtelen tábla)",
|
||||
"Sidebar.untitled-view": "(Névtelen nézet)",
|
||||
"SidebarCategories.BlocksMenu.Move": "Áthelyezés...",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "Új kategória létrehozása",
|
||||
"SidebarCategories.CategoryMenu.Delete": "Kategória törlése",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "A <b>{categoryName}</b> kategóriában lévő táblák visszakerülnek a Táblák kategóriákba. Ön egyik táblából sem lesz eltávolítva.",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "Törli ezt a kategóriát?",
|
||||
"SidebarCategories.CategoryMenu.Update": "Kategória átnevezése",
|
||||
"TableComponent.add-icon": "Ikon hozzáadása",
|
||||
"TableComponent.name": "Név",
|
||||
"TableComponent.plus-new": "+ Új",
|
||||
@ -268,6 +279,8 @@
|
||||
"calendar.week": "Hét",
|
||||
"default-properties.badges": "Megjegyzések és leírás",
|
||||
"default-properties.title": "Cím",
|
||||
"error.back-to-boards": "Vissza a táblákba",
|
||||
"error.back-to-home": "Vissza a kezdőlapra",
|
||||
"error.go-login": "Bejelentkezés",
|
||||
"error.not-logged-in": "Lehet, hogy lejárt a munkamenete, vagy nincs bejelentkezve.",
|
||||
"error.page.title": "Sajnálom, valami rosszul sikerült",
|
||||
@ -280,6 +293,7 @@
|
||||
"login.register-button": "vagy hozzon létre egy fiókot ha még nincs",
|
||||
"register.login-button": "vagy jelentkezzen be ha már van fiókja",
|
||||
"register.signup-title": "Regisztráljon fiókjáért",
|
||||
"shareBoard.lastAdmin": "A tábláknak legalább egy Adminisztárorral kell rendelkezniük",
|
||||
"tutorial_tip.finish_tour": "Kész",
|
||||
"tutorial_tip.got_it": "Értettem",
|
||||
"tutorial_tip.ok": "Következő",
|
||||
|
@ -44,11 +44,6 @@
|
||||
"ContentBlock.moveDown": "Turunkan",
|
||||
"ContentBlock.moveUp": "Naikkan",
|
||||
"ContentBlock.text": "teks",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Gunakan tombol saklar untuk berpindah kanal dengan mudah",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Maaf, kami tidak dapat menemukan kanal yang sesuai dengan kata tersebut",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Mohon lalukan pencarian untuk kata yang lain",
|
||||
"DashboardPage.showEmpty": "Tampilan kosong",
|
||||
"DashboardPage.title": "Dasbor",
|
||||
"Dialog.closeDialog": "Tutup dialog",
|
||||
"EditableDayPicker.today": "Hari Ini",
|
||||
"Error.websocket-closed": "Koneksi ke soket web tertutup, koneksi terganggu. Jika hal ini terus berlanjut, periksa konfigurasi server atau proxy web Anda.",
|
||||
@ -69,9 +64,7 @@
|
||||
"KanbanCard.delete": "Hapus",
|
||||
"KanbanCard.duplicate": "Duplikasikan",
|
||||
"KanbanCard.untitled": "Tidak berjudul",
|
||||
"Mutator.duplicate-board": "duplikasikan papan",
|
||||
"Mutator.new-card-from-template": "kartu baru dari template",
|
||||
"Mutator.new-template-from-board": "template baru dari papan",
|
||||
"Mutator.new-template-from-card": "template baru dari kartu",
|
||||
"PropertyMenu.Delete": "Hapus",
|
||||
"PropertyMenu.changeType": "Ubah jenis properti",
|
||||
@ -105,20 +98,15 @@
|
||||
"Sidebar.add-board": "+ Tambahkan papan",
|
||||
"Sidebar.changePassword": "Ubah kata sandi",
|
||||
"Sidebar.delete-board": "Hapus papan",
|
||||
"Sidebar.duplicate-board": "Duplikasikan papan",
|
||||
"Sidebar.export-archive": "Ekpor arsip",
|
||||
"Sidebar.import-archive": "Impor arsip",
|
||||
"Sidebar.invite-users": "Undang pengguna",
|
||||
"Sidebar.logout": "Keluar",
|
||||
"Sidebar.no-more-workspaces": "Tidak ada ruang kerja",
|
||||
"Sidebar.no-views-in-board": "Tidak ada halaman di dalam",
|
||||
"Sidebar.random-icons": "Ikon acak",
|
||||
"Sidebar.set-language": "Tetapkan bahasa",
|
||||
"Sidebar.set-theme": "Tetapkan tema",
|
||||
"Sidebar.settings": "Pengaturan",
|
||||
"Sidebar.template-from-board": "Template baru dari papan",
|
||||
"Sidebar.untitled-board": "(Papan Tak Berjudul)",
|
||||
"Sidebar.untitled-view": "(Tampilan Tak Berjudul)",
|
||||
"TableComponent.add-icon": "Tambahkan ikon",
|
||||
"TableComponent.name": "Nama",
|
||||
"TableComponent.plus-new": "+ Buat",
|
||||
|
@ -101,11 +101,6 @@
|
||||
"ContentBlock.moveDown": "Sposta giù",
|
||||
"ContentBlock.moveUp": "Sposta su",
|
||||
"ContentBlock.text": "testo",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Usa lo switch per cambiare facilmente canali",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Spiacente, non siamo riusciti a trovare nessuno canale corrispondente a quel termine",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Per favore prova a cercare un altro termine",
|
||||
"DashboardPage.showEmpty": "Mostra vuoto",
|
||||
"DashboardPage.title": "Dashboard",
|
||||
"DeleteBoardDialog.confirm-cancel": "Annulla",
|
||||
"DeleteBoardDialog.confirm-delete": "Elimina",
|
||||
"DeleteBoardDialog.confirm-info": "Sei sicuro di voler eliminare la bacheca \"{boardTitle}\"? Eliminandola, rimuoverai tutte le schede in bacheca.",
|
||||
@ -132,9 +127,7 @@
|
||||
"KanbanCard.delete": "Elimina",
|
||||
"KanbanCard.duplicate": "Duplica",
|
||||
"KanbanCard.untitled": "Senza titolo",
|
||||
"Mutator.duplicate-board": "duplica contenitore",
|
||||
"Mutator.new-card-from-template": "nuova scheda da modello",
|
||||
"Mutator.new-template-from-board": "nuovo modello da contenitore",
|
||||
"Mutator.new-template-from-card": "nuovo modello da scheda",
|
||||
"PropertyMenu.Delete": "Elimina",
|
||||
"PropertyMenu.changeType": "Cambia il tipo di proprietà",
|
||||
@ -174,20 +167,15 @@
|
||||
"Sidebar.add-board": "+ Aggiungi Contenitore",
|
||||
"Sidebar.changePassword": "Cambia password",
|
||||
"Sidebar.delete-board": "Elimina contenitore",
|
||||
"Sidebar.duplicate-board": "Duplica contenitore",
|
||||
"Sidebar.export-archive": "Esporta archivio",
|
||||
"Sidebar.import-archive": "Importa archivio",
|
||||
"Sidebar.invite-users": "Invita utenti",
|
||||
"Sidebar.logout": "Logout",
|
||||
"Sidebar.no-more-workspaces": "Non ci sono spazi di lavoro",
|
||||
"Sidebar.no-views-in-board": "Nessuna pagina all'interno",
|
||||
"Sidebar.random-icons": "Icone casuali",
|
||||
"Sidebar.set-language": "Imposta la lingua",
|
||||
"Sidebar.set-theme": "Imposta il tema",
|
||||
"Sidebar.settings": "Impostazioni",
|
||||
"Sidebar.template-from-board": "Nuovo modello da contenitore",
|
||||
"Sidebar.untitled-board": "(Contenitore senza titolo)",
|
||||
"Sidebar.untitled-view": "(Vista senza titolo)",
|
||||
"TableComponent.add-icon": "Aggiungi icona",
|
||||
"TableComponent.name": "Nome",
|
||||
"TableComponent.plus-new": "+ Nuovo",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "{property} 無し",
|
||||
"BoardComponent.no-property-title": "{property}が空のアイテムがここに表示されます。このカラムは削除できません。",
|
||||
"BoardComponent.show": "表示",
|
||||
"BoardMember.schemeAdmin": "管理者",
|
||||
"BoardMember.schemeEditor": "編集者",
|
||||
"BoardMember.schemeNone": "なし",
|
||||
"BoardPage.newVersion": "ボードの新しいバージョンが利用可能です。ここをクリックして再読み込みしてください。",
|
||||
"BoardPage.syncFailed": "ボードが削除されたか、アクセスが取り消されました。",
|
||||
"BoardTemplateSelector.add-template": "新しいテンプレート",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "削除する",
|
||||
"BoardTemplateSelector.description": "手軽に始めるにはテンプレートを選択します。ニーズに合わせてテンプレートを簡単にカスタマイズしたり、空のボードを作成してゼロから始めることもできます。",
|
||||
"BoardTemplateSelector.edit-template": "編集",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "サイドバーにボードを追加するには、以下のテンプレートを利用するか、空の状態から作成します。{lineBreak} \"{workspaceName}\"のメンバーは、作成されたボードにアクセスできます。",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "{workspaceName} にボードを作成する",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "サイドバーにボードを追加するには、以下のテンプレートを利用するか、空の状態から作成します。{lineBreak} \"{teamName}\"のメンバーは、作成されたボードにアクセスできます。",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "{teamName} にボードを作成する",
|
||||
"BoardTemplateSelector.title": "ボードを作成する",
|
||||
"BoardTemplateSelector.use-this-template": "このテンプレートを使う",
|
||||
"BoardsSwitcher.Title": "ボードを探す",
|
||||
"BoardsUnfurl.Remainder": "残り +{remainder}",
|
||||
"BoardsUnfurl.Updated": "更新日時 {time}",
|
||||
"Calculations.Options.average.displayName": "平均",
|
||||
@ -73,7 +77,7 @@
|
||||
"CardDetailProperty.property-change-action-button": "プロパティの変更",
|
||||
"CardDetailProperty.property-changed": "プロパティが変更されました!",
|
||||
"CardDetailProperty.property-deleted": "{propertyName} が正常に削除されました!",
|
||||
"CardDetailProperty.property-name-change-subtext": "種別を \"{oldPropType}\" から\"{newProptype}\" に",
|
||||
"CardDetailProperty.property-name-change-subtext": "種別を \"{oldPropType}\" から\"{newPropType}\" に",
|
||||
"CardDetailProperty.property-type-change-subtext": "名前を \"{newPropName}\" に",
|
||||
"CardDialog.copiedLink": "コピーしました!",
|
||||
"CardDialog.copyLink": "リンクをコピー",
|
||||
@ -81,6 +85,10 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "カード削除の確認",
|
||||
"CardDialog.editing-template": "テンプレートを編集しています。",
|
||||
"CardDialog.nocard": "このカードは存在しないか、アクセスできません。",
|
||||
"Categories.CreateCategoryDialog.CancelText": "キャンセル",
|
||||
"Categories.CreateCategoryDialog.CreateText": "作成",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "カテゴリ名を入力してください",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "更新",
|
||||
"CenterPanel.Share": "共有",
|
||||
"ColorOption.selectColor": "{color} 色を選択",
|
||||
"Comment.delete": "削除",
|
||||
@ -101,11 +109,6 @@
|
||||
"ContentBlock.moveDown": "下へ移動する",
|
||||
"ContentBlock.moveUp": "上へ移動する",
|
||||
"ContentBlock.text": "テキスト",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "スイッチャーで簡単にチャンネルを変更できます",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "その言葉に一致するチャンネルは見つかりませんでした",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "別の言葉で検索してみてください",
|
||||
"DashboardPage.showEmpty": "空のボードを表示",
|
||||
"DashboardPage.title": "ダッシュボード",
|
||||
"DeleteBoardDialog.confirm-cancel": "キャンセル",
|
||||
"DeleteBoardDialog.confirm-delete": "削除",
|
||||
"DeleteBoardDialog.confirm-info": "本当にボード \"{boardTitle}\" を削除しますか? 削除すると、このボードのすべてのカードが削除されます。",
|
||||
@ -121,6 +124,11 @@
|
||||
"Filter.not-includes": "を含まない",
|
||||
"FilterComponent.add-filter": "+ フィルターを追加する",
|
||||
"FilterComponent.delete": "削除",
|
||||
"FindBoFindBoardsDialog.IntroText": "ボードを検索する",
|
||||
"FindBoardsDialog.NoResultsFor": "\"{searchQuery}\"に対する結果はありません",
|
||||
"FindBoardsDialog.NoResultsSubtext": "スペルを確認し、再度検索してください。",
|
||||
"FindBoardsDialog.SubTitle": "ボードを検索するために文字を入力してください。<b>UP/DOWN</b>で閲覧、<b>ENTER</b>で選択、<b>ESC</b>でキャンセル",
|
||||
"FindBoardsDialog.Title": "ボードを探す",
|
||||
"GalleryCard.copiedLink": "コピーしました!",
|
||||
"GalleryCard.copyLink": "リンクをコピー",
|
||||
"GalleryCard.delete": "削除",
|
||||
@ -134,9 +142,7 @@
|
||||
"KanbanCard.delete": "削除",
|
||||
"KanbanCard.duplicate": "複製",
|
||||
"KanbanCard.untitled": "無題",
|
||||
"Mutator.duplicate-board": "ボードを複製する",
|
||||
"Mutator.new-card-from-template": "テンプレートから新しいカードを作成",
|
||||
"Mutator.new-template-from-board": "ボードから新しいテンプレートを作成",
|
||||
"Mutator.new-template-from-card": "カードから新しいテンプレートを作成",
|
||||
"OnboardingTour.AddComments.Body": "問題にコメントしたり、仲間のMattermostユーザーの注意を引くために@メンションすることもできます。",
|
||||
"OnboardingTour.AddComments.Title": "コメントを追加する",
|
||||
@ -185,26 +191,31 @@
|
||||
"ShareBoard.copiedLink": "コピーしました!",
|
||||
"ShareBoard.copyLink": "リンクをコピーする",
|
||||
"ShareBoard.regenerate": "トークンを再生成する",
|
||||
"ShareBoard.teamPermissionsText": "{teamName}チームの全員",
|
||||
"ShareBoard.tokenRegenrated": "トークンが再生成されました",
|
||||
"ShareBoard.userPermissionsRemoveMemberText": "メンバーを削除する",
|
||||
"ShareBoard.userPermissionsYouText": "(あなた)",
|
||||
"Sidebar.about": "Focalboardについて",
|
||||
"Sidebar.add-board": "+ ボードを追加する",
|
||||
"Sidebar.changePassword": "パスワードを変更する",
|
||||
"Sidebar.delete-board": "ボードを削除",
|
||||
"Sidebar.duplicate-board": "ボードを複製する",
|
||||
"Sidebar.export-archive": "エクスポート",
|
||||
"Sidebar.import": "インポート",
|
||||
"Sidebar.import-archive": "インポート",
|
||||
"Sidebar.invite-users": "ユーザーを招待する",
|
||||
"Sidebar.logout": "ログアウト",
|
||||
"Sidebar.no-more-workspaces": "他のワークスペースがありません",
|
||||
"Sidebar.no-views-in-board": "ページがありません",
|
||||
"Sidebar.no-boards-in-category": "カテゴリ内にボードがありません",
|
||||
"Sidebar.random-icons": "ランダムアイコン",
|
||||
"Sidebar.set-language": "言語設定",
|
||||
"Sidebar.set-theme": "テーマ設定",
|
||||
"Sidebar.settings": "設定",
|
||||
"Sidebar.template-from-board": "ボードから新しいテンプレートを作成",
|
||||
"Sidebar.untitled-board": "(無題のボード)",
|
||||
"Sidebar.untitled-view": "(無題のビュー)",
|
||||
"SidebarCategories.BlocksMenu.Move": "移動...",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "新しいカテゴリを作成する",
|
||||
"SidebarCategories.CategoryMenu.Delete": "カテゴリを削除する",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "<b>{categoryName}</b> にあるボードは、Boards カテゴリに戻されます。どのボードからも削除されることはありません。",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "このカテゴリを削除しますか?",
|
||||
"SidebarCategories.CategoryMenu.Update": "カテゴリ名を変更する",
|
||||
"TableComponent.add-icon": "アイコンを追加する",
|
||||
"TableComponent.name": "名前",
|
||||
"TableComponent.plus-new": "+ 新規",
|
||||
@ -282,6 +293,7 @@
|
||||
"login.register-button": "アカウントをお持ちでない方はアカウントを作成してください",
|
||||
"register.login-button": "または、すでにアカウントをお持ちの方はログインしてください",
|
||||
"register.signup-title": "アカウント登録",
|
||||
"shareBoard.lastAdmin": "ボードには少なくとも1名の管理者が必要です",
|
||||
"tutorial_tip.finish_tour": "完了",
|
||||
"tutorial_tip.got_it": "了解",
|
||||
"tutorial_tip.ok": "次へ",
|
||||
|
@ -86,11 +86,6 @@
|
||||
"ContentBlock.moveDown": "Түсіру",
|
||||
"ContentBlock.moveUp": "Көтеру",
|
||||
"ContentBlock.text": "мәтін",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Арналарды оңай өзгерту үшін ауыстырғышты қолданыныз",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Кешіріңіз, біз бұл термінге сәйкес ешбір арнаны таба алмадық",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Басқа термінді іздеп көрініз",
|
||||
"DashboardPage.showEmpty": "Босты көрсету",
|
||||
"DashboardPage.title": "Дашборт",
|
||||
"DeleteBoardDialog.confirm-cancel": "Болдырмау",
|
||||
"DeleteBoardDialog.confirm-delete": "Жою",
|
||||
"DeleteBoardDialog.confirm-info": "\"{boardTitle}\" тақтасын шынымен жойғыңыз келе ме? Оны жою тақтадағы барлық кәртелерді жояды.",
|
||||
@ -116,9 +111,7 @@
|
||||
"KanbanCard.delete": "Жою",
|
||||
"KanbanCard.duplicate": "Көшірмесін жасау",
|
||||
"KanbanCard.untitled": "Атаусыз",
|
||||
"Mutator.duplicate-board": "тақта көшірмесін жасау",
|
||||
"Mutator.new-card-from-template": "үлгіден жаңа кәрте жасау",
|
||||
"Mutator.new-template-from-board": "тақтадан жаңа үлгі",
|
||||
"Mutator.new-template-from-card": "кәртеден жаңа үлгі",
|
||||
"PropertyMenu.Delete": "Жою",
|
||||
"PropertyMenu.changeType": "Property түрін өзгерту",
|
||||
@ -154,20 +147,15 @@
|
||||
"Sidebar.add-board": "+ Тақта қосу",
|
||||
"Sidebar.changePassword": "Кілтсөзді өзгерту",
|
||||
"Sidebar.delete-board": "Тақтаны жою",
|
||||
"Sidebar.duplicate-board": "Тақтанын көшірмесін жасау",
|
||||
"Sidebar.export-archive": "Мұрағатты экспорттау",
|
||||
"Sidebar.import-archive": "Мұрағатты импорттау",
|
||||
"Sidebar.invite-users": "Қолданушыларды шақыру",
|
||||
"Sidebar.logout": "Шығу",
|
||||
"Sidebar.no-more-workspaces": "Басқа workspace жоқ",
|
||||
"Sidebar.no-views-in-board": "Ішінде беттер жоқ",
|
||||
"Sidebar.random-icons": "Рандом икондар",
|
||||
"Sidebar.set-language": "Тілді таңдау",
|
||||
"Sidebar.set-theme": "Теміні орнату",
|
||||
"Sidebar.settings": "Баптаулар",
|
||||
"Sidebar.template-from-board": "Тақтадан жаңа үлгі жасау",
|
||||
"Sidebar.untitled-board": "(Атаусыз Тақта)",
|
||||
"Sidebar.untitled-view": "(Атаусыз Көрініс)",
|
||||
"TableComponent.add-icon": "Иконды қосу",
|
||||
"TableComponent.name": "Атауы",
|
||||
"TableComponent.plus-new": "+ Қосу",
|
||||
|
@ -100,11 +100,6 @@
|
||||
"ContentBlock.moveDown": "아래로 이동하기",
|
||||
"ContentBlock.moveUp": "위로 이동하기",
|
||||
"ContentBlock.text": "텍스트",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "채널을 쉽게 바꾸기 위해 전환기를 사용하세요",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "죄송합니다. 해당 단어와 일치하는 채널을 찾을 수 없습니다",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "다른 단어로 검색해보세요",
|
||||
"DashboardPage.showEmpty": "빈칸 표시",
|
||||
"DashboardPage.title": "대시보드",
|
||||
"DeleteBoardDialog.confirm-cancel": "취소",
|
||||
"DeleteBoardDialog.confirm-delete": "삭제",
|
||||
"DeleteBoardDialog.confirm-info": "“{boardTitle}” 보드를 삭제하시겠습니까? 이 보드에 있는 모든 카드들이 삭제됩니다.",
|
||||
@ -131,9 +126,7 @@
|
||||
"KanbanCard.delete": "삭제",
|
||||
"KanbanCard.duplicate": "복제",
|
||||
"KanbanCard.untitled": "제목 없음",
|
||||
"Mutator.duplicate-board": "보드 복제",
|
||||
"Mutator.new-card-from-template": "템플릿에서 새 카드 만들기",
|
||||
"Mutator.new-template-from-board": "보드에서 새 템플릿 만들기",
|
||||
"Mutator.new-template-from-card": "카드에서 새 템플릿 만들기",
|
||||
"PropertyMenu.Delete": "삭제",
|
||||
"PropertyMenu.changeType": "속성 유형 변경",
|
||||
@ -169,20 +162,15 @@
|
||||
"Sidebar.add-board": "+ 보드 추가",
|
||||
"Sidebar.changePassword": "패스워드 변경",
|
||||
"Sidebar.delete-board": "보드 삭제",
|
||||
"Sidebar.duplicate-board": "보드 복제",
|
||||
"Sidebar.export-archive": "아카이브 내보내기",
|
||||
"Sidebar.import-archive": "아카이브 들여오기",
|
||||
"Sidebar.invite-users": "사용자 초대",
|
||||
"Sidebar.logout": "로그아웃",
|
||||
"Sidebar.no-more-workspaces": "더 이상 작업 공간이 없습니다",
|
||||
"Sidebar.no-views-in-board": "페이지가 없습니다",
|
||||
"Sidebar.random-icons": "임의 아이콘",
|
||||
"Sidebar.set-language": "언어 설정",
|
||||
"Sidebar.set-theme": "테마 설정",
|
||||
"Sidebar.settings": "설정",
|
||||
"Sidebar.template-from-board": "보드에서 새 템플릿 만들기",
|
||||
"Sidebar.untitled-board": "(제목 없는 보드)",
|
||||
"Sidebar.untitled-view": "(제목 없는 뷰)",
|
||||
"TableComponent.add-icon": "아이콘 추가",
|
||||
"TableComponent.name": "이름",
|
||||
"TableComponent.plus-new": "+ 생성",
|
||||
|
@ -7,6 +7,8 @@
|
||||
"BoardComponent.no-property": "ഇല്ല {property}",
|
||||
"BoardComponent.no-property-title": "ശൂന്യമായ {property} പ്രോപ്പർട്ടി ഉള്ള ഇനങ്ങൾ ഇവിടെ പോകും. ഈ കോളം നീക്കം ചെയ്യാൻ കഴിയില്ല.",
|
||||
"BoardComponent.show": "കാണിക്കുക",
|
||||
"BoardMember.schemeAdmin": "അഡ്മിൻ",
|
||||
"BoardMember.schemeEditor": "എഡിറ്റർ",
|
||||
"BoardPage.newVersion": "ബോർഡുകളുടെ ഒരു പുതിയ പതിപ്പ് ലഭ്യമാണ്, റീലോഡ് ചെയ്യാൻ ഇവിടെ ക്ലിക്ക് ചെയ്യുക.",
|
||||
"BoardPage.syncFailed": "ബോർഡ് ഇല്ലാതാക്കുകയോ ആക്സസ് റദ്ദാക്കുകയോ ചെയ്യാം.",
|
||||
"BoardTemplateSelector.add-template": "പുതിയ ടെംപ്ലേറ്റ്",
|
||||
@ -81,6 +83,9 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "കാർഡ് ഇല്ലാതാക്കൽ സ്ഥിരീകരിക്കുക!",
|
||||
"CardDialog.editing-template": "നിങ്ങൾ ഒരു ടെംപ്ലേറ്റ് എഡിറ്റ് ചെയ്യുകയാണ്.",
|
||||
"CardDialog.nocard": "ഈ കാർഡ് നിലവിലില്ല അല്ലെങ്കിൽ ആക്സസ് ചെയ്യാനാകുന്നില്ല.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "റദ്ദാക്കുക",
|
||||
"Categories.CreateCategoryDialog.CreateText": "സൃഷ്ടിക്കുക",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "അപ്ഡേറ്റ് ചെയ്യുക",
|
||||
"CenterPanel.Share": "പങ്കിടുക",
|
||||
"ColorOption.selectColor": "നിറം {color} തിരഞ്ഞെടുക്കുക",
|
||||
"Comment.delete": "ഇല്ലാതാക്കുക",
|
||||
@ -101,11 +106,6 @@
|
||||
"ContentBlock.moveDown": "താഴേക്ക് നീക്കുക",
|
||||
"ContentBlock.moveUp": "മുകളിലേക്കു നീക്കുക",
|
||||
"ContentBlock.text": "വാചകം",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "ചാനലുകൾ എളുപ്പത്തിൽ മാറ്റാൻ സ്വിച്ചർ ഉപയോഗിക്കുക",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "ക്ഷമിക്കണം, ആ പദവുമായി പൊരുത്തപ്പെടുന്ന ചാനലുകളൊന്നും കണ്ടെത്താൻ ഞങ്ങൾക്ക് കഴിഞ്ഞില്ല",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "ദയവായി മറ്റൊരു പദത്തിനായി തിരയാൻ ശ്രമിക്കുക",
|
||||
"DashboardPage.showEmpty": "ശൂന്യമായി കാണിക്കുക",
|
||||
"DashboardPage.title": "ഡാഷ്ബോർഡ്",
|
||||
"DeleteBoardDialog.confirm-cancel": "നിര്ത്തലാക്കുക",
|
||||
"DeleteBoardDialog.confirm-delete": "നീക്കം ചെയ്യുക",
|
||||
"DeleteBoardDialog.confirm-info": "\"{boardTitle}\" എന്ന ബോർഡ് ഇല്ലാതാക്കണമെന്ന് തീർച്ചയാണോ? ഇത് ഇല്ലാതാക്കുന്നത് ബോർഡിലെ എല്ലാ കാർഡുകളും ഇല്ലാതാക്കും.",
|
||||
@ -134,9 +134,7 @@
|
||||
"KanbanCard.delete": "ഇല്ലാതാക്കുക",
|
||||
"KanbanCard.duplicate": "തനിപ്പകർപ്പ്",
|
||||
"KanbanCard.untitled": "ശീർഷകമില്ലാത്തത്",
|
||||
"Mutator.duplicate-board": "ബോർഡിൻറെ തനിപ്പകർപ്പ്",
|
||||
"Mutator.new-card-from-template": "ടെംപ്ലേറ്റിൽ നിന്നുള്ള പുതിയ കാർഡ്",
|
||||
"Mutator.new-template-from-board": "ബോർഡിൽ നിന്നുള്ള പുതിയ ടെംപ്ലേറ്റ്",
|
||||
"Mutator.new-template-from-card": "കാർഡിൽ നിന്നുള്ള പുതിയ ടെംപ്ലേറ്റ്",
|
||||
"OnboardingTour.AddComments.Body": "നിങ്ങൾക്ക് പ്രശ്നങ്ങളിൽ അഭിപ്രായമിടാം, ഒപ്പം നിങ്ങളുടെ സഹ മാറ്റർമോസ് ഉപയോക്താക്കളെ അവരുടെ ശ്രദ്ധ ആകർഷിക്കാൻ അവരെ @പരാമർശിക്കുകയും ചെയ്യാം.",
|
||||
"OnboardingTour.AddComments.Title": "അഭിപ്രായങ്ങൾ ചേർക്കുക",
|
||||
@ -190,21 +188,16 @@
|
||||
"Sidebar.add-board": "+ ബോർഡ് ചേർക്കുക",
|
||||
"Sidebar.changePassword": "പാസ്സ്വേഡ് മാറ്റുക",
|
||||
"Sidebar.delete-board": "ബോർഡ് നീക്കം ചെയ്യുക",
|
||||
"Sidebar.duplicate-board": "ബോർഡിൻറെ തനിപ്പകർപ്പ്",
|
||||
"Sidebar.export-archive": "ആർക്കൈവ് എക്സ്പോർട്ട് ചെയ്യുക",
|
||||
"Sidebar.import": "ഇറക്കുമതി ചെയ്യുക",
|
||||
"Sidebar.import-archive": "ആർക്കൈവ് ഇമ്പോർട്ട് ചെയ്യുക",
|
||||
"Sidebar.invite-users": "ഉപയോക്താക്കളെ ക്ഷണിക്കുക",
|
||||
"Sidebar.logout": "ലോഗ്ഔട്ട്",
|
||||
"Sidebar.no-more-workspaces": "കൂടുതൽ വർക്ക്സ്പെയ്സുകളൊന്നുമില്ല",
|
||||
"Sidebar.no-views-in-board": "അകത്ത് പേജുകളൊന്നുമില്ല",
|
||||
"Sidebar.random-icons": "ക്രമരഹിതമായ ഐക്കണുകൾ",
|
||||
"Sidebar.set-language": "ഭാഷ സജ്ജമാക്കുക",
|
||||
"Sidebar.set-theme": "തീം സജ്ജമാക്കുക",
|
||||
"Sidebar.settings": "ക്രമീകരണങ്ങൾ",
|
||||
"Sidebar.template-from-board": "ബോർഡിൽ നിന്നുള്ള പുതിയ ടെംപ്ലേറ്റ്",
|
||||
"Sidebar.untitled-board": "(പേരില്ലാത്ത ബോർഡ്)",
|
||||
"Sidebar.untitled-view": "(ശീർഷകമില്ലാത്ത കാഴ്ച)",
|
||||
"TableComponent.add-icon": "ഐക്കൺ ചേർക്കുക",
|
||||
"TableComponent.name": "പേര്",
|
||||
"TableComponent.plus-new": "+ പുതിയത്",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "Geen {property}",
|
||||
"BoardComponent.no-property-title": "Items met een lege {property} eigenschap komen hier te staan. Deze kolom kan niet worden verwijderd.",
|
||||
"BoardComponent.show": "Toon",
|
||||
"BoardMember.schemeAdmin": "Beheerder",
|
||||
"BoardMember.schemeEditor": "Bewerker",
|
||||
"BoardMember.schemeNone": "Geen",
|
||||
"BoardPage.newVersion": "Er is een nieuwe versie van Boards, klik hier om te herladen.",
|
||||
"BoardPage.syncFailed": "Het bord kan worden verwijderd of de toegang kan worden ingetrokken.",
|
||||
"BoardTemplateSelector.add-template": "Nieuw sjabloon",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "Verwijderen",
|
||||
"BoardTemplateSelector.description": "Kies een sjabloon om je op weg te helpen. Pas het sjabloon eenvoudig aan jouw behoeften aan, of maak een leeg bord om vanaf nul te beginnen.",
|
||||
"BoardTemplateSelector.edit-template": "Bewerken",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Voeg een bord toe aan de zijbalk met behulp van een van de sjablonen die hieronder zijn gedefinieerd of begin vanaf nul.{lineBreak} Leden van \"{workspaceName}\" hebben toegang tot de boards die hier gemaakt zijn.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Maak een Board in {workspaceName}",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Voeg een bord toe aan de zijbalk door gebruik te maken van één van de sjablonen die hieronder zijn gedefinieerd of begin vanaf nul.{lineBreak} Leden van \"{teamName}\" zullen toegang hebben tot de boards die hier zijn gemaakt.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Maak een Board in {teamName}",
|
||||
"BoardTemplateSelector.title": "Maak een Board",
|
||||
"BoardTemplateSelector.use-this-template": "Gebruik dit sjabloon",
|
||||
"BoardsSwitcher.Title": "Boards vinden",
|
||||
"BoardsUnfurl.Remainder": "+{remainder} meer",
|
||||
"BoardsUnfurl.Updated": "Bijgewerkt {time}",
|
||||
"Calculations.Options.average.displayName": "Gemiddeld",
|
||||
@ -81,6 +85,10 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "Bevestig kaart verwijderen!",
|
||||
"CardDialog.editing-template": "Je bent een sjabloon aan het bewerken.",
|
||||
"CardDialog.nocard": "Deze kaart bestaat niet of is ontoegankelijk.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "Annuleren",
|
||||
"Categories.CreateCategoryDialog.CreateText": "Aanmaken",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "Geef je categorie een naam",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "Bijwerken",
|
||||
"CenterPanel.Share": "Delen",
|
||||
"ColorOption.selectColor": "Selecteer {color} Kleur",
|
||||
"Comment.delete": "Verwijderen",
|
||||
@ -101,11 +109,6 @@
|
||||
"ContentBlock.moveDown": "Naar beneden verplaatsen",
|
||||
"ContentBlock.moveUp": "Naar boven verplaatsen",
|
||||
"ContentBlock.text": "tekst",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Gebruik de wisselaar om gemakkelijk van kanaal te veranderen",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Sorry, we konden geen kanalen vinden die aan deze term voldoen",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Probeer op een andere term te zoeken",
|
||||
"DashboardPage.showEmpty": "Leeg tonen",
|
||||
"DashboardPage.title": "Dashboard",
|
||||
"DeleteBoardDialog.confirm-cancel": "Annuleren",
|
||||
"DeleteBoardDialog.confirm-delete": "Verwijderen",
|
||||
"DeleteBoardDialog.confirm-info": "Weet je zeker dat u het bord \"{boardTitle}\" wil verwijderen? Het verwijderen van het bord zal alle kaarten in het bord verwijderen.",
|
||||
@ -121,6 +124,9 @@
|
||||
"Filter.not-includes": "bevat niet",
|
||||
"FilterComponent.add-filter": "+ Filter toevoegen",
|
||||
"FilterComponent.delete": "Verwijderen",
|
||||
"FindBoFindBoardsDialog.IntroText": "Zoeken naar borden",
|
||||
"FindBoardsDialog.NoResultsFor": "Geen resultaten voor \"{searchQuery}\"",
|
||||
"FindBoardsDialog.NoResultsSubtext": "Controleer de spelling of probeer een andere zoekopdracht.",
|
||||
"GalleryCard.copiedLink": "Gekopieerd!",
|
||||
"GalleryCard.copyLink": "Kopieer link",
|
||||
"GalleryCard.delete": "Verwijderen",
|
||||
@ -134,9 +140,7 @@
|
||||
"KanbanCard.delete": "Verwijderen",
|
||||
"KanbanCard.duplicate": "Kopiëren",
|
||||
"KanbanCard.untitled": "Titelloos",
|
||||
"Mutator.duplicate-board": "bord kopiëren",
|
||||
"Mutator.new-card-from-template": "nieuwe kaart van sjabloon",
|
||||
"Mutator.new-template-from-board": "nieuw sjabloon van bord",
|
||||
"Mutator.new-template-from-card": "nieuw sjabloon van kaart",
|
||||
"OnboardingTour.AddComments.Body": "Je kunt commentaar geven op onderwerpen, en zelfs je medeMattermostgebruikers @vermelden om hun aandacht te trekken.",
|
||||
"OnboardingTour.AddComments.Title": "Opmerkingen toevoegen",
|
||||
@ -190,21 +194,16 @@
|
||||
"Sidebar.add-board": "+ Bord toevoegen",
|
||||
"Sidebar.changePassword": "Wachtwoord wijzigen",
|
||||
"Sidebar.delete-board": "Verwijder bord",
|
||||
"Sidebar.duplicate-board": "Bord kopiëren",
|
||||
"Sidebar.export-archive": "Archief exporteren",
|
||||
"Sidebar.import": "Importeren",
|
||||
"Sidebar.import-archive": "Archief importeren",
|
||||
"Sidebar.invite-users": "Gebruikers uitnodigen",
|
||||
"Sidebar.logout": "Afmelden",
|
||||
"Sidebar.no-more-workspaces": "Geen werkruimtes meer",
|
||||
"Sidebar.no-views-in-board": "Geen pagina's binnenin",
|
||||
"Sidebar.random-icons": "Willekeurige iconen",
|
||||
"Sidebar.set-language": "Taal instellen",
|
||||
"Sidebar.set-theme": "Thema instellen",
|
||||
"Sidebar.settings": "Instellingen",
|
||||
"Sidebar.template-from-board": "Nieuw sjabloon van bord",
|
||||
"Sidebar.untitled-board": "(Titelloze bord )",
|
||||
"Sidebar.untitled-view": "(Titelloze weergave)",
|
||||
"TableComponent.add-icon": "Pictogram toevoegen",
|
||||
"TableComponent.name": "Naam",
|
||||
"TableComponent.plus-new": "+ Nieuw",
|
||||
|
@ -40,11 +40,6 @@
|
||||
"ContentBlock.moveDown": "Desplaçar al dejós",
|
||||
"ContentBlock.moveUp": "Desplaçar al dessús",
|
||||
"ContentBlock.text": "tèxt",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Utilizatz l’alternator per cambiar facilament de cadenas",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "O planhèm, avèm pas trobat cap de cadena correspondenta al tèrme",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Mercés d’ensajar d’autres tèrmes",
|
||||
"DashboardPage.showEmpty": "Mostrar void",
|
||||
"DashboardPage.title": "Tablèu de bòrd",
|
||||
"Dialog.closeDialog": "Tampar la fenèstra de dialòg",
|
||||
"EditableDayPicker.today": "Uèi",
|
||||
"Error.websocket-closed": "Connexion al websocket tampada, connexion interrompuda. S’aquò ten de se produire, verificatz la configuracion del servidor o del servidor mandatari.",
|
||||
@ -65,9 +60,7 @@
|
||||
"KanbanCard.delete": "Suprimir",
|
||||
"KanbanCard.duplicate": "Duplicar",
|
||||
"KanbanCard.untitled": "Sens títol",
|
||||
"Mutator.duplicate-board": "duplicar lo tablèu",
|
||||
"Mutator.new-card-from-template": "zòna novèla a partir d’un modèl",
|
||||
"Mutator.new-template-from-board": "modèl novèl a parti d’un tablèu",
|
||||
"Mutator.new-template-from-card": "modèl novèl a partir d’una zòna",
|
||||
"PropertyMenu.Delete": "Suprimir",
|
||||
"PropertyMenu.changeType": "Modificar lo tipe de proprietat",
|
||||
@ -103,20 +96,15 @@
|
||||
"Sidebar.add-board": "+ Apondre un tablèu",
|
||||
"Sidebar.changePassword": "Modificar lo senhal",
|
||||
"Sidebar.delete-board": "Suprimir lo tablèu",
|
||||
"Sidebar.duplicate-board": "Duplicar lo tablèu",
|
||||
"Sidebar.export-archive": "Exportar un archiu",
|
||||
"Sidebar.import-archive": "Importar un archiu",
|
||||
"Sidebar.invite-users": "Convidar utilizaires",
|
||||
"Sidebar.logout": "Se desconnectar",
|
||||
"Sidebar.no-more-workspaces": "Pas mai d’espaci de trabalh",
|
||||
"Sidebar.no-views-in-board": "Cap de pagina pas inclusa",
|
||||
"Sidebar.random-icons": "Icònas aleatòrias",
|
||||
"Sidebar.set-language": "Definir la lenga",
|
||||
"Sidebar.set-theme": "Causir lo tèma",
|
||||
"Sidebar.settings": "Paramètres",
|
||||
"Sidebar.template-from-board": "Modèl novèl a partir del tablèu",
|
||||
"Sidebar.untitled-board": "(Tablèu sens títol)",
|
||||
"Sidebar.untitled-view": "(Vista sens títol)",
|
||||
"TableComponent.add-icon": "Apondre una icòna",
|
||||
"TableComponent.name": "Nom",
|
||||
"TableComponent.plus-new": "+ Novèl",
|
||||
|
@ -101,11 +101,6 @@
|
||||
"ContentBlock.moveDown": "Przesuń w dół",
|
||||
"ContentBlock.moveUp": "Przesuń do góry",
|
||||
"ContentBlock.text": "tekst",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Użyj przełącznika, aby łatwo zmieniać kanały",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Niestety, nie znaleźliśmy żadnych kanałów pasujących do tej frazy",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Proszę spróbować wyszukać inną frazę",
|
||||
"DashboardPage.showEmpty": "Pokaż puste",
|
||||
"DashboardPage.title": "Tablica",
|
||||
"DeleteBoardDialog.confirm-cancel": "Anuluj",
|
||||
"DeleteBoardDialog.confirm-delete": "Usuń",
|
||||
"DeleteBoardDialog.confirm-info": "Czy na pewno chcesz usunąć tablicę \"{boardTitle}\"? Usunięcie jej spowoduje usunięcie wszystkich kart na tablicy.",
|
||||
@ -126,16 +121,30 @@
|
||||
"GalleryCard.delete": "Usuń",
|
||||
"GalleryCard.duplicate": "Duplikuj",
|
||||
"General.BoardCount": "{count, plural, one {# Tablica} other {# Tablice}}",
|
||||
"GroupBy.hideEmptyGroups": "Ukryj {count} pustych grup",
|
||||
"GroupBy.showHiddenGroups": "Pokaż {count} ukrytych grup",
|
||||
"GroupBy.ungroup": "Rozgrupuj",
|
||||
"KanbanCard.copiedLink": "Skopiowane!",
|
||||
"KanbanCard.copyLink": "Kopiuj odnośnik",
|
||||
"KanbanCard.delete": "Usuń",
|
||||
"KanbanCard.duplicate": "Duplikuj",
|
||||
"KanbanCard.untitled": "Bez tytułu",
|
||||
"Mutator.duplicate-board": "duplikuj tablicę",
|
||||
"Mutator.new-card-from-template": "nowa karta z szablonu",
|
||||
"Mutator.new-template-from-board": "nowy szablon z tablicy",
|
||||
"Mutator.new-template-from-card": "nowy szablon z karty",
|
||||
"OnboardingTour.AddComments.Body": "Możesz komentować wydarzenia, a nawet @mention innych użytkowników Mattermost, aby zwrócić na siebie ich uwagę.",
|
||||
"OnboardingTour.AddComments.Title": "Dodaj komentarze",
|
||||
"OnboardingTour.AddDescription.Body": "Dodaj opis do swojej karty, aby koledzy z zespołu wiedzieli, czego ona dotyczy .",
|
||||
"OnboardingTour.AddDescription.Title": "Dodaj opis",
|
||||
"OnboardingTour.AddProperties.Body": "Dodawaj różne właściwości do kart, aby zwiększyć ich moc!",
|
||||
"OnboardingTour.AddProperties.Title": "Dodaj właściwości",
|
||||
"OnboardingTour.AddView.Body": "Przejdź tutaj, aby utworzyć nowy widok w celu uporządkowania tablicy przy użyciu różnych układów.",
|
||||
"OnboardingTour.AddView.Title": "Dodaj nowy widok",
|
||||
"OnboardingTour.CopyLink.Body": "Karty można udostępniać kolegom z zespołu, kopiując łącze i wklejając je w kanale, Wiadomości Bezpośredniej lub Wiadomości Grupowej.",
|
||||
"OnboardingTour.CopyLink.Title": "Kopiuj odnośnik",
|
||||
"OnboardingTour.OpenACard.Body": "Otwórz kartę, aby poznać różne sposoby, w których Tablice mogą pomóc Ci w organizacji pracy.",
|
||||
"OnboardingTour.OpenACard.Title": "Otwórz kartę",
|
||||
"OnboardingTour.ShareBoard.Body": "Możesz udostępniać swoją tablicę wewnętrznie, w ramach zespołu, lub publikować ją publicznie, aby była widoczna poza organizacją.",
|
||||
"OnboardingTour.ShareBoard.Title": "Udostępnij tablicę",
|
||||
"PropertyMenu.Delete": "Usuń",
|
||||
"PropertyMenu.changeType": "Zmień typ właściwości",
|
||||
"PropertyMenu.selectType": "Wybierz typ właściwości",
|
||||
@ -174,20 +183,16 @@
|
||||
"Sidebar.add-board": "+ Dodaj tablicę",
|
||||
"Sidebar.changePassword": "Zmień hasło",
|
||||
"Sidebar.delete-board": "Usuń tablicę",
|
||||
"Sidebar.duplicate-board": "Duplikuj tablicę",
|
||||
"Sidebar.export-archive": "Eksportuj archiwum",
|
||||
"Sidebar.import": "Importuj",
|
||||
"Sidebar.import-archive": "Importuj archiwum",
|
||||
"Sidebar.invite-users": "Zaproś użytkowników",
|
||||
"Sidebar.logout": "Wyloguj się",
|
||||
"Sidebar.no-more-workspaces": "Nie ma więcej obszaru roboczego",
|
||||
"Sidebar.no-views-in-board": "Brak stron wewnątrz",
|
||||
"Sidebar.random-icons": "Losowe ikony",
|
||||
"Sidebar.set-language": "Ustaw język",
|
||||
"Sidebar.set-theme": "Ustaw motyw",
|
||||
"Sidebar.settings": "Ustawienia",
|
||||
"Sidebar.template-from-board": "Nowy szablon z tablicy",
|
||||
"Sidebar.untitled-board": "(Tablica bez tytułu)",
|
||||
"Sidebar.untitled-view": "(Widok bez Tytułu)",
|
||||
"TableComponent.add-icon": "Dodaj Ikonę",
|
||||
"TableComponent.name": "Nazwa",
|
||||
"TableComponent.plus-new": "+ Nowy",
|
||||
@ -242,18 +247,32 @@
|
||||
"ViewTitle.show-description": "pokaż opis",
|
||||
"ViewTitle.untitled-board": "Tablica bez tytułu",
|
||||
"WelcomePage.Description": "Tablice to narzędzie do zarządzania projektami, które pomaga definiować, organizować, śledzić i zarządzać pracą w zespołach, wykorzystując widok znanych tablic kanban",
|
||||
"WelcomePage.Explore.Button": "Poznaj",
|
||||
"WelcomePage.Explore.Button": "Wybierz się na wycieczkę",
|
||||
"WelcomePage.Heading": "Witamy w Tablicach",
|
||||
"WelcomePage.NoThanks.Text": "Nie, dzięki, sam sobie z tym poradzę",
|
||||
"Workspace.editing-board-template": "Edytujesz szablon tablicy.",
|
||||
"calendar.month": "Miesiąc",
|
||||
"calendar.today": "DZIŚ",
|
||||
"calendar.week": "Tydzień",
|
||||
"default-properties.badges": "Uwagi i opis",
|
||||
"default-properties.title": "Tytuł",
|
||||
"error.back-to-boards": "Powrót do tablic",
|
||||
"error.back-to-home": "Powrót na stronę główną",
|
||||
"error.go-login": "Zaloguj się",
|
||||
"error.not-logged-in": "Być może Twoja sesja wygasła lub nie jesteś zalogowany.",
|
||||
"error.page.title": "Przepraszam, coś poszło nie tak",
|
||||
"error.relogin": "Zaloguj się ponownie",
|
||||
"error.unknown": "Wystąpił błąd.",
|
||||
"error.workspace-undefined": "Nie jest to prawidłowy obszar roboczy.",
|
||||
"generic.previous": "Wstecz",
|
||||
"login.log-in-button": "Zaloguj się",
|
||||
"login.log-in-title": "Zaloguj się",
|
||||
"login.register-button": "lub załóż konto, jeśli jeszcze go nie masz",
|
||||
"register.login-button": "lub zaloguj się, jeśli masz już konto",
|
||||
"register.signup-title": "Zarejestruj się na swoim koncie"
|
||||
"register.signup-title": "Zarejestruj się na swoim koncie",
|
||||
"tutorial_tip.finish_tour": "Gotowe",
|
||||
"tutorial_tip.got_it": "Jasne",
|
||||
"tutorial_tip.ok": "Dalej",
|
||||
"tutorial_tip.out": "Zrezygnuj z tych porad",
|
||||
"tutorial_tip.seen": "Widziałeś to wcześniej?"
|
||||
}
|
||||
|
@ -32,7 +32,6 @@
|
||||
"ContentBlock.moveDown": "Mover para baixo",
|
||||
"ContentBlock.moveUp": "Mover para cima",
|
||||
"ContentBlock.text": "texto",
|
||||
"DashboardPage.title": "Welcome to Focalboard!",
|
||||
"Dialog.closeDialog": "Fechar diálogo",
|
||||
"EditableDayPicker.today": "Hoje",
|
||||
"Error.websocket-closed": "Conexão Websocket fechada, conexão interrompida. Se isso persistir, verifique a configuração do seu servidor ou proxy da web.",
|
||||
@ -48,9 +47,7 @@
|
||||
"KanbanCard.delete": "Deletar",
|
||||
"KanbanCard.duplicate": "Duplicar",
|
||||
"KanbanCard.untitled": "Sem nome",
|
||||
"Mutator.duplicate-board": "quadro duplicado",
|
||||
"Mutator.new-card-from-template": "novo card à partir de um template",
|
||||
"Mutator.new-template-from-board": "novo template à partir de um quadro",
|
||||
"Mutator.new-template-from-card": "novo template à partir de um card",
|
||||
"PropertyMenu.Delete": "Deletar",
|
||||
"PropertyMenu.changeType": "Alterar tipo da propriedade",
|
||||
@ -84,19 +81,15 @@
|
||||
"Sidebar.add-board": "+ Adicionar Quadro",
|
||||
"Sidebar.changePassword": "Mudar senha",
|
||||
"Sidebar.delete-board": "Deletar quadro",
|
||||
"Sidebar.duplicate-board": "Duplicar quadro",
|
||||
"Sidebar.export-archive": "Exportar arquivo",
|
||||
"Sidebar.import-archive": "Importar arquivo",
|
||||
"Sidebar.invite-users": "Convidar Usuários",
|
||||
"Sidebar.logout": "Sair",
|
||||
"Sidebar.no-views-in-board": "Sem páginas dentro",
|
||||
"Sidebar.random-icons": "Ícones aleatórios",
|
||||
"Sidebar.set-language": "Definir linguagem",
|
||||
"Sidebar.set-theme": "Definir tema",
|
||||
"Sidebar.settings": "Configurações",
|
||||
"Sidebar.template-from-board": "Novo modelo à partir do quadro",
|
||||
"Sidebar.untitled-board": "(Quadro sem nome)",
|
||||
"Sidebar.untitled-view": "(Vista sem nome)",
|
||||
"TableComponent.add-icon": "Adicionar Ícone",
|
||||
"TableComponent.name": "Nome",
|
||||
"TableComponent.plus-new": "+ Novo",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "{property} пусто",
|
||||
"BoardComponent.no-property-title": "Здесь будут элементы с пустым свойством {property}. Этот столбец не может быть удален.",
|
||||
"BoardComponent.show": "Показать",
|
||||
"BoardMember.schemeAdmin": "Администратор",
|
||||
"BoardMember.schemeEditor": "Редактор",
|
||||
"BoardMember.schemeNone": "Никто",
|
||||
"BoardPage.newVersion": "Доступна новая версия Доски. Нажмите здесь, чтобы перезагрузить.",
|
||||
"BoardPage.syncFailed": "Доска может быть удалена или доступ аннулирован.",
|
||||
"BoardTemplateSelector.add-template": "Новый шаблон",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "Удалить",
|
||||
"BoardTemplateSelector.description": "Выберите шаблон, который поможет Вам начать работу. Легко настройте шаблон в соответствии со своими потребностями или создайте пустую доску, чтобы начать с нуля.",
|
||||
"BoardTemplateSelector.edit-template": "Редактировать",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Добавьте доску на боковую панель, используя любой из указанных ниже шаблонов, или начните с нуля.{lineBreak} Участники \"{workspaceName}\" будут иметь доступ к созданным здесь доскам.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Создать Доску в {workspaceName}",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Добавьте доску на боковую панель, используя любой из указанных ниже шаблонов, или начните с нуля.{lineBreak} Участники \"{teamName}\" будут иметь доступ к созданным здесь доскам.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "Создать доску в {teamName}",
|
||||
"BoardTemplateSelector.title": "Создать Доску",
|
||||
"BoardTemplateSelector.use-this-template": "Использовать этот шаблон",
|
||||
"BoardsSwitcher.Title": "Найти доски",
|
||||
"BoardsUnfurl.Remainder": "+{remainder} ещё",
|
||||
"BoardsUnfurl.Updated": "Обновлено {time}",
|
||||
"Calculations.Options.average.displayName": "Среднее",
|
||||
@ -72,7 +76,7 @@
|
||||
"CardDetailProperty.delete-action-button": "Удалить",
|
||||
"CardDetailProperty.property-change-action-button": "Изменить свойство",
|
||||
"CardDetailProperty.property-changed": "Свойство изменено успешно!",
|
||||
"CardDetailProperty.property-deleted": "{PropertyName} успешно удалено!",
|
||||
"CardDetailProperty.property-deleted": "{propertyName} успешно удалено!",
|
||||
"CardDetailProperty.property-name-change-subtext": "тип из \"{oldPropType}\" в \"{newPropType}\"",
|
||||
"CardDetailProperty.property-type-change-subtext": "название для \"{newPropName}\"",
|
||||
"CardDialog.copiedLink": "Скопировано!",
|
||||
@ -81,6 +85,10 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "Подтвердите удаление карточки!",
|
||||
"CardDialog.editing-template": "Вы редактируете шаблон.",
|
||||
"CardDialog.nocard": "Эта карточка не существует или недоступна.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "Отмена",
|
||||
"Categories.CreateCategoryDialog.CreateText": "Создать",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "Назовите свою категорию",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "Обновить",
|
||||
"CenterPanel.Share": "Поделится",
|
||||
"ColorOption.selectColor": "Выберите цвет {color}",
|
||||
"Comment.delete": "Удалить",
|
||||
@ -101,14 +109,9 @@
|
||||
"ContentBlock.moveDown": "Опустить",
|
||||
"ContentBlock.moveUp": "Поднять",
|
||||
"ContentBlock.text": "текст",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Используйте переключатель, чтобы легко сменить каналы",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "К сожалению, мы не смогли найти ни одного канала, соответствующего этому термину",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Пожалуйста, попробуйте найти другой термин",
|
||||
"DashboardPage.showEmpty": "Показать пустой",
|
||||
"DashboardPage.title": "Панель управления",
|
||||
"DeleteBoardDialog.confirm-cancel": "Отмена",
|
||||
"DeleteBoardDialog.confirm-delete": "Удалить",
|
||||
"DeleteBoardDialog.confirm-info": "Вы уверены, что хотите удалить доску \"{boardTitle}\"? Его удаление приведет к удалению всех карточек на доске.",
|
||||
"DeleteBoardDialog.confirm-info": "Вы уверены, что хотите удалить доску \"{boardTitle}\"? Ее удаление приведет к удалению всех карточек на доске.",
|
||||
"DeleteBoardDialog.confirm-tite": "Подтвердить удаление доски",
|
||||
"DeleteBoardDialog.confirm-tite-template": "Подтвердите удаление шаблона Доски",
|
||||
"Dialog.closeDialog": "Закрыть диалог",
|
||||
@ -121,11 +124,16 @@
|
||||
"Filter.not-includes": "не содержит",
|
||||
"FilterComponent.add-filter": "+ Добавить фильтр",
|
||||
"FilterComponent.delete": "Удалить",
|
||||
"FindBoFindBoardsDialog.IntroText": "Поиск досок",
|
||||
"FindBoardsDialog.NoResultsFor": "Нет результатов для \"{searchQuery}\"",
|
||||
"FindBoardsDialog.NoResultsSubtext": "Проверьте правильность написания или попробуйте другой запрос.",
|
||||
"FindBoardsDialog.SubTitle": "Введите запрос, чтобы найти доску. Используйте <b>ВВЕРХ/ВНИЗ</b> для просмотра. <b>ENTER</b> для выбора, <b>ESC</b> для закрытия",
|
||||
"FindBoardsDialog.Title": "Найти доски",
|
||||
"GalleryCard.copiedLink": "Скопировано!",
|
||||
"GalleryCard.copyLink": "Копировать ссылку",
|
||||
"GalleryCard.delete": "Удалить",
|
||||
"GalleryCard.duplicate": "Создать дубликат",
|
||||
"General.BoardCount": "{count, plural, one {# Доска} other {# Доски}}",
|
||||
"General.BoardCount": "{count, plural, one {# Доска} few {# Доски} other {# Досок}}",
|
||||
"GroupBy.hideEmptyGroups": "Скрыть {count} пустых групп",
|
||||
"GroupBy.showHiddenGroups": "Показать {count} скрытых групп",
|
||||
"GroupBy.ungroup": "Разгруппировать",
|
||||
@ -134,9 +142,7 @@
|
||||
"KanbanCard.delete": "Удалить",
|
||||
"KanbanCard.duplicate": "Создать дубликат",
|
||||
"KanbanCard.untitled": "Без названия",
|
||||
"Mutator.duplicate-board": "сделать дубликат доски",
|
||||
"Mutator.new-card-from-template": "новая карточка из шаблона",
|
||||
"Mutator.new-template-from-board": "новый шаблон из доски",
|
||||
"Mutator.new-template-from-card": "новый шаблон из карточки",
|
||||
"OnboardingTour.AddComments.Body": "Вы можете комментировать проблемы и даже @упоминать своих коллег-пользователей Mattermost, чтобы привлечь их внимание.",
|
||||
"OnboardingTour.AddComments.Title": "Добавить комментарии",
|
||||
@ -185,26 +191,31 @@
|
||||
"ShareBoard.copiedLink": "Скопировано!",
|
||||
"ShareBoard.copyLink": "Скопировать ссылку",
|
||||
"ShareBoard.regenerate": "Восстановить токен",
|
||||
"ShareBoard.teamPermissionsText": "Все в команде {teamName}",
|
||||
"ShareBoard.tokenRegenrated": "Токен пересоздан",
|
||||
"ShareBoard.userPermissionsRemoveMemberText": "Удалить участника",
|
||||
"ShareBoard.userPermissionsYouText": "(Вы)",
|
||||
"Sidebar.about": "О Focalboard",
|
||||
"Sidebar.add-board": "+ Добавить доску",
|
||||
"Sidebar.changePassword": "Изменить пароль",
|
||||
"Sidebar.delete-board": "Удалить доску",
|
||||
"Sidebar.duplicate-board": "Сделать дубликат доски",
|
||||
"Sidebar.export-archive": "Экспорт архива",
|
||||
"Sidebar.import": "Импорт",
|
||||
"Sidebar.import-archive": "Импорт архива",
|
||||
"Sidebar.invite-users": "Пригласить пользователей",
|
||||
"Sidebar.logout": "Выйти",
|
||||
"Sidebar.no-more-workspaces": "Рабочих пространств больше нет",
|
||||
"Sidebar.no-views-in-board": "Внутри нет страниц",
|
||||
"Sidebar.no-boards-in-category": "Без досок внутри",
|
||||
"Sidebar.random-icons": "Случайные иконки",
|
||||
"Sidebar.set-language": "Язык",
|
||||
"Sidebar.set-theme": "Тема",
|
||||
"Sidebar.settings": "Настройки",
|
||||
"Sidebar.template-from-board": "Новый шаблон из доски",
|
||||
"Sidebar.untitled-board": "(Доска без названия)",
|
||||
"Sidebar.untitled-view": "(Вид без названия)",
|
||||
"SidebarCategories.BlocksMenu.Move": "Перейти к...",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "Создать новую категорию",
|
||||
"SidebarCategories.CategoryMenu.Delete": "Удалить категорию",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "Доски в <b>{categoryName}</b> вернутся к категориям \"Доски\". Вы не удалены ни с одной доски.",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "Удалить эту категорию?",
|
||||
"SidebarCategories.CategoryMenu.Update": "Переименовать категорию",
|
||||
"TableComponent.add-icon": "Добавить иконку",
|
||||
"TableComponent.name": "Название",
|
||||
"TableComponent.plus-new": "+ Создать",
|
||||
@ -282,6 +293,7 @@
|
||||
"login.register-button": "или создать аккаунт, если у Вас его нет",
|
||||
"register.login-button": "или войти в систему, если у вас уже есть аккаунт",
|
||||
"register.signup-title": "Зарегистрируйте свой аккаунт",
|
||||
"shareBoard.lastAdmin": "Доски должны иметь хотя бы одного администратора",
|
||||
"tutorial_tip.finish_tour": "Готово",
|
||||
"tutorial_tip.got_it": "Понятно",
|
||||
"tutorial_tip.ok": "Следующий",
|
||||
|
@ -86,11 +86,6 @@
|
||||
"ContentBlock.moveDown": "Presuň dole",
|
||||
"ContentBlock.moveUp": "Presuň hore",
|
||||
"ContentBlock.text": "text",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Na zmenu kanálov použite prepínač",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Prepáčte, nenašli sa kanály s daným výrazom",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Skúste vyhľadať iný výraz",
|
||||
"DashboardPage.showEmpty": "Zobraziť prázdne",
|
||||
"DashboardPage.title": "Dashboard",
|
||||
"DeleteBoardDialog.confirm-cancel": "Zrušiť",
|
||||
"DeleteBoardDialog.confirm-delete": "Odstrániť",
|
||||
"DeleteBoardDialog.confirm-info": "Naozaj chcete odstrániť nástenku “{boardTitle}”? Odstránením vymažete všetky karty na tabuli.",
|
||||
@ -116,9 +111,7 @@
|
||||
"KanbanCard.delete": "Odstrániť",
|
||||
"KanbanCard.duplicate": "Duplikuj",
|
||||
"KanbanCard.untitled": "Nepomenované",
|
||||
"Mutator.duplicate-board": "duplikuj nástenku",
|
||||
"Mutator.new-card-from-template": "nová karta z template-u",
|
||||
"Mutator.new-template-from-board": "nový template z nástenky",
|
||||
"Mutator.new-template-from-card": "nový template z karty",
|
||||
"PropertyMenu.Delete": "Odstrániť",
|
||||
"PropertyMenu.changeType": "Zmeniť vlastnosť",
|
||||
@ -154,20 +147,15 @@
|
||||
"Sidebar.add-board": "+ Pridať nástenku",
|
||||
"Sidebar.changePassword": "Zmeniť heslo",
|
||||
"Sidebar.delete-board": "Odstrániť nástenku",
|
||||
"Sidebar.duplicate-board": "Duplikuj nástenku",
|
||||
"Sidebar.export-archive": "Export archívu",
|
||||
"Sidebar.import-archive": "Import archívu",
|
||||
"Sidebar.invite-users": "Pozvať užívateľa",
|
||||
"Sidebar.logout": "Odhlásiť sa",
|
||||
"Sidebar.no-more-workspaces": "Žiadne miesta",
|
||||
"Sidebar.no-views-in-board": "Bez obsahu",
|
||||
"Sidebar.random-icons": "Náhodné ikony",
|
||||
"Sidebar.set-language": "Nastaviť jazyk",
|
||||
"Sidebar.set-theme": "Nastaviť tému",
|
||||
"Sidebar.settings": "nastavenia",
|
||||
"Sidebar.template-from-board": "Nový template z nástenky",
|
||||
"Sidebar.untitled-board": "(nástenka bez názvu)",
|
||||
"Sidebar.untitled-view": "(náhľad bez názvu)",
|
||||
"TableComponent.add-icon": "Pridať ikonu",
|
||||
"TableComponent.name": "názov",
|
||||
"TableComponent.plus-new": "+ Nový",
|
||||
|
@ -80,11 +80,6 @@
|
||||
"ContentBlock.moveDown": "Flytta ned",
|
||||
"ContentBlock.moveUp": "Flytta upp",
|
||||
"ContentBlock.text": "text",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Använd kanalväljaren för att smidigt växla mellan kanaler",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Tyvärr hittade vi inga kanaler som matchar den termen",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Försök att söka efter en annan term",
|
||||
"DashboardPage.showEmpty": "Visa tomma",
|
||||
"DashboardPage.title": "Dashboard",
|
||||
"DeleteBoardDialog.confirm-cancel": "Avbryt",
|
||||
"DeleteBoardDialog.confirm-delete": "Radera",
|
||||
"DeleteBoardDialog.confirm-info": "Är du säker på att du vill ta bort tavlan “{boardTitle}”? När du tar bort den kommer du radera alla kort på tavlan.",
|
||||
@ -110,9 +105,7 @@
|
||||
"KanbanCard.delete": "Radera",
|
||||
"KanbanCard.duplicate": "Radera",
|
||||
"KanbanCard.untitled": "Saknar titel",
|
||||
"Mutator.duplicate-board": "duplicera tavla",
|
||||
"Mutator.new-card-from-template": "nytt kort från mall",
|
||||
"Mutator.new-template-from-board": "ny mall från tavla",
|
||||
"Mutator.new-template-from-card": "ny mall från kort",
|
||||
"PropertyMenu.Delete": "Radera",
|
||||
"PropertyMenu.changeType": "Ändra egenskapstyp",
|
||||
@ -148,20 +141,15 @@
|
||||
"Sidebar.add-board": "+ Lägg till tavla",
|
||||
"Sidebar.changePassword": "Ändra lösenord",
|
||||
"Sidebar.delete-board": "Radera tavla",
|
||||
"Sidebar.duplicate-board": "Duplicera tavla",
|
||||
"Sidebar.export-archive": "Exportera arkiv",
|
||||
"Sidebar.import-archive": "Importera arkiv",
|
||||
"Sidebar.invite-users": "Bjud in användare",
|
||||
"Sidebar.logout": "Logga ut",
|
||||
"Sidebar.no-more-workspaces": "Inga fler arbetsytor",
|
||||
"Sidebar.no-views-in-board": "Inga vyer på tavla",
|
||||
"Sidebar.random-icons": "Slumpmässiga ikoner",
|
||||
"Sidebar.set-language": "Välj språk",
|
||||
"Sidebar.set-theme": "Välj tema",
|
||||
"Sidebar.settings": "Inställningar",
|
||||
"Sidebar.template-from-board": "Ny mall från tavla",
|
||||
"Sidebar.untitled-board": "(Tavla saknar titel)",
|
||||
"Sidebar.untitled-view": "(Vy saknar titel)",
|
||||
"TableComponent.add-icon": "Lägg till ikon",
|
||||
"TableComponent.name": "Namn",
|
||||
"TableComponent.plus-new": "+ Ny",
|
||||
|
@ -7,6 +7,9 @@
|
||||
"BoardComponent.no-property": "{property} yok",
|
||||
"BoardComponent.no-property-title": "{property} alanı boş olan ögeler buraya atanır. Bu sütun silinemez.",
|
||||
"BoardComponent.show": "Görüntüle",
|
||||
"BoardMember.schemeAdmin": "Yönetici",
|
||||
"BoardMember.schemeEditor": "Düzenleyici",
|
||||
"BoardMember.schemeNone": "Yok",
|
||||
"BoardPage.newVersion": "Yeni bir pano sürümü yayınlanmış. Yeniden yüklemek için buraya tıklayın.",
|
||||
"BoardPage.syncFailed": "Pano silinmiş ya da erişim izni geri alınmış olabilir.",
|
||||
"BoardTemplateSelector.add-template": "Yeni kalıp",
|
||||
@ -14,10 +17,11 @@
|
||||
"BoardTemplateSelector.delete-template": "Sil",
|
||||
"BoardTemplateSelector.description": "Başlamanıza yardımcı olacak bir kalıp seçin. Kalıbı gereksinimlerinize göre kolayca özelleştirin ya da sıfırdan başlamak için boş bir pano oluşturun.",
|
||||
"BoardTemplateSelector.edit-template": "Düzenle",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Aşağıda tanımlanan kalıplardan herhangi birini kullanarak yan çubuğa bir pano ekleyin ya da sıfırdan başlayın.{lineBreak} \"{workspaceName}\" üyeleri burada oluşturulan panolara erişebilecek.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "{workspaceName} çalışma alanında bir pano oluştur",
|
||||
"BoardTemplateSelector.plugin.no-content-description": "Aşağıda tanımlanan kalıplardan herhangi birini kullanarak yan çubuğa bir pano ekleyin ya da sıfırdan başlayın.{lineBreak} \"{teamName}\" üyeleri burada oluşturulan panolara erişebilecek.",
|
||||
"BoardTemplateSelector.plugin.no-content-title": "{teamName} çalışma alanında bir pano oluştur",
|
||||
"BoardTemplateSelector.title": "Bir pano oluştur",
|
||||
"BoardTemplateSelector.use-this-template": "Bu kalıp kullanılsın",
|
||||
"BoardsSwitcher.Title": "Pano arama",
|
||||
"BoardsUnfurl.Remainder": "+{remainder} diğer",
|
||||
"BoardsUnfurl.Updated": "Güncellenme: {time}",
|
||||
"Calculations.Options.average.displayName": "Ortalama",
|
||||
@ -81,6 +85,10 @@
|
||||
"CardDialog.delete-confirmation-dialog-heading": "Kartı silmeyi onaylayın!",
|
||||
"CardDialog.editing-template": "Bir kalıbı düzenliyorsunuz.",
|
||||
"CardDialog.nocard": "Bu kart bulunamadı ya da erişilebilir değil.",
|
||||
"Categories.CreateCategoryDialog.CancelText": "İptal",
|
||||
"Categories.CreateCategoryDialog.CreateText": "Ekle",
|
||||
"Categories.CreateCategoryDialog.Placeholder": "Kategorinize bir ad verin",
|
||||
"Categories.CreateCategoryDialog.UpdateText": "Güncelle",
|
||||
"CenterPanel.Share": "Paylaş",
|
||||
"ColorOption.selectColor": "{color} rengi seçin",
|
||||
"Comment.delete": "Sil",
|
||||
@ -101,11 +109,6 @@
|
||||
"ContentBlock.moveDown": "Alta taşı",
|
||||
"ContentBlock.moveUp": "Üste taşı",
|
||||
"ContentBlock.text": "metin",
|
||||
"DashboardPage.CenterPanel.ChangeChannels": "Kanalları kolayca değiştirmek için değiştiriciyi kullanın",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "Maalesef, bu arama ifadesine uyan bir kanal bulunamadı",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Lütfen başka bir ifade ile aramayı deneyin",
|
||||
"DashboardPage.showEmpty": "Boş olanları görüntüle",
|
||||
"DashboardPage.title": "Pano",
|
||||
"DeleteBoardDialog.confirm-cancel": "İptal",
|
||||
"DeleteBoardDialog.confirm-delete": "Sil",
|
||||
"DeleteBoardDialog.confirm-info": "“{boardTitle}” panosunu silmek istediğinize emin misiniz? Silme işlemi bu panodaki tüm kartları siler.",
|
||||
@ -121,6 +124,11 @@
|
||||
"Filter.not-includes": "şunu içermeyen",
|
||||
"FilterComponent.add-filter": "+ Süzgeç ekle",
|
||||
"FilterComponent.delete": "Sil",
|
||||
"FindBoFindBoardsDialog.IntroText": "Pano arama",
|
||||
"FindBoardsDialog.NoResultsFor": "\"{searchQuery}\" için bir sonuç bulunamadı",
|
||||
"FindBoardsDialog.NoResultsSubtext": "Yazımı denetleyin ya da başka bir arama yapmayı deneyin.",
|
||||
"FindBoardsDialog.SubTitle": "Bulmak istediğiniz pano adını yazmaya başlayın. Gezinmek için <b>YUKAR/AŞAĞI</b>, seçmek için <b>ENTER</b>, vazgeçmek için <b>ESC</b> tuşlarını kullanın",
|
||||
"FindBoardsDialog.Title": "Pano arama",
|
||||
"GalleryCard.copiedLink": "Kopyalandı!",
|
||||
"GalleryCard.copyLink": "Bağlantıyı kopyala",
|
||||
"GalleryCard.delete": "Sil",
|
||||
@ -134,9 +142,7 @@
|
||||
"KanbanCard.delete": "Sil",
|
||||
"KanbanCard.duplicate": "Kopyala",
|
||||
"KanbanCard.untitled": "Başlıksız",
|
||||
"Mutator.duplicate-board": "panoyu kopyala",
|
||||
"Mutator.new-card-from-template": "kalıptan yeni kart oluştur",
|
||||
"Mutator.new-template-from-board": "panodan yeni kalıp oluştur",
|
||||
"Mutator.new-template-from-card": "karttan yeni kalıp oluştur",
|
||||
"OnboardingTour.AddComments.Body": "Sorunlar hakkında yorum yapabilir ve Mattermost kullanıcılarının dikkatini çekmek için @anabilirsiniz.",
|
||||
"OnboardingTour.AddComments.Title": "Yorum yap",
|
||||
@ -185,26 +191,31 @@
|
||||
"ShareBoard.copiedLink": "Kopyalandı!",
|
||||
"ShareBoard.copyLink": "Bağlantıyı kopyala",
|
||||
"ShareBoard.regenerate": "Kodu yeniden oluştur",
|
||||
"ShareBoard.teamPermissionsText": "{teamName} takımındaki herkes",
|
||||
"ShareBoard.tokenRegenrated": "Kod yeniden oluşturuldu",
|
||||
"ShareBoard.userPermissionsRemoveMemberText": "Üyelikten çıkar",
|
||||
"ShareBoard.userPermissionsYouText": "(Siz)",
|
||||
"Sidebar.about": "Focalboard hakkında",
|
||||
"Sidebar.add-board": "+ Pano ekle",
|
||||
"Sidebar.changePassword": "Parola değiştir",
|
||||
"Sidebar.delete-board": "Panoyu sil",
|
||||
"Sidebar.duplicate-board": "Panoyu kopyala",
|
||||
"Sidebar.export-archive": "Arşivi dışa aktar",
|
||||
"Sidebar.import": "İçe aktar",
|
||||
"Sidebar.import-archive": "Arşivi içe aktar",
|
||||
"Sidebar.invite-users": "Kullanıcıları çağır",
|
||||
"Sidebar.logout": "Oturumu kapat",
|
||||
"Sidebar.no-more-workspaces": "Başka bir çalışma alanı yok",
|
||||
"Sidebar.no-views-in-board": "İçeride bir sayfa yok",
|
||||
"Sidebar.no-boards-in-category": "İçeride bir pano yok",
|
||||
"Sidebar.random-icons": "Rastgele simgeler",
|
||||
"Sidebar.set-language": "Dil ayarla",
|
||||
"Sidebar.set-theme": "Tema ayarla",
|
||||
"Sidebar.settings": "Ayarlar",
|
||||
"Sidebar.template-from-board": "Panodan yeni kalıp",
|
||||
"Sidebar.untitled-board": "(Başlıksız pano)",
|
||||
"Sidebar.untitled-view": "(Başlıksız görünüm)",
|
||||
"SidebarCategories.BlocksMenu.Move": "Şuraya taşı...",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "Yeni kategori ekle",
|
||||
"SidebarCategories.CategoryMenu.Delete": "Kategoriyi sił",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "<b>{categoryName}</b> İçindeki panolar Panolar kategorisine taşınacak. Herhangi bir panodan çıkarılmayacaksınız.",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "Bu kategori silinsin mi?",
|
||||
"SidebarCategories.CategoryMenu.Update": "Kategoriyi yeniden adlandır",
|
||||
"TableComponent.add-icon": "Simge ekle",
|
||||
"TableComponent.name": "Ad",
|
||||
"TableComponent.plus-new": "+ Yeni",
|
||||
@ -282,6 +293,7 @@
|
||||
"login.register-button": "ya da hesabınız yoksa bir hesap açın",
|
||||
"register.login-button": "ya da bir hesabınız varsa oturum açın",
|
||||
"register.signup-title": "Hesap açın",
|
||||
"shareBoard.lastAdmin": "Panoların en az bir yöneticisi olmalıdır",
|
||||
"tutorial_tip.finish_tour": "Tamam",
|
||||
"tutorial_tip.got_it": "Anladım",
|
||||
"tutorial_tip.ok": "Sonraki",
|
||||
|
@ -43,7 +43,6 @@
|
||||
"ContentBlock.moveDown": "下移",
|
||||
"ContentBlock.moveUp": "上移",
|
||||
"ContentBlock.text": "文字",
|
||||
"DashboardPage.title": "仪表板",
|
||||
"Dialog.closeDialog": "关闭对话框",
|
||||
"EditableDayPicker.today": "今天",
|
||||
"Error.websocket-closed": "Websocket 连接关闭,连接中断。如果这种情况仍然存在,请检查您的服务器或网页代理配置。",
|
||||
@ -59,9 +58,7 @@
|
||||
"KanbanCard.delete": "删除",
|
||||
"KanbanCard.duplicate": "复制",
|
||||
"KanbanCard.untitled": "无标题",
|
||||
"Mutator.duplicate-board": "复制版面",
|
||||
"Mutator.new-card-from-template": "使用模板新增卡片",
|
||||
"Mutator.new-template-from-board": "从版面新增模板",
|
||||
"Mutator.new-template-from-card": "从卡片新增模板",
|
||||
"PropertyMenu.Delete": "删除",
|
||||
"PropertyMenu.changeType": "修改属性类型",
|
||||
@ -95,19 +92,15 @@
|
||||
"Sidebar.add-board": "+ 新增版面",
|
||||
"Sidebar.changePassword": "变更密码",
|
||||
"Sidebar.delete-board": "删除版面",
|
||||
"Sidebar.duplicate-board": "复制版面",
|
||||
"Sidebar.export-archive": "导出档案",
|
||||
"Sidebar.import-archive": "导入档案",
|
||||
"Sidebar.invite-users": "邀请使用者",
|
||||
"Sidebar.logout": "登出",
|
||||
"Sidebar.no-views-in-board": "里面没有页面",
|
||||
"Sidebar.random-icons": "随机图标",
|
||||
"Sidebar.set-language": "设定语言",
|
||||
"Sidebar.set-theme": "设置主题",
|
||||
"Sidebar.settings": "设定",
|
||||
"Sidebar.template-from-board": "从版面创建模板",
|
||||
"Sidebar.untitled-board": "(无标题版面)",
|
||||
"Sidebar.untitled-view": "(无标题视图)",
|
||||
"TableComponent.add-icon": "加入图标",
|
||||
"TableComponent.name": "姓名",
|
||||
"TableComponent.plus-new": "+ 新增",
|
||||
|
@ -44,9 +44,6 @@
|
||||
"ContentBlock.moveDown": "下移",
|
||||
"ContentBlock.moveUp": "上移",
|
||||
"ContentBlock.text": "文字",
|
||||
"DashboardPage.CenterPanel.NoWorkspaces": "很抱歉,我們找不到與符合該字詞的任何頻道",
|
||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "請嘗試以其他字詞進行搜尋",
|
||||
"DashboardPage.title": "資訊面板",
|
||||
"DeleteBoardDialog.confirm-cancel": "取消",
|
||||
"DeleteBoardDialog.confirm-delete": "刪除",
|
||||
"Dialog.closeDialog": "關閉對話框",
|
||||
@ -67,9 +64,7 @@
|
||||
"KanbanCard.delete": "刪除",
|
||||
"KanbanCard.duplicate": "建立副本",
|
||||
"KanbanCard.untitled": "無標題",
|
||||
"Mutator.duplicate-board": "建立版面副本",
|
||||
"Mutator.new-card-from-template": "使用範本新增卡片",
|
||||
"Mutator.new-template-from-board": "從版面新增範本",
|
||||
"Mutator.new-template-from-card": "從卡片新增範本",
|
||||
"PropertyMenu.Delete": "刪除",
|
||||
"PropertyMenu.changeType": "修改屬性類型",
|
||||
@ -104,20 +99,15 @@
|
||||
"Sidebar.add-board": "+ 新增版面",
|
||||
"Sidebar.changePassword": "變更密碼",
|
||||
"Sidebar.delete-board": "刪除版面",
|
||||
"Sidebar.duplicate-board": "建立版面副本",
|
||||
"Sidebar.export-archive": "匯入打包檔",
|
||||
"Sidebar.import-archive": "匯出打包檔",
|
||||
"Sidebar.invite-users": "邀請使用者",
|
||||
"Sidebar.logout": "登出",
|
||||
"Sidebar.no-more-workspaces": "沒有更多工作區",
|
||||
"Sidebar.no-views-in-board": "裡面沒有頁面",
|
||||
"Sidebar.random-icons": "隨機圖示",
|
||||
"Sidebar.set-language": "設定語言",
|
||||
"Sidebar.set-theme": "設定佈景主題",
|
||||
"Sidebar.settings": "設定",
|
||||
"Sidebar.template-from-board": "從版面新增範本",
|
||||
"Sidebar.untitled-board": "(無標題版面)",
|
||||
"Sidebar.untitled-view": "(無標題視圖)",
|
||||
"TableComponent.add-icon": "加入圖示",
|
||||
"TableComponent.name": "姓名",
|
||||
"TableComponent.plus-new": "+ 新增",
|
||||
|
546
webapp/package-lock.json
generated
546
webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -61,7 +61,7 @@
|
||||
"react-intl": "^5.24.7",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-router-dom": "^5.2.1",
|
||||
"react-select": "^4.3.0",
|
||||
"react-select": "^5.2.2",
|
||||
"trim-newlines": "^4.0.2"
|
||||
},
|
||||
"jest": {
|
||||
@ -108,7 +108,7 @@
|
||||
"@types/react-intl": "^3.0.0",
|
||||
"@types/react-redux": "^7.1.23",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-select": "^4.0.13",
|
||||
"@types/react-select": "^5.0.0",
|
||||
"@types/redux-mock-store": "^1.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
||||
"@typescript-eslint/parser": "^5.16.0",
|
||||
|
@ -40,7 +40,7 @@ exports[`components/blockIconSelector return menu on click 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -433,7 +433,7 @@ exports[`components/cardDialog return cardDialog menu content 1`] = `
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -485,8 +485,8 @@ exports[`components/cardDialog return cardDialog menu content 1`] = `
|
||||
class="MenuOption TextOption menu-option"
|
||||
role="button"
|
||||
>
|
||||
<div
|
||||
class="noicon"
|
||||
<i
|
||||
class="CompassIcon icon-plus undefined"
|
||||
/>
|
||||
<div
|
||||
class="menu-name"
|
||||
|
@ -24,7 +24,7 @@ exports[`components/contentBlock return commentBlock and click on menuwrapper 1`
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -6,7 +6,7 @@ Object {
|
||||
"baseElement": <body>
|
||||
<div>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -88,6 +88,8 @@ Object {
|
||||
<div
|
||||
class="MenuOption MenuSeparator menu-separator"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Duplicate view"
|
||||
class="MenuOption TextOption menu-option"
|
||||
@ -105,6 +107,8 @@ Object {
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Delete view"
|
||||
class="MenuOption TextOption menu-option"
|
||||
@ -122,6 +126,8 @@ Object {
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="MenuOption SubMenuOption menu-option"
|
||||
id="__addView"
|
||||
@ -176,7 +182,7 @@ Object {
|
||||
</body>,
|
||||
"container": <div>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -258,6 +264,8 @@ Object {
|
||||
<div
|
||||
class="MenuOption MenuSeparator menu-separator"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Duplicate view"
|
||||
class="MenuOption TextOption menu-option"
|
||||
@ -275,6 +283,8 @@ Object {
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Delete view"
|
||||
class="MenuOption TextOption menu-option"
|
||||
@ -292,6 +302,8 @@ Object {
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="MenuOption SubMenuOption menu-option"
|
||||
id="__addView"
|
||||
@ -403,7 +415,7 @@ Object {
|
||||
"baseElement": <body>
|
||||
<div>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -486,6 +498,9 @@ Object {
|
||||
class="MenuOption MenuSeparator menu-separator"
|
||||
/>
|
||||
</div>
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
<div
|
||||
class="menu-spacer hideOnWidescreen"
|
||||
@ -517,7 +532,7 @@ Object {
|
||||
</body>,
|
||||
"container": <div>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -600,6 +615,9 @@ Object {
|
||||
class="MenuOption MenuSeparator menu-separator"
|
||||
/>
|
||||
</div>
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
<div
|
||||
class="menu-spacer hideOnWidescreen"
|
||||
|
@ -27,21 +27,27 @@ const BoardTemplateSelectorPreview = (props: Props) => {
|
||||
const [activeTemplateCards, setActiveTemplateCards] = useState<Card[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
let isSubscribed = true
|
||||
if (activeTemplate) {
|
||||
setActiveTemplateCards([])
|
||||
setActiveView(null)
|
||||
setActiveTemplateCards([])
|
||||
octoClient.getAllBlocks(activeTemplate.id).then((blocks) => {
|
||||
const cards = blocks.filter((b) => b.type === 'card')
|
||||
const views = blocks.filter((b) => b.type === 'view').sort((a, b) => a.title.localeCompare(b.title))
|
||||
if (views.length > 0) {
|
||||
setActiveView(views[0] as BoardView)
|
||||
}
|
||||
if (cards.length > 0) {
|
||||
setActiveTemplateCards(cards as Card[])
|
||||
if (isSubscribed) {
|
||||
const cards = blocks.filter((b) => b.type === 'card')
|
||||
const views = blocks.filter((b) => b.type === 'view').sort((a, b) => a.title.localeCompare(b.title))
|
||||
if (views.length > 0) {
|
||||
setActiveView(views[0] as BoardView)
|
||||
}
|
||||
if (cards.length > 0) {
|
||||
setActiveTemplateCards(cards as Card[])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
isSubscribed = false
|
||||
}
|
||||
}, [activeTemplate])
|
||||
|
||||
const dateDisplayProperty = useMemo(() => {
|
||||
|
@ -86,8 +86,12 @@ exports[`components/calculations/Calculation should match snapshot - option chan
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -101,15 +105,21 @@ exports[`components/calculations/Calculation should match snapshot - option chan
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Calculate
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-2-listbox"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-2-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-2-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
|
@ -3,8 +3,12 @@
|
||||
exports[`components/calculations/Options should match snapshot 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -18,15 +22,21 @@ exports[`components/calculations/Options should match snapshot 1`] = `
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Calculate
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-2-listbox"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-2-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-2-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
@ -76,8 +86,12 @@ exports[`components/calculations/Options should match snapshot 1`] = `
|
||||
exports[`components/calculations/Options should match snapshot menu open 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-3-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -91,15 +105,21 @@ exports[`components/calculations/Options should match snapshot menu open 1`] = `
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Calculate
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-3-listbox"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-3-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-3-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
@ -139,11 +159,13 @@ exports[`components/calculations/Options should match snapshot menu open 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="CalculationOptions__menu css-1rsmi4x-menu"
|
||||
id="react-select-3-listbox"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__menu-list css-g29tl0-MenuList"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
class="CalculationOptions__option css-14xsrqy-option"
|
||||
id="react-select-3-option-0"
|
||||
tabindex="-1"
|
||||
@ -151,6 +173,7 @@ exports[`components/calculations/Options should match snapshot menu open 1`] = `
|
||||
Count
|
||||
</div>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
class="CalculationOptions__option css-14xsrqy-option"
|
||||
id="react-select-3-option-1"
|
||||
tabindex="-1"
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react'
|
||||
|
||||
import Select, {components, IndicatorProps} from 'react-select'
|
||||
import Select, {components, DropdownIndicatorProps} from 'react-select'
|
||||
|
||||
import {CSSObject} from '@emotion/serialize'
|
||||
|
||||
@ -151,7 +151,7 @@ const styles = {
|
||||
}),
|
||||
}
|
||||
|
||||
const DropdownIndicator = (props: IndicatorProps<Option, false>) => {
|
||||
const DropdownIndicator = (props: DropdownIndicatorProps<Option, false>) => {
|
||||
return (
|
||||
<components.DropdownIndicator {...props}>
|
||||
<ChevronUp/>
|
||||
|
@ -19,7 +19,7 @@ exports[`components/cardDetail/cardDetailContentsMenu return cardDetailContentsM
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect top"
|
||||
class="Menu noselect top "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -178,7 +178,7 @@ exports[`components/cardDetail/cardDetailContentsMenu return cardDetailContentsM
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect top"
|
||||
class="Menu noselect top "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -371,7 +371,7 @@ exports[`components/cardDetail/CardDetailProperties should show property types m
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -39,7 +39,7 @@ exports[`components/cardDetail/comment return comment 1`] = `
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -145,7 +145,7 @@ exports[`components/cardDetail/comment return comment and delete comment 1`] = `
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -13,6 +13,7 @@ import {getCardContents} from '../store/contents'
|
||||
import {useAppSelector} from '../store/hooks'
|
||||
import TelemetryClient, {TelemetryActions, TelemetryCategory} from '../telemetry/telemetryClient'
|
||||
import {Utils} from '../utils'
|
||||
import CompassIcon from '../widgets/icons/compassIcon'
|
||||
import DeleteIcon from '../widgets/icons/delete'
|
||||
import LinkIcon from '../widgets/icons/Link'
|
||||
import Menu from '../widgets/menu'
|
||||
@ -137,6 +138,10 @@ const CardDialog = (props: Props): JSX.Element => {
|
||||
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
|
||||
<Menu.Text
|
||||
id='makeTemplate'
|
||||
icon={
|
||||
<CompassIcon
|
||||
icon='plus'
|
||||
/>}
|
||||
name='New template from card'
|
||||
onClick={makeTemplateClicked}
|
||||
/>
|
||||
|
@ -125,7 +125,7 @@ exports[`src/components/gallery/Gallery should match snapshot 1`] = `
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -283,7 +283,7 @@ exports[`src/components/gallery/Gallery should match snapshot without permission
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -46,7 +46,7 @@ exports[`src/components/gallery/GalleryCard with a comment content should match
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -176,7 +176,7 @@ exports[`src/components/gallery/GalleryCard with an image content should match s
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -342,7 +342,7 @@ exports[`src/components/gallery/GalleryCard with many contents should match snap
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -476,7 +476,7 @@ exports[`src/components/gallery/GalleryCard with many images content should matc
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -768,7 +768,7 @@ exports[`src/components/gallery/GalleryCard without block content should match s
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -18,7 +18,7 @@ exports[`components/sidebar/GlobalHeaderSettingsMenu imports menu open should ma
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -323,7 +323,7 @@ exports[`components/sidebar/GlobalHeaderSettingsMenu languages menu open should
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -843,7 +843,7 @@ exports[`components/sidebar/GlobalHeaderSettingsMenu settings menu open should m
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -329,8 +329,12 @@ exports[`src/component/kanban/kanban return kanban and click on KanbanCalculatio
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -344,15 +348,21 @@ exports[`src/component/kanban/kanban return kanban and click on KanbanCalculatio
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Count
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-2-listbox"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-2-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-2-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
@ -392,6 +402,7 @@ exports[`src/component/kanban/kanban return kanban and click on KanbanCalculatio
|
||||
</div>
|
||||
<div
|
||||
class="CalculationOptions__menu css-1rsmi4x-menu"
|
||||
id="react-select-2-listbox"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__menu-list css-g29tl0-MenuList"
|
||||
|
@ -20,7 +20,7 @@ exports[`src/components/kanban/kanbanCard return kanbanCard and click on copy li
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -157,7 +157,7 @@ exports[`src/components/kanban/kanbanCard return kanbanCard and click on delete
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -294,7 +294,7 @@ exports[`src/components/kanban/kanbanCard return kanbanCard and click on duplica
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -48,7 +48,7 @@ exports[`src/components/kanban/kanbanColumnHeader return kanbanColumnHeader and
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -16,7 +16,7 @@ exports[`src/components/kanban/kanbanHiddenColumnItem return kanbanHiddenColumnI
|
||||
propOption
|
||||
</span>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -105,7 +105,7 @@ exports[`src/components/kanban/kanbanHiddenColumnItem return kanbanHiddenColumnI
|
||||
propOption
|
||||
</span>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -33,8 +33,12 @@ exports[`components/kanban/calculation/KanbanCalculation calculations menu open
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -48,15 +52,21 @@ exports[`components/kanban/calculation/KanbanCalculation calculations menu open
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Count
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-2-listbox"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-2-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-2-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
@ -96,6 +106,7 @@ exports[`components/kanban/calculation/KanbanCalculation calculations menu open
|
||||
</div>
|
||||
<div
|
||||
class="CalculationOptions__menu css-1rsmi4x-menu"
|
||||
id="react-select-2-listbox"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__menu-list css-g29tl0-MenuList"
|
||||
|
@ -3,8 +3,12 @@
|
||||
exports[`components/kanban/calculations/KanbanCalculationOptions base case 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -18,15 +22,21 @@ exports[`components/kanban/calculations/KanbanCalculationOptions base case 1`] =
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Count
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-2-listbox"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-2-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-2-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
@ -76,8 +86,12 @@ exports[`components/kanban/calculations/KanbanCalculationOptions base case 1`] =
|
||||
exports[`components/kanban/calculations/KanbanCalculationOptions with menu open 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-3-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -91,15 +105,21 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with menu open
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Count
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-3-listbox"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-3-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-3-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
@ -139,6 +159,7 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with menu open
|
||||
</div>
|
||||
<div
|
||||
class="CalculationOptions__menu css-1rsmi4x-menu"
|
||||
id="react-select-3-listbox"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__menu-list css-g29tl0-MenuList"
|
||||
@ -231,8 +252,12 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with menu open
|
||||
exports[`components/kanban/calculations/KanbanCalculationOptions with submenu open 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="CalculationOptions css-2b097c-container"
|
||||
class="CalculationOptions css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-4-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -246,15 +271,21 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with submenu op
|
||||
class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__single-value css-1brck82-singleValue"
|
||||
class="CalculationOptions__single-value css-1qlwihv-singleValue"
|
||||
>
|
||||
Count
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
class="css-wmatm6-dummyInput-DummyInput"
|
||||
aria-controls="react-select-4-listbox"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-4-listbox"
|
||||
aria-readonly="true"
|
||||
class="css-mohuvp-dummyInput-DummyInput"
|
||||
id="react-select-4-input"
|
||||
readonly=""
|
||||
inputmode="none"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
value=""
|
||||
/>
|
||||
@ -294,6 +325,7 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with submenu op
|
||||
</div>
|
||||
<div
|
||||
class="CalculationOptions__menu css-1rsmi4x-menu"
|
||||
id="react-select-4-listbox"
|
||||
>
|
||||
<div
|
||||
class="CalculationOptions__menu-list css-g29tl0-MenuList"
|
||||
|
@ -93,7 +93,7 @@ describe('components/properties/multiSelect', () => {
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableMultiSelectTestId))
|
||||
|
||||
expect(screen.getByRole('textbox', {name: /value selector/i})).toBeInTheDocument()
|
||||
expect(screen.getByRole('combobox', {name: /value selector/i})).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('can select a option', async () => {
|
||||
@ -118,7 +118,7 @@ describe('components/properties/multiSelect', () => {
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableMultiSelectTestId))
|
||||
|
||||
userEvent.type(screen.getByRole('textbox', {name: /value selector/i}), 'b{enter}')
|
||||
userEvent.type(screen.getByRole('combobox', {name: /value selector/i}), 'b{enter}')
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith(['multi-option-1', 'multi-option-2'])
|
||||
})
|
||||
@ -175,7 +175,7 @@ describe('components/properties/multiSelect', () => {
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableMultiSelectTestId))
|
||||
|
||||
userEvent.type(screen.getByRole('textbox', {name: /value selector/i}), 'new-value{enter}')
|
||||
userEvent.type(screen.getByRole('combobox', {name: /value selector/i}), 'new-value{enter}')
|
||||
|
||||
const selectedValues = propertyTemplate.options.filter((option: IPropertyOption) => propertyValue.includes(option.id))
|
||||
|
||||
|
@ -186,7 +186,7 @@ describe('components/properties/select', () => {
|
||||
))
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableSelectTestId))
|
||||
userEvent.type(screen.getByRole('textbox', {name: /value selector/i}), `${newOption}{enter}`)
|
||||
userEvent.type(screen.getByRole('combobox', {name: /value selector/i}), `${newOption}{enter}`)
|
||||
|
||||
expect(onCreate).toHaveBeenCalledWith(newOption)
|
||||
})
|
||||
|
@ -3,8 +3,12 @@
|
||||
exports[`components/properties/user not readonly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="UserProperty css-2b097c-container"
|
||||
class="UserProperty css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-3-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -15,10 +19,10 @@ exports[`components/properties/user not readonly 1`] = `
|
||||
class="react-select__control css-18140j1-Control"
|
||||
>
|
||||
<div
|
||||
class="react-select__value-container react-select__value-container--has-value css-o7cxt9-ValueContainer"
|
||||
class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="react-select__single-value css-14cfm31-singleValue"
|
||||
class="react-select__single-value css-1lixa2z-singleValue"
|
||||
>
|
||||
<div
|
||||
class="UserProperty-item"
|
||||
@ -27,28 +31,27 @@ exports[`components/properties/user not readonly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class="react-select__input-container css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-3-listbox"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-3-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="react-select__input"
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-3-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-3-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -100,8 +103,12 @@ exports[`components/properties/user not readonly 1`] = `
|
||||
exports[`components/properties/user not readonly not existing user 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="UserProperty css-2b097c-container"
|
||||
class="UserProperty css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -112,36 +119,37 @@ exports[`components/properties/user not readonly not existing user 1`] = `
|
||||
class="react-select__control css-18140j1-Control"
|
||||
>
|
||||
<div
|
||||
class="react-select__value-container css-o7cxt9-ValueContainer"
|
||||
class="react-select__value-container css-433wy7-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="react-select__placeholder css-1wa3eu0-placeholder"
|
||||
class="react-select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-2-placeholder"
|
||||
>
|
||||
Empty
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class="react-select__input-container css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-2-listbox"
|
||||
aria-describedby="react-select-2-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-2-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="react-select__input"
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-2-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-2-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -190,8 +198,12 @@ exports[`components/properties/user readonly view 1`] = `
|
||||
exports[`components/properties/user user dropdown open 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="UserProperty css-2b097c-container"
|
||||
class="UserProperty css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-4-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -211,10 +223,10 @@ exports[`components/properties/user user dropdown open 1`] = `
|
||||
class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control"
|
||||
>
|
||||
<div
|
||||
class="react-select__value-container react-select__value-container--has-value css-o7cxt9-ValueContainer"
|
||||
class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="react-select__single-value css-14cfm31-singleValue"
|
||||
class="react-select__single-value css-1lixa2z-singleValue"
|
||||
>
|
||||
<div
|
||||
class="UserProperty-item"
|
||||
@ -223,28 +235,27 @@ exports[`components/properties/user user dropdown open 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class="react-select__input-container css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-4-listbox"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-4-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="react-select__input"
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-4-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-4-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -291,11 +302,13 @@ exports[`components/properties/user user dropdown open 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="react-select__menu css-10b6da7-menu"
|
||||
id="react-select-4-listbox"
|
||||
>
|
||||
<div
|
||||
class="react-select__menu-list css-g29tl0-MenuList"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
class="react-select__option react-select__option--is-focused react-select__option--is-selected css-10e3bcm-option"
|
||||
id="react-select-4-option-0"
|
||||
tabindex="-1"
|
||||
|
@ -127,7 +127,7 @@ describe('components/properties/user', () => {
|
||||
if (container) {
|
||||
// this is the actual element where the click event triggers
|
||||
// opening of the dropdown
|
||||
const userProperty = container.querySelector('.UserProperty > div > div:nth-child(1) > div:nth-child(2) > div > input')
|
||||
const userProperty = container.querySelector('.UserProperty > div > div:nth-child(1) > div:nth-child(2) > input')
|
||||
expect(userProperty).not.toBeNull()
|
||||
|
||||
act(() => {
|
||||
|
@ -44,8 +44,12 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Copy l
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-4-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -56,36 +60,37 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Copy l
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-4-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-4-listbox"
|
||||
aria-describedby="react-select-4-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-4-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-4-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-4-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -96,7 +101,7 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Copy l
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -263,8 +268,12 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Copy l
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-4-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -275,36 +284,37 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Copy l
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-4-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-4-listbox"
|
||||
aria-describedby="react-select-4-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-4-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-4-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-4-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -315,7 +325,7 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Copy l
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -482,8 +492,12 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Regene
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-5-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -494,36 +508,37 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Regene
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-5-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-5-listbox"
|
||||
aria-describedby="react-select-5-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-5-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-5-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-5-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -534,7 +549,7 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Regene
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -724,8 +739,12 @@ exports[`src/components/shareBoard/shareBoard return shareBoard, and click switc
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-6-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -736,36 +755,37 @@ exports[`src/components/shareBoard/shareBoard return shareBoard, and click switc
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-6-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-6-listbox"
|
||||
aria-describedby="react-select-6-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-6-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-6-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-6-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -776,7 +796,7 @@ exports[`src/components/shareBoard/shareBoard return shareBoard, and click switc
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -966,8 +986,12 @@ exports[`src/components/shareBoard/shareBoard return shareBoardComponent and cli
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-7-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -978,36 +1002,37 @@ exports[`src/components/shareBoard/shareBoard return shareBoardComponent and cli
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-7-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-7-listbox"
|
||||
aria-describedby="react-select-7-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-7-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-7-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-7-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -1018,7 +1043,7 @@ exports[`src/components/shareBoard/shareBoard return shareBoardComponent and cli
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -1208,8 +1233,12 @@ exports[`src/components/shareBoard/shareBoard should match snapshot 1`] = `
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -1220,36 +1249,37 @@ exports[`src/components/shareBoard/shareBoard should match snapshot 1`] = `
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-2-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-2-listbox"
|
||||
aria-describedby="react-select-2-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-2-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-2-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-2-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -1260,7 +1290,7 @@ exports[`src/components/shareBoard/shareBoard should match snapshot 1`] = `
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -1427,8 +1457,12 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-3-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -1439,36 +1473,37 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-3-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-3-listbox"
|
||||
aria-describedby="react-select-3-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-3-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-3-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-3-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -1479,7 +1514,7 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -1646,8 +1681,12 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-9-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -1658,36 +1697,37 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-9-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-9-listbox"
|
||||
aria-describedby="react-select-9-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-9-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-9-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-9-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -1698,7 +1738,7 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
@ -1865,8 +1905,12 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class="CompassIcon icon-magnify MagnifyIcon"
|
||||
/>
|
||||
<div
|
||||
class="userSearchInput css-2b097c-container"
|
||||
class="userSearchInput css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-8-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
@ -1877,36 +1921,37 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class=" css-1wmrr75-Control"
|
||||
>
|
||||
<div
|
||||
class=" css-kpfmlq-ValueContainer"
|
||||
class=" css-30zlo3-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class=" css-1wa3eu0-placeholder"
|
||||
class=" css-14el2xx-placeholder"
|
||||
id="react-select-8-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="css-1shkodo-Input"
|
||||
class=" css-ox1y69-Input"
|
||||
data-value=""
|
||||
>
|
||||
<div
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="react-select-8-listbox"
|
||||
aria-describedby="react-select-8-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="react-select-8-listbox"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class=""
|
||||
style="display: inline-block;"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
id="react-select-8-input"
|
||||
spellcheck="false"
|
||||
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
|
||||
/>
|
||||
</div>
|
||||
id="react-select-8-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -1917,7 +1962,7 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing
|
||||
class=" css-byrije-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1yvy2vo-LoadingDot"
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
|
@ -275,7 +275,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
|
||||
value={selectedUser}
|
||||
className={'userSearchInput'}
|
||||
cacheOptions={true}
|
||||
loadOptions={(inputValue) => client.searchTeamUsers(inputValue)}
|
||||
loadOptions={(inputValue: string) => client.searchTeamUsers(inputValue)}
|
||||
components={{DropdownIndicator: () => null, IndicatorSeparator: () => null}}
|
||||
defaultOptions={true}
|
||||
getOptionValue={(u) => u.id}
|
||||
|
@ -16,7 +16,7 @@ exports[`components/sidebar/SidebarSettingsMenu imports menu open should match s
|
||||
Settings
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect top"
|
||||
class="Menu noselect top "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -324,7 +324,7 @@ exports[`components/sidebar/SidebarSettingsMenu languages menu open should match
|
||||
Settings
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect top"
|
||||
class="Menu noselect top "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -845,7 +845,7 @@ exports[`components/sidebar/SidebarSettingsMenu settings menu open should match
|
||||
Settings
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect top"
|
||||
class="Menu noselect top "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -1015,7 +1015,7 @@ exports[`components/sidebar/SidebarSettingsMenu theme menu open should match sna
|
||||
Settings
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect top"
|
||||
class="Menu noselect top "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -2,7 +2,7 @@
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-weight: 500;
|
||||
padding: 0 16px 0 8px;
|
||||
padding: 0 20px;
|
||||
height: 36px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
@ -23,7 +23,7 @@
|
||||
}
|
||||
|
||||
&.sidebar-view-item {
|
||||
padding-left: 40px;
|
||||
padding-left: 32px;
|
||||
color: rgba(var(--sidebar-text-rgb), 0.64);
|
||||
font-weight: 400;
|
||||
}
|
||||
@ -61,7 +61,6 @@
|
||||
> .Icon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.GalleryIcon {
|
||||
@ -160,3 +159,12 @@
|
||||
left: calc(240px - 50px);
|
||||
}
|
||||
}
|
||||
|
||||
.team-sidebar + .product-wrapper {
|
||||
.SidebarBoardItem {
|
||||
.Menu.noselect.left {
|
||||
right: calc(100% - 480px - 64px + 50px);
|
||||
left: calc(64px + 240px - 50px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,10 @@ const SidebarBoardItem = (props: Props) => {
|
||||
}}
|
||||
>
|
||||
<IconButton icon={<OptionsIcon/>}/>
|
||||
<Menu position='left'>
|
||||
<Menu
|
||||
fixed={true}
|
||||
position='left'
|
||||
>
|
||||
<BoardPermissionGate
|
||||
boardId={board.id}
|
||||
permissions={[Permission.DeleteBoard]}
|
||||
|
@ -6,7 +6,7 @@
|
||||
padding: 0 16px 0 8px;
|
||||
height: 36px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
gap: 4px;
|
||||
|
||||
&.category {
|
||||
padding-left: 0;
|
||||
|
@ -3,7 +3,7 @@
|
||||
exports[`components/table/TableHeaderMenu should match snapshot, other column 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -173,7 +173,7 @@ exports[`components/table/TableHeaderMenu should match snapshot, other column 1`
|
||||
exports[`components/table/TableHeaderMenu should match snapshot, title column 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -257,6 +257,7 @@ exports[`components/table/TableHeaderMenu should match snapshot, title column 1`
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
<div
|
||||
class="menu-spacer hideOnWidescreen"
|
||||
|
@ -84,7 +84,7 @@ exports[`components/viewHeader/emptyCardButton return EmptyCardButton and Set Te
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -39,7 +39,7 @@ exports[`components/viewHeader/filterComponent return filterComponent 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -230,7 +230,7 @@ exports[`components/viewHeader/filterComponent return filterComponent and add Fi
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -435,7 +435,7 @@ exports[`components/viewHeader/filterComponent return filterComponent and click
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -612,7 +612,7 @@ exports[`components/viewHeader/filterComponent return filterComponent and filter
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -19,7 +19,7 @@ exports[`components/viewHeader/filterEntry return filterEntry 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -193,7 +193,7 @@ exports[`components/viewHeader/filterEntry return filterEntry and click on delet
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -353,7 +353,7 @@ exports[`components/viewHeader/filterEntry return filterEntry and click on doesn
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -513,7 +513,7 @@ exports[`components/viewHeader/filterEntry return filterEntry and click on inclu
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -673,7 +673,7 @@ exports[`components/viewHeader/filterEntry return filterEntry and click on is em
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -833,7 +833,7 @@ exports[`components/viewHeader/filterEntry return filterEntry and click on is no
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -979,7 +979,7 @@ exports[`components/viewHeader/filterEntry return filterEntry and click on statu
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -16,7 +16,7 @@ exports[`components/viewHeader/filterValue return filterValue 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -23,7 +23,7 @@ exports[`components/viewHeader/newCardButton return NewCardButton 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -31,6 +31,7 @@ exports[`components/viewHeader/newCardButton return NewCardButton 1`] = `
|
||||
<div
|
||||
class="menu-options"
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
<div
|
||||
aria-label="Empty card"
|
||||
@ -146,7 +147,7 @@ exports[`components/viewHeader/newCardButton return NewCardButton and addCard 1`
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -154,6 +155,7 @@ exports[`components/viewHeader/newCardButton return NewCardButton and addCard 1`
|
||||
<div
|
||||
class="menu-options"
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
<div
|
||||
aria-label="Empty card"
|
||||
@ -269,7 +271,7 @@ exports[`components/viewHeader/newCardButton return NewCardButton and addCardTem
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -277,6 +279,7 @@ exports[`components/viewHeader/newCardButton return NewCardButton and addCardTem
|
||||
<div
|
||||
class="menu-options"
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
<div
|
||||
aria-label="Empty card"
|
||||
|
@ -31,7 +31,7 @@ exports[`components/viewHeader/newCardButtonTemplateItem return NewCardButtonTem
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -165,7 +165,7 @@ exports[`components/viewHeader/newCardButtonTemplateItem return NewCardButtonTem
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -334,7 +334,7 @@ exports[`components/viewHeader/newCardButtonTemplateItem return NewCardButtonTem
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -468,7 +468,7 @@ exports[`components/viewHeader/newCardButtonTemplateItem return NewCardButtonTem
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect left"
|
||||
class="Menu noselect left "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -19,7 +19,7 @@ exports[`components/viewHeader/viewHeaderActionsMenu return menu 1`] = `
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -116,7 +116,7 @@ exports[`components/viewHeader/viewHeaderActionsMenu return menu and verify call
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -213,7 +213,7 @@ exports[`components/viewHeader/viewHeaderActionsMenu return menu and verify call
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -21,7 +21,7 @@ exports[`components/viewHeader/viewHeaderGroupByMenu For viewType table render o
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -208,7 +208,7 @@ exports[`components/viewHeader/viewHeaderGroupByMenu For viewType table render o
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -395,7 +395,7 @@ exports[`components/viewHeader/viewHeaderGroupByMenu return groupBy menu 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -403,6 +403,7 @@ exports[`components/viewHeader/viewHeaderGroupByMenu return groupBy menu 1`] = `
|
||||
<div
|
||||
class="menu-options"
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
<div
|
||||
aria-label="Status"
|
||||
@ -561,7 +562,7 @@ exports[`components/viewHeader/viewHeaderGroupByMenu return groupBy menu, hideEm
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -16,7 +16,7 @@ exports[`components/viewHeader/viewHeaderPropertiesMenu return properties menu 1
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
@ -24,6 +24,7 @@ exports[`components/viewHeader/viewHeaderPropertiesMenu return properties menu 1
|
||||
<div
|
||||
class="menu-options"
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
<div
|
||||
aria-label="Status"
|
||||
@ -186,7 +187,7 @@ exports[`components/viewHeader/viewHeaderPropertiesMenu return properties menu w
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -16,7 +16,7 @@ exports[`components/viewHeader/viewHeaderSortMenu return sort menu 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="Menu noselect bottom"
|
||||
class="Menu noselect bottom "
|
||||
>
|
||||
<div
|
||||
class="menu-contents"
|
||||
|
@ -253,23 +253,29 @@ const ViewMenu = (props: Props) => {
|
||||
/>))}
|
||||
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
|
||||
<Menu.Separator/>
|
||||
{!props.readonly &&
|
||||
</BoardPermissionGate>
|
||||
{!props.readonly &&
|
||||
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
|
||||
<Menu.Text
|
||||
id='__duplicateView'
|
||||
name={duplicateViewText}
|
||||
icon={<DuplicateIcon/>}
|
||||
onClick={handleDuplicateView}
|
||||
/>
|
||||
}
|
||||
{!props.readonly && views.length > 1 &&
|
||||
</BoardPermissionGate>
|
||||
}
|
||||
{!props.readonly && views.length > 1 &&
|
||||
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
|
||||
<Menu.Text
|
||||
id='__deleteView'
|
||||
name={deleteViewText}
|
||||
icon={<DeleteIcon/>}
|
||||
onClick={handleDeleteView}
|
||||
/>
|
||||
}
|
||||
{!props.readonly &&
|
||||
</BoardPermissionGate>
|
||||
}
|
||||
{!props.readonly &&
|
||||
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
|
||||
<Menu.SubMenu
|
||||
id='__addView'
|
||||
name={addViewText}
|
||||
@ -300,8 +306,8 @@ const ViewMenu = (props: Props) => {
|
||||
onClick={handleAddViewCalendar}
|
||||
/>
|
||||
</Menu.SubMenu>
|
||||
}
|
||||
</BoardPermissionGate>
|
||||
</BoardPermissionGate>
|
||||
}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user