diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 000000000..f7eca26a6 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1 @@ +repo_token: ajmTWjgPlMcmueSxBUkdlLinSXOre9XdK diff --git a/.env.sample b/.env.sample new file mode 100644 index 000000000..0ed160dff --- /dev/null +++ b/.env.sample @@ -0,0 +1,4 @@ +GATSBY_ALGOLIA_APP_ID= +GATSBY_ALGOLIA_SEARCH_KEY= +ALGOLIA_ADMIN_KEY= +BUILD_ENV=LOCAL \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index da448446c..f4c7669b1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -16,8 +16,10 @@ module.exports = { ignorePatterns: ['*.scss', '*.md'], extends: [ 'airbnb-base', - 'plugin:prettier/recommended', 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + 'plugin:comment-length/recommended', + 'plugin:jsdoc/recommended', ], globals: { Atomics: 'readonly', @@ -28,7 +30,7 @@ module.exports = { ecmaVersion: 2018, sourceType: 'module', }, - plugins: ['@typescript-eslint'], + plugins: ['@typescript-eslint', 'jsdoc'], settings: { 'import/extensions': ['.js', '.ts'], 'import/parsers': { @@ -44,20 +46,23 @@ module.exports = { }, }, rules: { - indent: [1, 4, { SwitchCase: 1 }], // Conflict with Prettier - quotes: [2, "single", { "avoidEscape": true }], - 'jsx-quotes': [2, 'prefer-single'], + indent: [2, 4, { SwitchCase: 1 }], // Conflict with Prettier + quotes: [2, 'single', { avoidEscape: true }], + 'no-tabs': ['error', { allowIndentationTabs: true }], + 'jsx-quotes': [2, 'prefer-double'], '@typescript-eslint/explicit-function-return-type': [0], '@typescript-eslint/no-explicit-any': [0], '@typescript-eslint/no-unused-vars': [0], 'import/prefer-default-export': 0, + 'no-use-before-define': 'off', + '@typescript-eslint/no-use-before-define': ['off'], // do not complain when importing js related files without extension, // Typescript should handle this. 'import/extensions': [0], 'import/no-extraneous-dependencies': [ 'error', { - devDependencies: ['**/*.spec.ts'], + devDependencies: ['**/*.spec.{ts,tsx}'], }, ], 'import/no-absolute-path': [0], @@ -68,5 +73,16 @@ module.exports = { 'no-continue': 0, 'max-classes-per-file': 0, 'class-methods-use-this': 0, + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': ['error'], + 'no-param-reassign': 0, + 'comment-length/limit-multi-line-comments': [ + 'warn', + { + maxLength: 90, + ignoreUrls: true, + }, + ], + 'jsdoc/check-tag-names': 0, }, }; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..91f30eb24 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +static/* linguist-documentation diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..b7f6db664 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,67 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '26 1 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..090f45fe9 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,102 @@ + +name: DeployDocs + +# Controls when the action will run. Triggers the workflow on push to main branch +# events but only for the main branch +on: + push: + branches: + # Push events on `main` branch + - main + - '[0-9]+.[0-9]+.[0-9]+' + + paths: + - 'static/typedoc/**' + - 'docs/src/**' + - 'gatsby-config.js' + + # For manually triggering the build + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "deploy" + deploy: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # ENV variables that will be used + env: + GH_TOKEN: ${{ secrets.GATSBY_PUBLISH_SECRET_KEY }} + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # extract branch name + - name: Extract branch name + run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + id: extract_branch + + # Add build env for Prod + - name: Add build Env for Prod + if: ${{ env.BRANCH_NAME == 'release' }} + run: echo "BUILD_ENV=PROD" >> $GITHUB_ENV + + # Add build env for Dev/Staging + - name: Add build Env for Dev/Staging + if: ${{ env.BRANCH_NAME == 'main' }} + run: echo "BUILD_ENV=DEV" >> $GITHUB_ENV + + # Check the branch is new release versions + - name: Check branch name for release versions + id: check-release-brnch-version + run: | + if [[ ${{ env.BRANCH_NAME }} =~ ^[0-9]+.[0-9]+.[0-9]+$ ]]; then + echo ::set-output name=match::true + fi + + # extract destination dir + - name: Extract destination dir name + id: extract-destination-dir + uses: actions/github-script@v4 + env: + BRANCH_NAME: '${{env.BRANCH_NAME}}' + with: + result-encoding: string + script: | + const branch = process.env.BRANCH_NAME + if (branch === 'release') { + return 'release' + } + if (branch === 'main') { + return 'dev' + } + return branch.match(/[0-9]+.[0-9]+/) ? branch.match(/[0-9]+.[0-9]+/).toString() : branch + + # Add build env for release versions + - name: Add build Env for Prod + if: steps.check-release-brnch-version.outputs.match == 'true' + run: | + echo "BUILD_ENV=PROD_VERSIONING" >> $GITHUB_ENV + echo "BUILD_DIR=${{steps.extract-destination-dir.outputs.result}}" >> $GITHUB_ENV + + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + # Use NodeJS v12.18.3 + - uses: actions/setup-node@v2 + with: + node-version: '12.18.3' + + # Run npm install + - name: Run npm install + run: npm install + + # Deploy on github pages + - name: build + run: npm run build:gatsby + + # Deploy on github pages + - name: publish-release-version + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public + destination_dir: ./${{ steps.extract-destination-dir.outputs.result }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 39f2b3491..a4b9d96e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,53 +5,62 @@ name: CI # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the main branch on: - push: - branches: [ main ] - pull_request: - branches: [ main ] + push: + branches: [main, release] + pull_request: + branches: [main, release] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - # Use NodeJS v12.18.3 - - uses: actions/setup-node@v2 - with: - node-version: '12.18.3' - - # Run npm install - - name: Run npm install - run: npm install - - # Runs linter - - name: Run linter - run: npm run lint - - # Runs tests - - name: Run tests - run: npm test - - # Collect coverage report - - uses: 5monkeys/cobertura-action@master - with: - path: coverage/cobertura-coverage.xml - repo_token: ${{ secrets.GITHUB_TOKEN }} - minimum_coverage: 0 - - # Runs TypeScript compiler - - name: Run TypeScript compiler - run: npm run tsc - - # Collect artifacts - - uses: actions/upload-artifact@v2 - with: - name: test-coverage - path: coverage/ + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + # Use NodeJS v14.19.0 + - uses: actions/setup-node@v2 + with: + node-version: '20.16.0' + + # Run npm install + - name: Run npm install + run: npm install --legacy-peer-deps + + # Runs linter + - name: Run linter + run: npm run lint + + # Runs tests + - name: Run tests + run: npm test + + # Collect coverage report + - uses: 5monkeys/cobertura-action@master + continue-on-error: true + with: + path: coverage/sdk/cobertura-coverage.xml + repo_token: ${{ secrets.GITHUB_TOKEN }} + minimum_coverage: 0 + + # Runs TypeScript compiler + - name: Run TypeScript compiler + run: npm run tsc + + # Run size check + - name: Run npm check-size + run: npm run check-size + + # Collect artifacts + - uses: actions/upload-artifact@v2 + with: + name: test-coverage + path: coverage/ + + # Create new package release + - name: Publish dev package + run: npx pkg-pr-new publish diff --git a/.github/workflows/publishToNPM.yml b/.github/workflows/publishToNPM.yml new file mode 100644 index 000000000..bbaa6868a --- /dev/null +++ b/.github/workflows/publishToNPM.yml @@ -0,0 +1,81 @@ +# This is a basic workflow to help you get started with Actions + +name: publishToNPM + +# Controls when the action will run. Triggers the workflow on pull request +# event +on: workflow_dispatch + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-node@v3 + with: + node-version: '16.19.0' + registry-url: 'https://registry.npmjs.org' + + - name: Get Branch Name + id: branch_name + run: echo "::set-output name=BRANCH_NAME::$(git branch --show-current)" + + - name: Get Latest Tag + id: latest_tag + run: | + echo "Getting Git tag list.." + git fetch --depth=1 origin +refs/tags/*:refs/tags/* | sort -V + + echo "Getting the latest Git tag." + git tag -l | sort -V | tail -n 1 + + # Get the latest Git tag and set it as an output variable + echo "::set-output name=LATEST_TAG::$(git tag -l | sort -V | tail -n 1)" + + # Run npm install + - name: Run npm install + run: npm install --legacy-peer-deps + + # Runs docgen and publish + - name: Run docgen and publish + run: | + BRANCH_NAME="${{ steps.branch_name.outputs.BRANCH_NAME }}" + npm run docgen + if [ "$BRANCH_NAME" = "release" ]; then + echo "publish release" + npm run publish-prod + elif [ "$BRANCH_NAME" = "main" ]; then + echo "publish dev" + npm run publish-dev + else + echo "Stopping workflow for branch $BRANCH_NAME" + exit 1 + fi + + env: + NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + + - name: Create Draft Release + if: success() && steps.branch_name.outputs.BRANCH_NAME == 'release' + run: | + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "Current Version: $CURRENT_VERSION" + + PREV_TAG=$(git tag -l | sort -V | tail -n 1) + echo "LAST TAG: $PREV_TAG" + + # Extract commit messages between previous and current versions + COMMIT_MESSAGES=$(git log --pretty=format:"%s" $PREV_TAG..HEAD | uniq | sed -E 's/\(#[0-9]+\)//g') + echo "commit : $COMMIT_MESSAGES" + + # Create draft Release + gh release create "$CURRENT_VERSION" -t "Release $CURRENT_VERSION" -n "$COMMIT_MESSAGES" -d + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.gitignore b/.gitignore index 5b9cd6a7b..72a337d7c 100644 --- a/.gitignore +++ b/.gitignore @@ -85,6 +85,7 @@ dist lib public/ docs/public/ +cjs # Gatsby files .cache/ @@ -109,3 +110,6 @@ docs/public/ # Code editors or IDEs .vscode/ + +# Don't ignore examples public folder +!/examples/public diff --git a/.npmignore b/.npmignore index 739fe9454..f3b505370 100644 --- a/.npmignore +++ b/.npmignore @@ -1,2 +1,5 @@ docs - +.cache +coverage +.coveralls +.github diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..f4e1e4ad0 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry = 'https://registry.npmjs.org/' diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 750de74e4..000000000 --- a/.prettierrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - bracketSpacing: true, - htmlWhitespaceSensitivity: 'css', - jsxBracketSameLine: false, - semi: true, - singleQuote: true, - tabWidth: 4, - trailingComma: 'all', -}; diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..3a248a9f6 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,10 @@ +{ + "bracketSpacing": true, + "htmlWhitespaceSensitivity": "css", + "jsxBracketSameLine": false, + "semi": true, + "singleQuote": true, + "tabWidth": 4, + "trailingComma": "all", + "printWidth": 100 +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..9d51c1f25 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,126 @@ +# Changelog + +Please find the comprehensive list of changes for ThoughtSpot releases and SDK [here](https://developers.thoughtspot.com/docs/?pageid=whats-new) +This project follows Semantic Versioning. + +## Unreleased + +### New Features +- Set of new Host events to drive interactions on the embed programatically + +## 1.14.1 (08-31-2022) +- Fixed "not logged in" message showing up on "SearchEmbed" with AuthType.None. + +## 1.14.0 (08-29-2022) +- [AuthType.AuthServer] Now uses `POST` call to log the user in using the bearer token. +- `liveboardV2` flag on `LiveboardEmbed` to try out the LiveboardV2 experience. + +## 1.13.0 (07-19-2022) +- Release to support TS version 8.5.0.cl +- Please check the full list of changes [here](https://developers.thoughtspot.com/docs/?pageid=embed-sdk-changelog) +## 1.12.1 (06-21-2022) +### Fixed +- Search embed beta warning check for TS cloud releases +## 1.12.0 (06-21-2022) +- Release to support TS version 8.4.0.cl +- Please check the full list of changes [here](https://developers.thoughtspot.com/docs/?pageid=embed-sdk-changelog) + +## 1.11.2 (06-10-2022) +### Fixed +- Typescript build that was affecting some Angular project configurations + +## 1.11.1 (05-30-2022) +### Fixed +- Whitelabeling - new [action](https://developers.thoughtspot.com/docs/typedoc/enums/Action.html#ReportError) for the ability to turn off TS specific error reporting by end users. + +## 1.11.0 (05-20-2022) +- Release to support TS version 8.3.0.cl +- Please check the full list of changes [here](https://developers.thoughtspot.com/docs/?pageid=embed-sdk-changelog) + +## 1.10.4 (05-06-2022) +### New Features +- Config option `detectCookieAccessSlow` when doing Basic|AuthServer auth. [Ref doc](https://developers.thoughtspot.com/docs/typedoc/interfaces/EmbedConfig.html#detectCookieAccessSlow) + +## 1.10.3 (05-04-2022) +### Fixed +- `logout` method works consistently on multiple TS releases + +## 1.10.2 (05-01-2022) +### New features +- Ability to configure `redirectPath` on the origin when using SSO auth. [Ref doc](https://developers.thoughtspot.com/docs/typedoc/interfaces/EmbedConfig.html#redirectPath) + +## 1.10.1 (05-01-2022) + +### New features +- `logout` method exposed from the SDK. This can be used to log the user out. [Ref doc](https://developers.thoughtspot.com/docs/typedoc/modules.html#logout) + +### Updated +- When login fails the user is presented with a `Not logged in` message, which is configurable using `loginFailedMessage` property on `init`. [Ref doc](https://developers.thoughtspot.com/docs/typedoc/interfaces/EmbedConfig.html#loginFailedMessage) +- `init` now returns a event emitter which can be used to listen to Login `failures` and `success`. [Ref doc](https://developers.thoughtspot.com/docs/typedoc/modules.html#init) + +## 1.10.0 (04-22-2022) + +- Release to support TS version 8.2.0.cl +- Please check the full list of changes [here](https://developers.thoughtspot.com/docs/?pageid=embed-sdk-changelog) + +## 1.9.5 (04-06-2022) + +### New Features +- `locale` param to set Locale/language for the embedded view. + + +## 1.9.4 (04-06-2022) + +### Fixed +- [React] `className` should be forwarded to the iframe container div. + + +## 1.9.3 (03-22-2022) + +### New Features +- `disableLoginRedirect` option in `EmbedConfig` + +## 1.9.2 (03-17-2022) + +### New Features +- Ability to trigger events on React components + - Added new `useEmbedRef` hook, check README for usage. + +### Fixed + +- Typings for `on*` event handlers for React components + + +## 1.9.1 (03-15-2022) + +### New Features + +- `visibleVizs` option in the `LiveboardEmbed` +- `LiveboardRendered` new `EmbedEvent` emitted when a liveboard completes rendering. + + +## 1.9.0 + +- Release to support TS version 8.1.0.cl +- Please check the full list of changes [here](https://developers.thoughtspot.com/docs/?pageid=embed-sdk-changelog) + + +## 1.8.1 + +### Bug fix + +- `authEndpoint` in AuthServer authentication scheme was failing because of a missing `await`. + +## 1.8.0 + +### Breaking Changes + +- `autoLogin` option in `init` method is now by default `false` instead of `true`. + +### New Features + +- `init` method now returns the `authPromise` which resolves when auth is complete. + +## 1.7.0 (and earlier) + +- Please check the full list of changes [here](https://developers.thoughtspot.com/docs/?pageid=embed-sdk-changelog) diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..6f2e4ff41 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,3 @@ +@ashubham +@pushkar100 +@abdulasulaiman diff --git a/Contributing.md b/Contributing.md new file mode 100644 index 000000000..6f204508b --- /dev/null +++ b/Contributing.md @@ -0,0 +1,92 @@ +## Contribution guide + +### Requirements + +- NodeJS 18.x / npm 9.x + +### Cloning and making changes + +``` +$ git clone https://github.com/thoughtspot/visual-embed-sdk +$ npm i --legacy-peer-deps +``` + +All the code is in the `src` directory. + +### Code structure + +#### Components + +All components are exposed as Classes which extend from the `TsEmbed` class. Blink V1 based components +extend from `V1Embed` class. These based classes are defined in `src/embed/ts-embed.ts`. + +The named components are exposed from the named files `src/embed/app.ts`, `src/embed/liveboard.ts` etc. + +#### Events + +There are two kinds of events `HostEvents` and `EmbedEvents`. + +- HostEvents: Host application => ThoughtSpot. +- EmbedEvents: ThoughtSpot => Host application. + +All the events are listed in `src/types.ts`. + +#### Actions + +These are all the actions in the TS application, like "Save", "MakeACopy" etc. Listed in `src/types.ts`. + +### Documentation + +All publicly exposed methods, events, actions, classes, enums and interfaces should have JSDoc clearly explaining their +purpose and usage. The doc should have the following tags: + +- Description +- @params (if a method which takes params) +- @return (if a method which returns a value) +- @version (Version this member is available since, both TS and the SDK version) +- @example (an example of how this member could be used in code). + +Check [this](https://github.com/thoughtspot/visual-embed-sdk/blob/main/src/embed/base.ts#L143_ for example. + + +### Building and Testing + +Once you have made changes, we should add a test to make sure the change is tested. If the test is not added +and the coverage falls below the threshold the PR will fail sanity. + +All tests are written using `jest`. And are written in a file named `.spec.ts` corresponding to any module named +`file`. This file is colocated with the module. + +The tests can be run using: + +``` +$ npm test +``` + +#### Testing an unreleased version + +To test an unreleased version of the SDK you have a few options: + +*Locally:* +- Use `npm link`, to test the sdk against a local application. + +*Codesanbox:* +- Publish a new version of the SDK with a tag. +- To publish you may need to be given permission, by adding yourself to the `developers` group on `npm`. + - Set the version in the `package.json` file to a version with a scheme like `1..0-.`. + For eg, `1.21.0-mytest.2`. + - `npm publish --tag mytest`. + +#### Testing against a live application. + +There are a few options here: + +1. Use with this [example](https://github.com/thoughtspot/visual-embed-sdk/tree/main/examples/app-with-custom-actions) app. +2. Fork and use the embed [codesandbox](https://codesandbox.io/s/big-tse-react-demo-i4g9xi) +3. The clover bank demo [app](https://github.com/ts-blink/clover-bank). + +Once the changes are made and tests are written, raise a PR against the `main` branch of this repo. Please make sure to include +the `JIRA` id in the commit message. Request members on the ThoughtSpot Embedded team to review your PR. The sanity tests should run automatically. +Once everything is complete, you should be able to merge the PR. + + diff --git a/LICENSE b/LICENSE index eff18030d..71f37868a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,22 @@ -MIT License -Copyright (c) 2020 ts-blink +- ThoughtSpot Development Tools End User License Agreement -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THIS THOUGHTSPOT DEVELOPMENT TOOLS END USER LICENSE AGREEMENT (“EULA”) FORMS A BINDING AGREEMENT BETWEEN YOU INDIVIDUALLY OR THE BUSINESS ENTITY OR PUBLIC AGENCY ON WHOSE BEHALF YOU ARE ACCEPTING THIS AGREEMENT (“COMPANY”) AND THOUGHTSPOT, INC. (“THOUGHTSPOT”). THIS EULA DESCRIBES THE RIGHTS AND OBLIGATIONS OF COMPANY AND THOUGHTSPOT GOVERNING THE USE OF ANY APPLICATION PROGRAMMING INTERFACE, CONNECTOR, SOFTWARE DEVELOPMENT KIT, CODE SNIPPET, SAMPLE CODE, FREE CUSTOM USER INTERFACE OR VISUALIZATION, SAMPLE DATA, AND THE CORRESPONDING DOCUMENTATION FOR EACH, ANY UPDATES AND UPGRADES THERETO, AND ANY MODIFICATIONS, ENHANCEMENTS, OR IMPROVEMENTS, OF ANY OF THE FOREGOING, MADE AVAILABLE BY THOUGHTSPOT TOGETHER WITH THIS EULA (EACH A “TOOL” AND COLLECTIVELY “TOOLS”). +THIS EULA IS ACCEPTED BY: (1) INDICATING ACCEPTANCE OF THESE TERMS BY CLICKING “SUBMIT,” “ACCEPT” OR A SIMILAR BUTTON WHEN THIS EULA IS REFERENCED ON A WEB PAGE TO RECEIVE A TOOL; OR (2) DOWNLOADING, INSTALLING, OR USING, ANY PORTION OF THE TOOL. THE INDIVIDUAL ACCEPTING THIS AGREEMENT ON BEHALF OF COMPANY REPRESENTS AND WARRANTS THAT HE OR SHE: (A) IS AN EMPLOYEE, CONTRACTOR, OR AGENT OF, AND HAS THE AUTHORITY TO REPRESENT, COMPANY; AND (B) HAS READ AND UNDERSTANDS ALL THE PROVISIONS OF THIS AGREEMENT. IF COMPANY DOES NOT WISH TO ACCEPT THIS AGREEMENT, OR THE INDIVIDUAL ACCEPTING THE AGREEMENT DOES NOT HAVE AUTHORITY TO BIND COMPANY TO THIS AGREEMENT, THEN DO NOT CLICK OR SIGN TO ACCEPT THIS AGREEMENT, OR DOWNLOAD, INSTALL, OR USE, ANY TOOL. +In the event of any conflict between the terms of this EULA and a signed agreement between Company and ThoughtSpot, the terms of the signed agreement will apply. +ACKNOWLEDGMENT. ThoughtSpot provides the Tool to Company “as is” and “as available” and as an accommodation to Company to more quickly connect third-party software or services with, utilize sample data or code on, or utilize sample data sets or other materials with, the search and analytics ThoughtSpot Cloud subscription service or ThoughtSpot Application licensed software, to which Company must have purchased the necessary use rights pursuant to a separate purchase agreement (“Agreement”). ThoughtSpot may at any time remove Company’s access to any Tool or terminate the availability of a Tool without any liability to Company or any third party. In the event of termination, Company must remove and destroy all copies of the affected Tool, including all backup copies from all devices Company owns, possesses or controls and on which the Tool is installed. +LICENSE SCOPE. Subject to Company’s compliance with this EULA, ThoughtSpot hereby grants to Company a royalty-free, sub-licensable, transferable, non-exclusive, worldwide right and license to use, reproduce, display, perform, import and export, the Tool. The Tool is licensed, not sold. +RESTRICTIONS. Company will not (and has no license to): (a) use the Tool except as permitted in this EULA; (b) sell, resell, license, sublicense, rent, lease, encumber, lend, distribute, transfer, or provide a third party with access to the Tool; (c) modify, or create derivative works of the Tool; (d) circumvent or remove by any means any click-accept or copy protection used by ThoughtSpot in connection with the Tool; (e) use the Tool to conduct competitive research, to develop a product that is competitive with any ThoughtSpot product offering, or otherwise if Company is a competitor to ThoughtSpot, or to assert, authorize, assist, or encourage a third-party to assert, against ThoughtSpot or any of its affiliates, customers, vendors, business partners, or licensors, any patent or other intellectual property claim regarding ThoughtSpot products or services; (f) publicly disseminate any performance or security vulnerability test (including a penetration test) results or analysis related to or derived from the Tool; (g) use the Tool to create a product that converts ThoughtSpot products’ file formats for use with data analysis, machine learning, or data visualization software that is not the property of ThoughtSpot; (h) use the Tool to access ThoughtSpot products in a manner not authorized by the Agreement or this EULA; (i) use the Tool in any manner that violates any applicable laws or regulations; or (j) to the extent that the Tool includes a third-party application programming interface, then Company will not modify, distribute, or use, the Tool with anything other than to connect the intended corresponding third-party technology to ThoughtSpot’s products. Company will not cause, encourage, or permit any other person or entity under its control from taking any actions that Company is prohibited from taking under this Agreement. Before Company engages in any of the foregoing acts that it believes it may be entitled to, it will provide ThoughtSpot with 30 days’ prior notice to legal@thoughtspot.com, and provide reasonably requested information to allow ThoughtSpot to assess Company’s claim. ThoughtSpot may, in its discretion, provide alternatives that reduce adverse impacts to ThoughtSpot’s intellectual property or other rights. +OPEN SOURCE COMPONENTS. A Tool may include one or more open source software components provided under separate license terms which can be found in the open source disclosure file provided with or within a Tool download. Notwithstanding anything herein to the contrary, open source software is licensed to Company under such OSS’s own applicable license terms, which can be found in the attribution file. The open source license terms are consistent with the license granted in this EULA, and may contain additional rights benefiting Company. The open source license terms shall take precedence over this EULA to the extent that this EULA imposes greater restrictions on Company than the applicable open source license terms. To the extent the license for any open source software requires ThoughtSpot to make available to Company the corresponding source code and/or modifications, Company may obtain a copy of the applicable source files by sending a written request, with Company’s name and address to: ThoughtSpot, Inc., 910 Hermosa Court, Sunnyvale, California 94085, United States of America. All requests should clearly specify: Open Source Files Request, Attention: General Counsel. This offer to obtain a copy of such source files is valid for three years from the date Company acquired the applicable Tool. +THIRD-PARTY COMPONENTS. In addition to open source components, a Tool may include one or more components licensed by a third party (a “Component”) (e.g., an application programming interface or a sample data set). To the extent that third-party license requirements apply to a third-party component in a Tool, such additional license terms will be provided in the open source disclosure file provided with or within a Tool download. Third-party license terms shall take precedence over this EULA to the extent that they impose additional restrictions or limitations on Company than the license provided herein for download and use of a Component. The parties agree that: (a) to the extent that the terms between Company and the third party for use of a third-party technology accessed by the Component are more restrictive, such terms shall apply to Company’s use of the Component; (b) ThoughtSpot, and not the third party, is responsible for the Component including, without limitation, for any warranties, maintenance, and support thereof, and the third party does not warrant the Component’s accuracy, reliability, completeness, usefulness, non-infringement, or quality of the Component, and will not be liable for any losses or damages of any kind, including lost profits or other indirect or consequential damages, relating to use of or reliance on the Component; and (c) the third party owns all right, title, and interest in and to the Component, including all intellectual property rights therein. +DISCLAIMER OF WARRANTIES. THOUGHTSPOT DISCLAIMS RESPONSIBILITY FOR ANY HARM RESULTING FROM COMPANY’S USE OF THIS TOOL. THOUGHTSPOT DISCLAIMS TO THE FULLEST EXTENT PERMITTED, ALL GUARANTEES AND EXPRESS, IMPLIED AND STATUTORY WARRANTIES, INCLUDING WITHOUT LIMITATION THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT OF PROPRIETARY RIGHTS, AND ANY WARRANTIES REGARDING THE AVAILABILITY, SECURITY, RELIABILITY, TIMELINESS AND PERFORMANCE OF THIS TOOL. COMPANY DOWNLOADS AND USES THIS TOOL AT ITS OWN DISCRETION AND RISK, AND COMPANY IS SOLELY RESPONSIBLE FOR ANY DAMAGES TO ITS HARDWARE DEVICES OR LOSS OF DATA THAT RESULT FROM THE DOWNLOAD OR USE OF THIS TOOL. +INTELLECTUAL PROPERTY. ThoughtSpot and its licensors own all right, title, and interest in and to this Tool, including all intellectual property or other proprietary rights worldwide therein, including patent, trademark, service mark, copyright, trade secret, know-how, moral right, and any other intellectual and intangible property rights, including all continuations, continuations in part, applications, renewals, and extensions of any of the foregoing, whether registered or unregistered. All rights not expressly granted herein are reserved. +INDEMNIFICATION. Company will indemnify and hold harmless ThoughtSpot from any claim made by any third party due to or arising directly or indirectly out of its conduct or any connection with its use of this Tool, violation of the terms herein, and any violation of any applicable law or regulation. ThoughtSpot reserves the right, at its own expense, to assume the exclusive defense and control of any manner subject to indemnification by Company, but doing so will not excuse Company’s indemnity obligations. +LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL THOUGHTSPOT AND ITS LICENSORS BE LIABLE FOR ANY LOST PROFITS OR BUSINESS OPPORTUNITIES, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, OR ANY OTHER INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES UNDER ANY THEORY OF LIABILITY, WHETHER BASED IN CONTRACT, TORT, NEGLIGENCE, PRODUCT LIABILITY, OR OTHERWISE. BECAUSE SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE PRECEDING LIMITATION MAY NOT APPLY TO COMPANY. THOUGHTSPOT’S AND ITS LICENSORS’ LIABILITY UNDER THIS EULA WILL NOT, IN ANY EVENT, EXCEED $10 USD. THE FOREGOING LIMITATIONS SHALL APPLY REGARDLESS OF WHETHER THOUGHTSPOT OR ITS LICENSORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND REGARDLESS OF WHETHER ANY REMEDY FAILS OF ITS ESSENTIAL PURPOSE. +LEGAL COMPLIANCE. A Tool may be subject to United States export control regulations. Without prior authorization from the United States government, Company shall not use the Tool for, and shall not permit the Tool to be used for, any purposes prohibited by United States law, including, without limitation, for any prohibited development, design, manufacture or production of missiles or nuclear, chemical or biological weapons. Without limiting the foregoing, Company represents and warrants that: (a) Company is not, and is not acting on behalf of, any person who is a citizen, national, or resident of, or who is controlled by the government of, Cuba, Iran, North Korea, Sudan, or Syria, the Crimea Region, or any other country to which the United States has prohibited export transactions; (b) Company is not located in a country that is subject to a U.S. Government embargo, or that has been designated by the U.S. Government as a “terrorist supporting” country; and (c) Company is not, and is not acting on behalf of, any person or entity listed on the U.S. Treasury Department list of Specially Designated Nationals and Blocked Persons, or the U.S. Commerce Department Denied Persons List, Unverified List, or Entity List or any other U.S. Government list of prohibited or restricted parties unless authorized by license or regulation. In addition, Company is responsible for complying with any local Law that may impact Company’s right to import, export, or use the Tool. +U.S. GOVERNMENT USE. If a Tool provided under this Agreement is software, then it is commercial computer software developed exclusively at private expense. Unless otherwise set forth in this Agreement, use, duplication, and disclosure by civilian agencies of the U.S. Government will not exceed those minimum rights set forth in FAR 52.227-19(c) or successor regulations. Use, duplication, and disclosure by U.S. Department of Defense agencies is subject solely to the license terms contained in this EULA, as stated in DFARS 227.7202 or successor regulations. U.S. Government rights will apply only to the specific agency and program for which the Application is obtained. +SUPPORT. If Company has a support question regarding a Tool, use ThoughtSpot’s standard support process applicable to Company’s access to ThoughtSpot Cloud or license to the ThoughtSpot Application to receive assistance. +COMPLAINTS. Company agrees to direct any questions, complaints, or claims, with respect to the Tools to legal@thoughtspot.com. +CONTRACTING PARTIES. The contracting party is ThoughtSpot, Inc., 910 Hermosa Court, Sunnyvale, California 94085, the United States of America. This EULA is governed by the laws of the State of California, United States of America, unless mandated by other law. The United Nations Convention for the International Sale of Goods shall not apply. +ENTIRE AGREEMENT. This EULA represents the entire agreement between the parties with respect to the Tool, and supersedes any prior or contemporaneous oral or written agreements concerning the subject matter contained herein. +INTERPRETATION. No failure of either party to exercise or enforce any of its rights under this EULA will act as a waiver of those rights. This EULA may only be modified, or any rights under it waived, by a written agreement executed by the party against which it is asserted. If any provision of this EULA is found illegal or unenforceable, it will be enforced to the maximum extent permissible, and the legality and enforceability of the other provisions of this EULA will not be affected. Any translation of this EULA is done for local requirements and in the event of a dispute between the English and any non-English version, the English version of this EULA shall govern. If Company is located in the province of Quebec, Canada, the following clause applies: The parties hereby confirm that Company has requested this EULA and all related documents be drafted in English. Les parties ont exige que le present contrat et tous les documents connexes soient rediges en anglais. diff --git a/README.md b/README.md index 142d16c46..593f9893f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,248 @@ -# embed-sdk -ThoughtSpot Embed SDK +

+ ThoughtSpot +

+ +
+ +# ThoughtSpot Visual Embed SDK
[![Coverage Status](https://coveralls.io/repos/github/thoughtspot/visual-embed-sdk/badge.svg?branch=main)](https://coveralls.io/github/thoughtspot/visual-embed-sdk?branch=main) ![npm (scoped with tag)](https://img.shields.io/npm/v/@thoughtspot/visual-embed-sdk) [![](https://data.jsdelivr.com/v1/package/npm/@thoughtspot/visual-embed-sdk/badge?style=rounded)](https://www.jsdelivr.com/package/npm/@thoughtspot/visual-embed-sdk) ![npm](https://img.shields.io/npm/dm/@thoughtspot/visual-embed-sdk?label=npm%20downloads&style=flat-square) ![npm bundle size (scoped)](https://img.shields.io/bundlephobia/minzip/@thoughtspot/visual-embed-sdk?style=flat-square) + + +SDK to embed ThoughtSpot into your web apps. You need a ThoughtSpot account to use the SDK, [click here](https://www.thoughtspot.com/trial?tsref=trialtse) to start a trial. + + * [Installation](#installation) + * [Live Playground](#live-playground) + * [Full API Reference](#full-api-reference) + * [Quick Start](#quick-start) + * [Embedded Search](#embedded-search) + * [Embedded Liveboard & Visualization](#embedded-liveboard--visualization) + * [Embedded Full App](#embedded-full-app) + * [Triggering and Listening to events](#triggering-and-listening-to-events) + * [React Components](#react-components) + * [Search Component](#search-component) + * [Triggering events on React components](#triggering-events-on-react-components--version-192) + * [Contributing](#contributing) + +## Installation + +The SDK is compatible with ThoughtSpot SW version >= 7.1 and ThoughtSpot Cloud. + +Install the Visual Embed SDK from [NPM](https://www.npmjs.com/package/@thoughtspot/visual-embed-sdk): + +``` +npm i @thoughtspot/visual-embed-sdk +``` + +The SDK is written in TypeScript and is also provided both as ES Module (ESM) and Universal Module Definition (UMD) modules, allowing you to use it in a variety of environments. For example,... + +```js +// ESM via NPM +import * as TsEmbedSDK from '@thoughtspot/visual-embed-sdk'; +// OR +import { LiveboardEmbed } from '@thoughtspot/visual-embed-sdk'; + +// NPM ; +// Makes the SDK available on global namespace window.tsembed + +// ES6 from web +import { + LiveboardEmbed, + AuthType, + init, +} from 'https://cdn.jsdelivr.net/npm/@thoughtspot/visual-embed-sdk/dist/tsembed.es.js'; +``` + +
+ +## Live Playground + +Visit our [code playground](https://try-everywhere.thoughtspot.cloud/v2/#/everywhere).

+Start a [free trial](https://www.thoughtspot.com/trial?tsref=trialtse) on your own data. + +
+ +## Full API Reference + +- Thoughtspot Embedded [Docs](https://developers.thoughtspot.com/docs/) +- Please visit our [API reference docs](https://developers.thoughtspot.com/docs/VisualEmbedSdk). +- Comprehensive [CodeSandbox](https://codesandbox.io/s/big-tse-react-demo-i4g9xi?file=/src/App.tsx) + +
+ +## Quick Start + +The ThoughtSpot Embed SDK allows you to embed the ThoughtSpot search experience, +liveboards, visualizations or the even full app version. + +### Embedded Search + +```js +// NPM +import { SearchEmbed, AuthType, init } from '@thoughtspot/visual-embed-sdk'; +// or ES6 +// import { SearchEmbed, AuthType, init } from 'https://cdn.jsdelivr.net/npm/@thoughtspot/visual-embed-sdk/dist/tsembed.es.js'; + +init({ + thoughtSpotHost: '<%=tshost%>', + authType: AuthType.None, +}); + +const searchEmbed = new SearchEmbed(document.getElementById('ts-embed'), { + frameParams: { + width: '100%', + height: '100%', + }, +}); + +searchEmbed.render(); +``` + +### Embedded Liveboard & Visualization + +```js +// NPM +import { LiveboardEmbed, AuthType, init } from '@thoughtspot/visual-embed-sdk'; +// or ES6 +// import { LiveboardEmbed, AuthType, init } from 'https://cdn.jsdelivr.net/npm/@thoughtspot/visual-embed-sdk/dist/tsembed.es.js'; + +init({ + thoughtSpotHost: '<%=tshost%>', + authType: AuthType.None, +}); + +const liveboardEmbed = new LiveboardEmbed( + document.getElementById('ts-embed'), + { + frameParams: { + width: '100%', + height: '100%', + }, + liveboardId: '<%=liveboardGUID%>', + vizId: '<%=vizGUID%>', + }, +}); + +liveboardEmbed.render(); +``` + +### Embedded Full App + +```js +// NPM +import { AppEmbed, Page, AuthType, init } from '@thoughtspot/visual-embed-sdk'; +// or ES6 +// import { AppEmbed, AuthType, init } from 'https://cdn.jsdelivr.net/npm/@thoughtspot/visual-embed-sdk/dist/tsembed.es.js'; + +init({ + thoughtSpotHost: '<%=tshost%>', + authType: AuthType.None, +}); + +const appEmbed = new AppEmbed(document.getElementById('ts-embed'), { + frameParams: { + width: '100%', + height: '100%', + }, + pageId: Page.Data, +}); + +appEmbed.render(); +``` + +### Triggering and Listening to events +```js +// NPM +import { LiveboardEmbed, Page, AuthType, init, EmbedEvent, HostEvent } from '@thoughtspot/visual-embed-sdk'; + +// .. Do init and create a liveboardEmbed object as above. + +liveboardEmbed.render(); + +liveboardEmbed.on(EmbedEvent.LiveboardRendered, () => { + liveboardEmbed.trigger(HostEvent.SetVisibleVizs, ['viz1', 'viz2']); +}); +``` + +## React Components + +All the above flavors of embedding are also provided as React components for your convenience. +The constructor options are passed as props and the event listeners can be attached using `on` convention. +

+Checkout a comprehensive working demo [here](https://codesandbox.io/s/big-tse-react-demo-i4g9xi?file=/src/App.tsx) + +### Search Component + +```js +import { init } from '@thoughtspot/visual-embed-sdk'; +import { SearchEmbed } from '@thoughtspot/visual-embed-sdk/react'; + +// If you are using Webpack 4 (which is the default when using create-react-app v4), you would need to import +// the React components using the below: +import { SearchEmbed } from '@thoughtspot/visual-embed-sdk/lib/src/react'; + +init({ + thoughtSpotHost: '<%=tshost%>', + authType: AuthType.None, +}); + +const MyComponent = ({ dataSources }) => { + const onCustomAction = (actionEvent) => { + // Do something with actionEvent. + }; + + return ( + + ); +}; +``` + +### Triggering events on React components (> version 1.9.2) + +```jsx +import { HostEvent } from '@thoughtspot/visual-embed-sdk'; +import { LiveboardEmbed, useEmbedRef } from '@thoughtspot/visual-embed-sdk/react'; + +const MyComponent = () => { + const embedRef = useEmbedRef(); + const onLiveboardRendered = () => { + embedRef.current.trigger(HostEvent.SetVisibleVizs, ['viz1', 'viz2']); + }; + + return ( + + ); +}; +``` + +### + + +## Contributing + +### Local dev server + +How to run the local vite server to test out the sdk. + +``` +$ npm run build +``` + +``` +$ npm run dev +``` + +Goto `http://localhost:2343/local` to check the output. + +Look at `local/index.html` and `local/index.ts` for some starter code. + +
+
+ +Visual-Embed-SDK, © ThoughtSpot, Inc. 2023 diff --git a/custom-typings/reporting.d.ts b/custom-typings/reporting.d.ts new file mode 100644 index 000000000..9092efaaf --- /dev/null +++ b/custom-typings/reporting.d.ts @@ -0,0 +1,10 @@ +interface ReportingObserver { + observe: () => void; + disconnect: () => void; + takeRecords: () => any[]; +} + +declare const ReportingObserver: { + prototype: ReportingObserver; + new (callback: (reports: any[]) => void, options?: { buffered?: boolean }): ReportingObserver; +}; diff --git a/docs/__mock__/file.mock.js b/docs/__mock__/file.mock.js new file mode 100644 index 000000000..e3b91b243 --- /dev/null +++ b/docs/__mock__/file.mock.js @@ -0,0 +1 @@ +module.exports = "test-file-stub" \ No newline at end of file diff --git a/docs/__mock__/gatsby.js b/docs/__mock__/gatsby.js new file mode 100644 index 000000000..37a76ff31 --- /dev/null +++ b/docs/__mock__/gatsby.js @@ -0,0 +1,27 @@ +const React = require("react") +const gatsby = jest.requireActual("gatsby") + +module.exports = { + ...gatsby, + graphql: jest.fn(), + Link: jest.fn().mockImplementation( + // these props are invalid for an `a` tag + ({ + activeClassName, + activeStyle, + getProps, + innerRef, + partiallyActive, + ref, + replace, + to, + ...rest + }) => + React.createElement("a", { + ...rest, + href: to, + }) + ), + StaticQuery: jest.fn(), + useStaticQuery: jest.fn(), +} \ No newline at end of file diff --git a/docs/about-rest-apis.adoc b/docs/about-rest-apis.adoc deleted file mode 100644 index 76ba324fd..000000000 --- a/docs/about-rest-apis.adoc +++ /dev/null @@ -1,5 +0,0 @@ -== REST APIs -ThoughtSpot APIs are documented in the ThoughtSpot Documentation. You can also find details about the APIs and test many of them using Swagger. To access Swagger, first, login as a user with Administrator credentials. Then navigate to https:///external/swagger. You will get a list of all publicly available services. - - -You can click on a header to expand and get the list of services. Clicking on a service name provides more details about the service. diff --git a/docs/authentication.adoc b/docs/authentication.adoc deleted file mode 100644 index 1c2f69af6..000000000 --- a/docs/authentication.adoc +++ /dev/null @@ -1,122 +0,0 @@ -== Authentication -:toc: true - -You can control which type of authentication you use between your client application and ThoughtSpot. - -=== No Authentication - -You can simply not set up authentication. -This would require the user to be _already logged into ThoughtSpot_, before interacting with the client application. -This approach is for testing the client. -Do not use this in a production environment. - -=== SAML SSO - -To avoid showing the ThoughtSpot login page in the iFrame and provide a seamless login experience, you should configure SSO so that your users are automatically authenticated to ThoughtSpot, and the pages are loaded immediately. - -Before you can embed all or part of ThoughtSpot, you must authenticate to ThoughtSpot using SAML with the public REST API call. - -//// -For more information, see https://cloud-docs.thoughtspot.com/admin/ts-cloud/authentication-integration.html[Managing authentication with SAML]. -Note that this does not assign the user to any groups, which must be managed manually or via the APIs. - -After authentication, a URL is provided to call the desired visualization, and populate it into an ` - - ----- - -The function `updateIframeUrl(id)` contains the logic to change the src URL of the ` +< script src="/path/to/liveboard.js" > < /script> +< script > + const embed = new LiveboardEmbed("#embed", { + frameParams: {}, + }); + async function downloadPDF() { + const transientPinboardContent = await embed.trigger(HostEvent.getExportRequestForCurrentPinboard); + const pdfResponse = await fetch("https://ts_host:port/callosum/v1/tspublic/v1/export/pinboard/pdf", { + method: "POST", + body: createFormDataObjectWith({ + "layout_type": "PINBOARD", + "transient_pinboard_content": transientPinboardContent, + }), + }); + } +< /script> +---- + +==== Sample browser fetch request without Visual Embed SDK + +This example calls the `getExportRequestForCurrentPinboard` function from the `api.js` file used in the legacy embed method. + +[source,JavaScript] +---- +< iframe src = "http://ts_host:port/" id = "ts-embed" > < /iframe> +< script src = "/path/to/ts-api.js" > < /script> +< script > + const tsFrame = document.getElementById("ts-embed"); + async function downloadPDF() { + const transientPinboardContent = await thoughtspot.getExportRequestForCurrentPinboard(tsFrame); + const pdfResponse = await fetch("http://ts_host:port/callosum/v1/tspublic/v1/export/pinboard/pdf", { + method: "POST", + body: createFormDataObjectWith({ + "layout_type": "PINBOARD", + "transient_pinboard_content": transientPinboardContent, + }), + }); + // Do something with pdfResponse.blob() + } +< /script> +---- + +== Example request + +Make sure the API request has the following headers: + +* The `Accept` header is set as `Accept: application/octet-stream` +* The `Content-type` header set as `Content-type: multipart/form-data` +* The `X-requested-by` header set as `X-Requested-By: ThoughtSpot` + +.cURL +[source,curl] +---- + curl --location --request POST 'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/export/pinboard/pdf' \ +--header 'Content-Type: multipart/form-data \ +--header 'Accept: application/octet-stream' \ +--header 'X-Requested-By: ThoughtSpot' \ +--header 'Cookie: JSESSIONID=71cc2672-7ead-4480-be7d-b6ad52023e98; userGUID=59481331-ee53-42be-a548-bd87be6ddd4a; Callosum-Download-Initiated=false' \ +--form 'id="061457a2-27bc-43a9-9754-0cd873691bf0"' \ +--form 'layout_type="PINBOARD"' \ +--form 'orientation="LANDSCAPE"' \ +--form 'truncate_tables="false"' \ +--form 'include_logo="true"' \ +--form 'include_page_number="true"' \ +--form 'include_filter_page="true"' \ +--form 'include_cover_page="true"' +---- + +.Request URL + +[source,html] +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/export/pinboard/pdf +---- + +== Example response + +The response appears in the form of a raw pdf file. The response type is `application/octet-stream`. + +== Runtime filters + +You can modify the API's output by passing runtime filters as parameters in the resource URL. + +For example: + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/export/pinboard/pdf?col1=COL_NAME1&op1=OP_TYPE1&val1=VALUE1&coln=COL_NAMEn&opn=OP_TYPEn&valn=VALUEn +---- + +You can add more than one filter by specifying `col2`, `op2`, `val2`, and so on. +[width="100%" cols="1,5"] +[options='header'] +|=== +| Parameter | Definition + +| col<__n__> +| Name of the column to filter on. + +| op<__n__> +| {IN, EQ, NE, LT, LE...} + +| val<__n__> +| Value of the column to filter on. +|=== + +[NOTE] +These parameters are case-insensitive. For example, `EQ`, `eq`, and `eQ` have the same result. + +=== Runtime filter operators +[width="100%" cols="1,2,1"] +[options='header'] +|=== +| Operator | Description | Number of Values + +| `EQ` +| equals +| 1 + +| `NE` +| does not equal +| 1 + +| `LT` +| less than +| 1 + +| `LE` +| less than or equal to +| 1 + +| `GT` +| greater than +| 1 + +| `GE` +| greater than or equal to +| 1 + +| `CONTAINS` +| contains +| 1 + +| `BEGINS_WITH` +| begins with +| 1 + +| `ENDS_WITH` +| ends with +| 1 + +| `BW_INC_MAX` +| between inclusive of the higher value +| 2 + +| `BW_INC_MIN` +| between inclusive of the lower value +| 2 + +| `BW_INC` +| between inclusive +| 2 + +| `BW` +| between non-inclusive +| 2 + +| `IN` +| is included in this list of values +| multiple +|=== + + + +== Response codes + +[width="100%" cols="1,5"] +[options='header'] +|=== +| HTTP status code | Description + +| **200** +| Streaming output for Liveboard pdf + +| **400** +| Invalid parameter values + +| **403** +| No read access for Liveboard + +| **404** +| Object not found +|=== diff --git a/docs/src/asciidocs/pinboarddata.adoc b/docs/src/asciidocs/pinboarddata.adoc new file mode 100644 index 000000000..a51d71836 --- /dev/null +++ b/docs/src/asciidocs/pinboarddata.adoc @@ -0,0 +1,360 @@ += Liveboard data API +:toc: true +:toclevels: 1 + +:page-title: Get Liveboard Data +:page-pageid: liveboard-data-api +:page-description: The liveboard data API API allows you to query a pinboard and its visualizations + +To retrieve data related to a Liveboard or visualization from the ThoughtSpot system, you can use the Liveboard data API. + +Using this API, you can fetch the following information: + +* All the visualization objects on a Liveboard +* A specific or a group of visualizations on a Liveboard + +[NOTE] +==== +ThoughtSpot recommends using Liveboard data API to embed ThoughtSpot content within a native mobile app. +==== + +== Supported operations + +[div boxAuto] +-- +[width="100%" cols="2,1"] +[options='header'] +|===== +|API endpoint| Available from +|`xref:pinboarddata.adoc[*POST* /tspublic/v1/pinboarddata]` + +Gets Liveboard object data from the ThoughtSpot application.| +ThoughtSpot Cloud [version noBackground]#ts7.april.cl# + +ThoughtSpot Software [version noBackground]#6.0.x# +|===== +-- + +== Required permissions + +You must have at least view access to the Liveboard and visualization objects. + +== Request URL +---- +POST /tspublic/v1/pinboarddata +---- +== Request parameters + +[width="100%" cols="1,4"] +[options='header'] +|==== +|Query parameter|Description +|`id`|__String__. The GUID of the Liveboard. +|`vizid` __Optional__|__String__. A JSON array of GUIDs of the visualizations. +|`transient_pinboard_content`|__String__. If the Liveboard has unsaved changes, pass this parameter in the xref:pinboard-export-api.adoc#transient-pinboard[browser fetch request]. +|`batchsize`|__Integer__. The batch size for loading Liveboard objects. The system default is -1. +|`pagenumber`|__Integer__. An alternate way to define the offset. The system default is -1. The `offset` attribute definition will not apply if the `pagenumber` value is greater than 0. +|`offset` a|__Integer__. The system default is -1. You can set an offset value based on the following formula: + +`PageNumber (Offset) = PageNumber -1 * BatchSize` + +For example, if a Liveboard has 10 charts and each chart has 5 columns and 10 records, and the `offset` value is set to `1`, the charts will display data from the second record onwards. If the `pagenumber` attribute is set to `3` and `batchsize` is defined as `1`, then the offset value changes to 2, and all 10 charts will display data from the third record onwards. +|`formattype`|__String__. Valid values are `COMPACT` or `FULL` JSON. The system default is `COMPACT`. +|==== + +[#transient-pinboard] +== Liveboard data with unsaved changes + +To download retrieve a Liveboard with unsaved changes, pass the `transient_pinboard_content` script with `getExportRequestForCurrentPinboard` method in the browser fetch request . + +[source,JavaScript] +---- +function getExportRequestForCurrentPinboard(frame: HTMLIframeElement): Promise; +---- + +The promise returned resolves to a string that contains the transient Liveboard content, which is encoded as JSON and is sent to the `/tspublic/v1/pinboarddata` endpoint with the `transient_pinboard_content` key. This content resembles the current Liveboard as is, including the unsaved changes if any. + +The promise returned resolves to a string that contains the transient Liveboard content, which is encoded as JSON and is sent to the `/tspublic/v1/pinboarddata` endpoint with the `transient_pinboard_content` key. This content resembles the current Liveboard as is, including unsaved changes to the following: + +* Liveboard filters +* Runtime filters applied on visualizations on a Liveboard +* Liveboard layout + +If the new Liveboard experience is enabled, the transient content includes ad hoc changes to visualizations such as sorting, toggling of legends, and data drill down. + +=== Sample browser fetch request +[source,JavaScript] +---- +< iframe src = "http://ts_host:port/" id = "ts-embed" > < /iframe> +< script src = "/path/to/liveboard.js" > < /script> +< script > + const embed = new LiveboardEmbed("#embed", { + frameParams: {}, + }); + async function liveboardData() { + const transientPinboardContent = await embed.trigger(HostEvent.getExportRequestForCurrentPinboard); + const liveboardDataResponse = await fetch("https://ts_host:port/callosum/v1/tspublic/v1/pinboarddata", { + method: "POST", + body: createFormDataObjectWith({ + "formattype": "COMPACT", + "transient_pinboard_content": transientPinboardContent, + }), + }); + } +< /script> +---- + +== Example requests + +=== Liveboard data + +.CURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=f4533461-caa5-4efa-a189-13815ab86770&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=f4533461-caa5-4efa-a189-13815ab86770&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT +---- + +=== Visualization data + +.CURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=bea79810-145f-4ad0-a02c-4177a6e7d861&vizid=['fa934657-e347-4de7-b02d-3b46609233cc','62f98ad3-6ddd-4aed-8f13-58054295b7e3','eb77ba14-15de-4d4d-aac4-625ebd58b1c6']&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=bea79810-145f-4ad0-a02c-4177a6e7d861&vizid=['fa934657-e347-4de7-b02d-3b46609233cc','62f98ad3-6ddd-4aed-8f13-58054295b7e3','eb77ba14-15de-4d4d-aac4-625ebd58b1c6']&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT +---- + +== Example response +Each data object returned in the API response contains four components: + +. The `columnNames` array that contains a list of all column headers. +. The `data` array that contains a list of sub-arrays. Each sub-array represents a new row of data. +. Name of the visualization. +. A sampling ratio. ++ +The sampling ratio tells you the percentage of total data returned. +A sampling ratio of `1` indicates that all data in the visualization object was returned in the API response. + +=== Liveboard data + +[source,JSON] +---- +{ + "4fdf9d2c-6f34-4e3b-9fa6-bd0ca69676e1": { + "name": "Sample Name", + "columnNames": [ + "Opportunity Stage", + "Opportunity Owner Name", + "Total Amount" + ], + "data": [ + [ + "s3 alignment with eb", + "jeff cameron", + 1102272 + ], + [ + "s4 validation", + "brian mcquillan", + 59150 + ] + ], + "samplingRatio": 1, + "totalRowCount": 14, + "rowCount": 14, + "pageSize": 10, + "offset": 0 + } +} +---- +=== Visualization data +The returned JSON data includes one object for every visualization on the Liveboard. +If you make a call to obtain data for a specific visualization on a Liveboard, The API returns data for only that visualization. + +[source,JSON] +---- +{ + "fa934657-e347-4de7-b02d-3b46609233cc": { + "columnNames": [ + "User" + ], + "data": [ + [ + 9 + ] + ], + "samplingRatio": 1, + "totalRowCount": 1, + "rowCount": 1, + "pageSize": -1, + "offset": -1, + "name": "MAU Last 30 Days" + }, + "eb77ba14-15de-4d4d-aac4-625ebd58b1c6": { + "columnNames": [ + "User", + "Number of User Action" + ], + "data": [ + [ + "tsadmin", + 436 + ], + [ + "system", + 50 + ], + [ + "cristi-test", + 8 + ], + [ + "sandeep2", + 7 + ], + [ + "sandeep", + 4 + ] + ], + "samplingRatio": 1, + "totalRowCount": 5, + "rowCount": 5, + "pageSize": 100000, + "offset": 0, + "name": "Top 10 Liveboard Consumers Last 30 days" + }, + "62f98ad3-6ddd-4aed-8f13-58054295b7e3": { + "columnNames": [ + "User" + ], + "data": [ + [ + 2 + ] + ], + "samplingRatio": 1, + "totalRowCount": 1, + "rowCount": 1, + "pageSize": -1, + "offset": -1, + "name": "Inactive Users" + } +} +---- + +=== Runtime filters +You can modify the API's output by passing runtime filters as parameters in the resource URL. + +For example: + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=f4533461-caa5-4efa-a189-13815ab86770&batchsize=-1&col1=COL_NAME1&op1=OP_TYPE1&val1=VALUE1&coln=COL_NAMEn&opn=OP_TYPEn&valn=VALUEn +---- + +You can add more than one filter by specifying `col2`, `op2`, `val2`, and so on. +[width="100%" cols="1,5"] +[options='header'] +|=== +| Parameter | Definition + +| col<__n__> +| Name of the column to filter on. + +| op<__n__> +| {IN, EQ, NE, LT, LE...} + +| val<__n__> +| Value of the column to filter on. +|=== + +[NOTE] +These parameters are case-insensitive. For example, `EQ`, `eq`, and `eQ` have the same result. + +==== Runtime filter operators +[width="100%" cols="1,2,1"] +[options='header'] +|=== +| Operator | Description | Number of Values + +| `EQ` +| equals +| 1 + +| `NE` +| does not equal +| 1 + +| `LT` +| less than +| 1 + +| `LE` +| less than or equal to +| 1 + +| `GT` +| greater than +| 1 + +| `GE` +| greater than or equal to +| 1 + +| `CONTAINS` +| contains +| 1 + +| `BEGINS_WITH` +| begins with +| 1 + +| `ENDS_WITH` +| ends with +| 1 + +| `BW_INC_MAX` +| between inclusive of the higher value +| 2 + +| `BW_INC_MIN` +| between inclusive of the lower value +| 2 + +| `BW_INC` +| between inclusive +| 2 + +| `BW` +| between non-inclusive +| 2 + +| `IN` +| is included in this list of values +| multiple +|=== + +== Response codes + +[options="header", cols="1,2"] +|=== +|HTTP Code|Description +|**200**|Successful retrieval of Liveboard or visualization data +|**400**|Invalid Liveboard ID +|=== \ No newline at end of file diff --git a/docs/src/asciidocs/prefetch-and-cache.adoc b/docs/src/asciidocs/prefetch-and-cache.adoc new file mode 100644 index 000000000..a6a5758e2 --- /dev/null +++ b/docs/src/asciidocs/prefetch-and-cache.adoc @@ -0,0 +1,69 @@ += Prefetch static resources +:toc: true + +:page-title: Prefetch static resources +:page-pageid: prefetch +:page-description: Prefetch static resources before loading an application. + +By default, the SDK fetches application resources when the embedded app content is requested. For optimal performance and faster loading of embedded objects, we recommend prefetching static resources and serving these static assets from the local cache of the user's browser. + +To prefetch static resources, use one of these options: + +* Use the `prefetch` method (Recommended) ++ +The `prefetch` method in the SDK allows your web browsers to prefetch static resources from a given URL on application load. In the `prefetch` method, you can define the prefetch URL and specify the embed components for which you want to prefetch resources. To improve application response time, ThoughtSpot recommends that you call the `prefetch` method as soon as possible when your application initializes. ++ +In the following example, the `prefetch` method is called before `init` to prefetch resources before the authentication process is initialized. ++ +[source,JavaScript] +---- +// App.jsx +import { + prefetch, + PrefetchFeatures +} +from '@thoughtspot/visual-embed-sdk'; +... +prefetch + ({ + url: "https://:", + prefetchFeatures: [PrefetchFeatures.LiveboardEmbed,PrefetchFeatures.VizEmbed] + }); +... +// post-login.jsx +// might need to be called after login to get +// the user's context. + +import { + AuthType, + init, +} +from '@thoughtspot/visual-embed-sdk'; +init + ({ + thoughtSpotHost: "https://:", + authType: AuthType.None, + }); +---- + +* Call prefetch in `init` ++ +You can call prefetch in the `init` method by setting the `callPrefetch` attribute to `true`. + ++ +[source,JavaScript] +---- +import { + LiveboardEmbed, + AuthType, + init, + prefetch, +} +from '@thoughtspot/visual-embed-sdk'; +init + ({ + thoughtSpotHost: "https://:", + authType: AuthType.None, + callPrefetch: true + }); +---- \ No newline at end of file diff --git a/docs/src/asciidocs/push-data-to-external-app.adoc b/docs/src/asciidocs/push-data-to-external-app.adoc new file mode 100644 index 000000000..79b3731f9 --- /dev/null +++ b/docs/src/asciidocs/push-data-to-external-app.adoc @@ -0,0 +1,168 @@ += Callback custom action workflow +:toc: true + +:page-title: Push data to an external app +:page-pageid: push-data +:page-description: Push data to an external application + +ThoughtSpot allows you to create custom actions to push data to a third-party application from the ThoughtSpot application context. +You can configure this custom menu item to initiate an action or a callback to the parent application. +For example, if you have embedded the ThoughtSpot search functionality in your application, you can add an action to send the data obtained from a search query to an external application or a workflow. +//// +You can also use the REST APIs to query data and automatically trigger the custom action workflow. +//// +[NOTE] +The data is available to the external application in the JavaScript Object Notation (JSON) format. You must parse the JSON data to get the values you need using JavaScript in the receiving application. + +== Push data using a callback custom action +To push data to an external app through a callback custom action, follow these steps: + +* xref:push-data-to-external-app.adoc#add-callback[Add a callback custom action in ThoughtSpot] +* xref:push-data-to-external-app.adoc#register-callback[Register the custom action] +* xref:push-data-to-external-app.adoc#callback-initiate[Initiate a callback] +* xref:push-data-to-external-app.adoc#handle-data[Define classes and functions to handle custom action data] + +[#add-callback] +=== Add a callback custom action in the ThoughtSpot +You can xref:custom-actions-callback.adoc[Create a callback custom action] in the ThoughtSpot Developer portal (*Develop* > *Customization* > *Custom actions* > *Create action*) or using the xref:admin-api.adoc#create-custom-action[/tspublic/v1/admin/embed/actions] REST API. + +[#register-callback] +=== Register the callback through the Visual Embed SDK + +Register the callback using the Visual Embed SDK. This configuration is required to trigger an event when the custom action is initiated. + +The following example shows how to call `showData` when a custom action is received. + +[source, Javascript] +---- +const searchEmbed = new SearchEmbed('#embed', { + frameParams: {}, +}); +embed + .on(EmbedEvent.CustomAction, (payload) => { + showData(payload); + }) + .render(); +---- + +[#callback-initiate] +=== Initiate the callback action +Define the function and classes to handle the data that you want to send as a payload when a custom action is triggered. +This example shows how to handle the `show-data` callback custom action and the details of its data: + +[source, Javascript] +---- +const showData = (payload) => { + const data = payload.data; + if (data.id === 'show-data') { + // Display the data as a table. + const actionData = ActionData.createFromJSON(payload); + const html = actionDataToHTML(actionData); + const dataContentElement = document.getElementById('modal-data-content'); + dataContentElement.innerHTML = html; + const dataElement = document.getElementById('show-data'); + dataElement.style.display = 'block'; + } else { + console.log(`Got unknown custom actions ${data.id}`); + } +} +---- + +[#large-dataset] +ThoughtSpot visualization objects can include several rows of records. For callback custom action payloads, the Visual Embed SDK supports retrieving data in batches. + +The following example shows how to handle large datasets in custom action payloads: + +[source, Javascript] +---- +const data = payload.data; +if (data.id === 'show-data') { + const fetchAnswerData = await payload.answerService.fetchData(1, 5); //where the first integer is the offset value and second integer is batchsize + console.log('fetchAnswerData:::', fetchAnswerData); +} +---- + +[#handle-data] +=== Define functions and classes to handle custom action data +The following code snippet shows the sample classes and functions for handling custom action data. For an up-to-date version of the code sample, see link:https://github.com/thoughtspot/ts_everywhere_resources/blob/master/apis/dataclasses.js[dataclasses.js, window=_blank]. + +[source, Javascript] +---- +const zip = (arrays) => { + // combines and inverts arrays, so a = [1, 2, 3], b = [4, 5, 6] becomes [[1,4], [2,5], [3,6]] + return arrays[0].map(function(_, i) { + return arrays.map(function(array) { + return array[i] + }) + }); +} +class ActionData { + // Wrapper for the data sent when a custom action is triggered. + constructor() { + this._columnNames = []; // list of the columns in order. + this._data = {}; // data is stored and indexed by column with the index being column name. + } + get nbrRows() { + // Returns the number of rows. Assumes all columns are of the same length. + if (this._columnNames && Object.keys(this._data)) { // make sure there is some data. + return this._data[this._columnNames[0]]?.length; + } + return 0; + } + get nbrColumns() { + // Returns the number of columns. + return this._columnNames.length; + } + static createFromJSON(jsonData) { + // Creates a new ActionData object from JSON. + const actionData = new ActionData(); + // Gets the column names. + const nbrCols = jsonData.data.embedAnswerData.columns.length; + for (let colCnt = 0; colCnt < nbrCols; colCnt += 1) { + actionData._columnNames.push(jsonData.data.embedAnswerData.columns[colCnt].column.name); + } + let dataSet; + dataSet = (Array.isArray(jsonData.data.embedAnswerData.data)) ? + jsonData.data.embedAnswerData.data[0].columnDataLite : + jsonData.data.embedAnswerData.data.columnDataLite; + for (let colCnt = 0; colCnt < actionData.nbrColumns; colCnt++) { + actionData._data[actionData._columnNames[colCnt]] = Array.from(dataSet[colCnt].dataValue); // shallow copy the data + } + return actionData + } + getDataAsTable() { + // returns the data as a table. The columns will be in the same order as the column headers. + const arrays = [] + for (const cname of this._columnNames) { + arrays.push(this._data[cname]) + } + return zip(arrays); // returns a two dimensional data array + } +} +const actionDataToHTML = (actionData) => { + // Converts an ActionData data to an HTML table. + let table = ''; + // Add a header + table += ''; + for (const columnName of actionData._columnNames) { + table += ``; + } + table += ''; + const data = actionData.getDataAsTable(); + for (let rnbr = 0; rnbr < actionData.nbrRows; rnbr++) { + table += ''; + for (let cnbr = 0; cnbr < actionData.nbrColumns; cnbr++) { + table += ``; + } + table += ''; + } + table += '
${columnName}
${data[rnbr][cnbr]}
'; + return table; +} +export { + ActionData, + actionDataToHTML +} +---- + +For sample response payloads, see xref:callback-response-payload.adoc[Custom action response payload]. diff --git a/docs/src/asciidocs/push-data-to-slack.adoc b/docs/src/asciidocs/push-data-to-slack.adoc new file mode 100644 index 000000000..273ad8486 --- /dev/null +++ b/docs/src/asciidocs/push-data-to-slack.adoc @@ -0,0 +1,177 @@ + += Push data to a Slack workspace[beta betaBackground]^Beta^ +:toc: true + +:page-title: Integrate ThoughtSpot with Slack app +:page-pageid: slack-integration +:page-description: You can connect users to their Slack workspace via app actions and allow them to push insights to a Slack channel + +With most businesses using Slack for communication and team collaboration, business users and analysts may want to deliver insights to their Slack workspace from the ThoughtSpot UI. ThoughtSpot makes it easier for your developers to automate the app integration workflow and enable seamless integration with your business apps. With app actions, users can now connect their Slack workspace with ThoughtSpot and push insights directly to their Slack channels. + + +== Before you begin + +To integrate Slack workspaces with ThoughtSpot, you will need the following: + +* A ThoughtSpot user account with developer or admin privileges to create app actions +* A ThoughtSpot user with a Slack account +* A ThoughtSpot application instance with *New Answer Experience* enabled +* A saved answer or Liveboard visualization + + +== Integration workflow + +The Slack app integration workflow involves the following steps: + +. A developer or admin user creates an app action for Slack in the Developer portal. ++ +This step sets Slack as a destination app. +. A user clicks a Slack app action on a saved answer or Liveboard visualization, and invokes the workflow. + ++ +This step initiates the OAuth workflow to secure data transactions between the source and destination app. +. ThoughtSpot requests access to the users' Slack workspace. +. The user authorizes the request. + ++ +This step creates a pipeline between ThoughtSpot and the destination app for data exchange. +. ThoughtSpot obtains a list of channels from the user's Slack workspace. +. The user selects a channel and clicks **Send now**. +. ThoughtSpot pushes the answer data or insights from the visualization to the specified channel in the specified file format. + + +== Get started + +The Slack app integration procedure involves the following steps: + +. xref:push-data-to-slack.adoc#app-action-slack[Create an app action with Slack as the destination app] +. xref:push-data-to-slack.adoc#initiateActionSlack[Initiate a data push request to Slack] +. xref:push-data-to-slack.adoc#viewInSlack[View insights in your Slack workspace] + +[#app-action-slack] +=== Create an app action with Slack as the destination app + +To create an app action for Slack, complete the following steps: + +. Log in to ThoughtSpot with your admin or developer user credentials. +. Go to *Develop* > *Customizations* > *Custom actions*. +. Click *Create action*. +. Enter a name for the action. For example, __Send to Slack__. +. Select the *App* option and then select **Slack** from the *Select app* drop-down. ++ +Note that the app action ID is generated automatically. + +. To add this action globally to all visualizations and saved answers, select *On by default on all visualizations*. ++ +If you do not select this checkbox, the app action is set as *Local* and is not assigned to any visualization or saved answer. + ++ +[.bordered] +image:./images/app-action-dev.png[App action creation, width=auto] + ++ +. To restrict action availability to specific user groups, click *Show advanced availability settings*, and select the groups. + +. Click *Create action*. + +. To view the custom action you just created, navigate to a visualization or saved answer page. + ++ +include::{path}/global-local-action.adoc[] + + +[#initiateActionSlack] +=== Initiate the app action + +Before you begin, perform the following checks: + +* You have access to a Slack workspace. +* The *New Answer experience* is enabled on your ThoughtSpot application instance. +* The Slack app action is added to a visualization or saved answer on your instance. + +[NOTE] +==== +The Slack app authorization page opens as a pop-up. Make sure your web browser allows pop-ups from the ThoughtSpot application. +==== + +To initiate a data push request to your Slack workspace, complete the following steps: + +. Go to a Liveboard visualization or saved answer page. + +. If you have created an answer from a new query, make sure you save the answer. ++ +If the app action is set as a global action, the action will appear in the **More** menu image:./images/icon-more-10px.png[the more options menu]. If the action is set as a local app action, you must add it to your answer page. + +. Click the action to initiate a data push request. + ++ +[.bordered] +image::./images/initiate-app-action.png[Initiate an app action] + +. In the app authorization pop-up, select your Slack workspace. + +If the ThoughtSpot app is not installed in your Slack workspace:: + +The app authorization page prompts you to install the app. + +* If you have admin rights to your workspace, complete the installation, and then retry the Slack action workflow. + +* If you don't have access rights to install the app in your Slack workspace: +.. Click **Submit** to send a request to your workspace administrator. You can also add a message for your workspace administrator in the request. ++ +Your Slack workspace administrator will receive a Slackbot notification to approve the request. + +.. Close the app authorization pop-up and return to the ThoughtSpot UI. +.. Wait until your request is approved by the Slack workspace administrator. If your request is approved, you will receive a notification via email and Slackbot. ++ +If your request is not approved, the app authorization pop-up displays the *Your request is already submitted* message when you re-initiate the Slack app action. Contact your Slack administrator and ensure that the ThoughtSpot app is installed in your workspace. + +.. After you receive a notification from Slackbot or email about the request approval, re-initiate the data push workflow by clicking the app action in the ThoughtSpot UI. + ++ +If the ThoughtSpot app is installed in your Slack workspace:: +ThoughtSpot requests access to your Slack workspace and opens the app authorization pop-up. ++ +If you are not logged in to Slack workspace, the app authorization page prompts you to sign in. To continue with the integration, sign in with your credentials. + +. To authorize ThoughtSpot to send data, click **Allow**. + ++ +This step is required only if you are using the Slack integration action for the first time or when ThoughtSpot refreshes its OAuth access token. + +. Wait for ThoughtSpot to connect to your workspace and obtain a list of channels. + ++ +If the connection is successful, the app action dialog in the ThoughtSpot UI displays a list of Slack channels. + ++ +[.bordered] +image:./images/send-to-slack.png[Initiate an app action, width=auto] + +. Select a channel from the *Slack channel* drop-down. ++ +You can also search for a channel and then select it. + +. If required, modify the title of the data. +. Specify the text to send in your Slack message. +. Specify if the data must be sent as a PNG file or in the CSV format, or both. ++ + +[NOTE] +==== +ThoughtSpot does not support sending data in the PNG format if a chart or table does not include measures. +==== +. Click **Send now**. + +[#viewInSlack] +=== View insights in your Slack workspace + +To view the insights sent to a Slack channel: + +. Go to your Slack workspace. +. Click the channel to which you have sent the data. +. Verify the data in the CSV and image files. ++ +To view the source app details in your Slack workspace, go to *Apps* in your Slack app. + + diff --git a/docs/src/asciidocs/rel-page-sw.adoc b/docs/src/asciidocs/rel-page-sw.adoc new file mode 100644 index 000000000..4c459f2ab --- /dev/null +++ b/docs/src/asciidocs/rel-page-sw.adoc @@ -0,0 +1,121 @@ += Now available on ThoughtSpot Software! +:toc: true +:toclevels: 1 + +:page-title: Embedding support on ThoughtSpot Software clusters +:page-pageid: embedding-support-software +:page-description: This article sumamrizes the embedding support and ThoughtSpot Everywhere features available on ThoughtSpot Software clusters. + +ThoughtSpot Software clusters now support ThoughtSpot Everywhere and embedding with Visual Embed SDK! + +Starting from the 8.4.1-sw release, ThoughtSpot Software customers who have a license to embed ThoughtSpot can use ThoughtSpot Everywhere features and Visual Embed SDK to embed ThoughtSpot objects in their apps. + +== Embedding methods + +For information about the embedding options available for your deployments, see xref:embed-methods.adoc#_supported_embedding_methods[Supported embedding methods]. + + +== Embedding with Visual Embed SDK + +The Visual Embed SDK provides Javascript-based embed packages and client libraries to help you embed the following ThoughtSpot components in your web application: + + +* xref:embed-search.adoc[ThoughtSpot Search] +* xref:embed-pinboard.adoc[Liveboards] +* xref:embed-a-viz.adoc[Individual visualizations from a Liveboard] +* xref:full-embed.adoc[Individual application pages or the full application] + +Developers can also customize embedded objects using the APIs in the SDK: + + +* xref:embed-search.adoc[modify the layout of the embedded Search page] +* xref:full-embed.adoc[customize the layout and home tabs in the embedded ThoughtSpot view] +* xref:embed-actions.adoc[show or hide UI actions] +* xref:runtime-filters.adoc[apply runtime filters] +* xref:embed-events.adoc[trigger events and respond to events with an action] +* xref:custom-actions.adoc[handle callback custom actions] that trigger a callback and send ThoughtSpot data in a response payload to the parent app. + +=== Supported SDK versions + +The minimum SDK version required for embedding ThoughtSpot Software in your app is `1.12.0`. + +You can upgrade to a later version if required. However, you must exercise caution before upgrading to a new version because the new versions may introduce breaking changes. The new version may also include APIs, methods, and attributes for features that are not yet available on your ThoughtSpot Software release. + +For more information about the SDK versions, supported methods and classes, see xref:api-changelog.adoc[Visual Embed Changelog] and link:{{visualEmbedSDKPrefix}}/modules.html[Visual Embed SDK Reference Guide, window=_blank]. + +== REST API + +REST API v1 operations are supported on ThoughtSpot Software by default. You can make API calls to query data, add and modify ThoughtSpot objects, and perform administrative tasks. + +The *Develop* tab in the UI also allows you to explore REST API v1 and REST API v2 [beta betaBackground]^Beta^ request and response workflows. + +For a complete list of endpoints and information about allowed operations, see xref:rest-api-reference.adoc[REST API v1 Reference] and xref:rest-api-v2-reference.adoc[REST API v2 ^BETA^ Reference]. + +== Feature support matrix + +[div tableContainer] +-- +[width="100%" cols="7,5,5"] +[options='header'] +|===== +|Feature|ThoughtSpot Software clusters with ThoughtSpot Everywhere|Clusters without ThoughtSpot Everywhere or embedding license + +|Access to **Develop** tab + + +(Requires developer or admin privileges) |[tag greenBackground]#✓# | [tag greenBackground]#✓# +| Visual Embed playground |[tag greenBackground]#✓# +|[tag greenBackground]#✓# + +| Visual Embed SDK + + +Creating an app with ThoughtSpot Search, visualizations, Liveboards, or full application using Visual Embed SDK libraries a|[tag greenBackground]#✓# + +__The minimum supported version is 1.12.0__| [tag greyBackground]#–# + +a|Embedding with REST APIs + + +* Embedding Liveboards with visualizations + +* Embedding search data +|[tag greenBackground]#✓# + + +|[tag greenBackground]#✓# + +(Basic authentication only) + +|Authentication options + +(For embedded ThoughtSpot instances only) a| [tag greenBackground]#✓# Basic authentication + + +[tag greenBackground]#✓# SAML SSO + + +[tag greenBackground]#✓# Token-based authentication + + +[tag greenBackground]#✓# OIDC + + +| [tag greenBackground]#✓# Basic authentication + + +[tag greenBackground]#✓# SAML SSO + +a|REST API v1 + + +|[tag greenBackground]#✓# +|[tag greenBackground]#✓# + +(Basic authentication only) + +a|REST API v2 [beta betaBackground]^Beta^ |[tag greenBackground]#✓# + + |[tag greenBackground]#✓# + +(Basic authentication only) + +|REST API Playground [beta betaBackground]^Beta^|[tag greenBackground]#✓# | [tag greenBackground]#✓# + +|URL-based custom actions|[tag greenBackground]#✓# |[tag greenBackground]#✓# +|Callback custom actions|[tag greenBackground]#✓# |[tag greyBackground]#–# +|UI styles, font, and layout customization|[tag greenBackground]#✓# |[tag greenBackground]#✓# +|Link customization|[tag greenBackground]#✓# |[tag greyBackground]#–# +|Security settings for embedding ThoughtSpot + + +(CSP, CORS, and SAML Redirect configuration)| [tag greenBackground]#✓# | [tag greyBackground]#–# | [tag greyBackground]#–# +|===== +-- + +== Documentation + +An up-to-date version of ThoughtSpot Everywhere documentation is available on the link:https://developers.thoughtspot.com/docs[Developer Documentation] site. To view the documentation specific to the Software release version that your cluster is currently on: + +. Go to the *Develop* tab on your cluster. +. Click the *Guide* menu under *Visual Embed SDK* or *REST API*. diff --git a/docs/src/asciidocs/response-pagination.adoc b/docs/src/asciidocs/response-pagination.adoc new file mode 100644 index 000000000..90a6921a2 --- /dev/null +++ b/docs/src/asciidocs/response-pagination.adoc @@ -0,0 +1,90 @@ += Paginate API response + +:page-title: REST API response pagination +:page-pageid: rest-api-pagination +:page-description: REST API response pagination + +When you make REST API calls to some endpoints to query data, the API may return many rows of data in the response. You can paginate the JSON response and retain the order of data across all pages. Given the ability to paginate, you can quickly populate tables and make new REST calls every time you go to the next page of the data on the table. There is significant load time if you want to populate the data table with many rows (greater than 1000). + +To paginate results in your API response, add the following parameters to the query: + +`pagesize` determines the number of rows to include. + +[source,JSON] +---- + { + "name": "pagesize", + "description": "pagesize: The number of rows.", + "defaultValue": "-1", + "type": "integer" + } +---- + +`offset` determines the starting point. + +[source,JSON] +---- + { + "name": "offset", + "description": "Offset: The starting point", + "defaultValue": "-1", + "type": "integer" + } +---- + +`pageNumber` is an alternate way to determine the offset. +You must make a call with `pageNumber = 1` first, and then you can access any page. +Calling with `pageNumber != 1` as the initial call will fail. +`pageNumber = 0` is not a valid value. + +[source,JSON] +---- +{ + "name": "pagenumber", + "description": "PageNumber: This is an alternate way to set offset. This is 1-based indexing. Offset = (pageNumber - 1) * pageSize.", + "defaultValue": "-1", + "type": "integer" +} +---- + +`FormatType` is the JSON format type. + +[source,JSON] +---- +{ + "name": "formattype", + "description": "FormatType: This sets the JSON format type. Values that are allowed are FULL and COMPACT.", + "defaultValue": "COMPACT", + "type": "string" +} +---- + +`COMPACT` is the default type, and is formatted as follows: `['col1', 'col2'] [1, 'a']`. +While `FULL` is formatted like this: +---- +{'col1': 1 'col2': 'a'} +---- +== Example + +The following example shows ThoughtSpot data that is being populated in a table: + +[source,JSON] +---- + +{ + "totalRowCount": 1500, + "pageSize": 1000, + "pageNumber": 1, + "data": + [ + { + "key1": "value1", + "key2": "value2" + }, + { + "key1": "value1", + "key2": "value2" + } + ] +} +---- diff --git a/docs/src/asciidocs/rest-api-getstarted.adoc b/docs/src/asciidocs/rest-api-getstarted.adoc new file mode 100644 index 000000000..ce2e43497 --- /dev/null +++ b/docs/src/asciidocs/rest-api-getstarted.adoc @@ -0,0 +1,166 @@ += Get started with REST API v1 +:toc: true +:toclevels: 2 + +:page-title: Getting started with REST APIs +:page-pageid: rest-api-getstarted +:page-description: Get started with REST API to access, create, and manage ThoughtSpot resources programmatically. + +Before you start using REST APIs, perform the following checks: + +* Your client application domain is added as a xref:security-settings.adoc[Cross-Origin Resource Sharing (CORS) host] in the ThoughtSpot Developer portal. ++ +Note that after you add your host domain for CORS, ThoughtSpot adds the `access-control-allow-origin` header in its API responses. + +* You have valid login credentials and access privileges to run the operations. + +== Access resource endpoints + +You can access the REST API v1 explorer using one of the following options: + +* Using the *REST Playground v1* menu option in the Developer portal (Requires Developer or Administrator privilege) ++ +If the REST API Playground feature is enabled on your cluster, go to *Develop* > **REST API **> *REST Playground v1*. + ++ +++++ +Try it out +++++ + + +* Using the Swagger URL ++ +---- +https:///external/swagger +---- ++ +++++ + Try it out +++++ +The REST API v1 Explorer displays a list of REST API services available for the logged-in ThoughtSpot users. + ++ +To make an API call and view results: + +. Click the API service category and view a list of endpoints. +. Click on the endpoint to which you want to send an API request. +. If required, define the attributes. +. Click **Try it out** and verify the API response and HTTP status code. + +== Authentication + +To create, access, and modify ThoughtSpot objects and resources using the REST API, you must log in as an authorized user. + +When using the REST API through a web browser, we recommend that you use the xref:configure-saml.adoc[SAML SSO] or xref:trusted-authentication.adoc[trusted authentication] service to authenticate to ThoughtSpot. + +Any completed log-in process will return session cookies from the ThoughtSpot system, which must be included with any subsequent REST API call. + +For more information, see xref:api-auth-session.adoc[Authentication]. + +== Data format + +The REST APIs allow you to send and receive data in JSON format. +To embed this data in your application, you can import or extract the data from the JSON file. +You can also use scriptable files in ThoughtSpot Modeling Language (TML) to represent objects in a reusable, editable, and easy-to-read format. ThoughtSpot allows you to export and import these scriptable files using REST APIs. + +== API requests and response + +To call a REST API, send a request to the endpoint URL with the attributes required to create, view, or modify an object. + + +=== Request method + +Specify the HTTP request method in your API request. + +* `GET` to query information, such as getting a list of users or groups. +* `POST` to create and add new properties to a resource, such as a user, group, Answer, Worksheet, or data object. +* `PUT` to update the properties of an existing resource, such as modifying the properties of a user or user group. +* `DELETE` to remove an object or object association. + +Some endpoints may require you to send a `POST` request for delete or update operation. For more information about the endpoint URIs and request methods, see xref:rest-api-reference.adoc[REST API v1 Reference]. + + +=== Request headers + +[width="100%" cols="1,4"] +|=== +|`X-Requested-By`| Make sure you include the `'X-Requested-By: ThoughtSpot'` header in all API requests. +|`User-Agent`|The `User-Agent` header is required for all requests. Most clients will add the `User-Agent` header automatically. However, when making API calls from code, especially `.NET`, you need to add the `User-Agent` header. + +The `User-Agent` can be any string; for example, you can set the header as `'User-Agent: /'`. +|`Accept`| Use this header to specify the content type for the API responses. You can set it to `'Accept: application/json'` for JSON and `'Accept: text/plain'` for plain text responses. +|`Content-Type` a| Use this header to indicate the content type to use in the request body. Set this header as `'Content-Type: application/json'`. + +* Some `POST` operations, such as sharing an object with another user, require the URL-encoded objects to be passed as parameters in the URL. For such API requests, set the header as `'Content-Type: application/x-www-form-urlencoded'`. + +* For some endpoints, such as `/tspublic/v1/user/sync`, you need to send the request body as separate blocks of data or as a JSON file in `POST` requests. For APIs that require multiple blocks of data, set the header as `'Content-Type: multipart/form-data'`. + +For more information, see the example requests in the xref:rest-api-reference.adoc[API reference articles]. +|=== + +=== Request parameters + +Some API endpoints allow you to send attributes as query parameters in `POST` requests. For example, the `/tspublic/v1/metadata/listobjectheaders` API endpoint passes request parameters as a query string in the URL. + +For object creation or update operations (`POST` and `PUT` requests), you may need to send `formData` attributes as a JSON array of strings or as a JSON map of key-value pairs in the request body. Make sure you specify the attributes in the format recommended in the Swagger UI and xref:rest-api-reference.adoc[REST API v1 Reference]. + +==== Object IDs + +All ThoughtSpot objects and resources are assigned a Globally Unique Identifier (GUID) by default. Most endpoints require you to specify the GUID to access, query, or modify a specific object. You can query the metadata list to get a list of objects of a specific type and the GUIDs assigned to each of these objects. + +For example, you can use the `/tspublic/v1/metadata/listvizheaders` endpoint to get a list of the Liveboards and their GUIDs: + +[source,JSON] +---- +[ +{ + "id":"d084c256-e284-4fc4-b80c-111cb606449a", + "name":"Sales Performance", + "description":"", + "author":"67e15c06-d153-4924-a4cd-ff615393b60f", + "created":1642560047638, + "modified":1642560047638, + "modifiedBy":"67e15c06-d153-4924-a4cd-ff615393b60f", + "owner":"d084c256-e284-4fc4-b80c-111cb606449a", + "isAutoCreated":false, + "isAutoDelete":false +}, +{ + "id":"74852035-9624-4fac-b352-200fa8506b14", + "name":"Object Usage", + "description":"", + "author":"67e15c06-d153-4924-a4cd-ff615393b60f", + "created":1620198465429, + "modified":1620198473992, + "modifiedBy":"67e15c06-d153-4924-a4cd-ff615393b60f", + "owner":"74852035-9624-4fac-b352-200fa8506b14", + "isAutoCreated":false, + "isAutoDelete":false +} +] +---- + +=== HTTP status codes + +For each API request, ThoughtSpot sends a response. The API returns one of the following response codes upon completing a request operation: + +* *200* ++ +Indicates a successful operation. The API returns a response body. +* *204* ++ +Indicates a successful operation. The 204 response code does not include a response body. +* *400* ++ +Indicates a bad request. You may have to modify the request before making another call. +* *401* ++ +Indicates an unauthorized request. Check if you have the required credentials and object access to send the API request. + +* *415* ++ +Indicates an unsupported media type. Check the media type specified in the `Content-Type` header. + +* *500* ++ +Indicates an internal server error. Check if the data format of the request is supported. Verify if the server is available and can process the request. diff --git a/docs/src/asciidocs/rest-api-reference.adoc b/docs/src/asciidocs/rest-api-reference.adoc new file mode 100644 index 000000000..39ae972e6 --- /dev/null +++ b/docs/src/asciidocs/rest-api-reference.adoc @@ -0,0 +1,74 @@ += REST API v1 Reference +:toc: true + +:page-title: REST API Reference Guide +:page-pageid: rest-api-reference +:page-description: REST API Reference + + +[div announcementBlock] +-- +Starting from the ThoughtSpot Cloud ts8.nov.cl and ThoughtSpot Software 8.4.1-sw releases, pinboards are rebranded as *Liveboards* in ThoughtSpot UI, documentation, and learning resources. +Note that the `pinboard` and `PINBOARD_ANSWER_BOOK` terminology in REST API v1 endpoint URLs, request and response workflows are not rebranded. +-- + + +== Orgs management + +include::{path}/org-api-list.adoc[] + +== User management + +include::{path}/user-api-list.adoc[] + +== Groups and privileges + +include::{path}/group-api-list.adoc[] + +== Session management + +include::{path}/session-api-list.adoc[] + +== Metadata management + +include::{path}/metadata-api-list.adoc[] + +== Configuration management + +include::{path}/admin-api-list.adoc[] + +== Data connections + +include::{path}/data-connection-apis.adoc[] + +== TML objects + +include::{path}/tml-api-list.adoc[] + +== Liveboard data + +include::{path}/pinboard-api-list.adoc[] + +== Search data + +include::{path}/search-api-list.adoc[] + +== Dependent objects + +include::{path}/dependency-api-list.adoc[] + +== Security + +include::{path}/security-api-list.adoc[] + +== Audit logs + +include::{path}/audit-log-api.adoc[] + +== Materialization service + +include::{path}/materialization-api-list.adoc[] + +== Database and schema + +include::{path}/database-api-list.adoc[] diff --git a/docs/src/asciidocs/rest-api-sdk-libraries.adoc b/docs/src/asciidocs/rest-api-sdk-libraries.adoc new file mode 100644 index 000000000..1aa94a0f2 --- /dev/null +++ b/docs/src/asciidocs/rest-api-sdk-libraries.adoc @@ -0,0 +1,76 @@ += REST API SDK and client libraries +:toc: true + +:page-title: REST API SDK and client libraries +:page-pageid: client-libraries +:page-description: REST API SDK + +ThoughtSpot provides native SDK libraries to help client applications call REST APIs in a language-specific way. + +Client libraries are available for Java, Python, TypeScript, and .NET. For each language, the client library provides tools and APIs to construct queries and process responses programmatically. Each client library includes classes that correspond to the resource elements and data types that the API uses. + +== Download the SDK + +You can also download the REST API SDK [beta betaBackground]^Beta^ from the following public resources: + +* link:https://github.com/thoughtspot/rest-api-sdk[GitHub repository, window=_blank] +* TypeScript SDK [beta betaBackground]^Beta^ + +link:https://www.npmjs.com/package/@thoughtspot/rest-api-sdk[NPM site, window=_blank] +* Python SDK [beta betaBackground]^Beta^ + +link:https://pypi.org/project/thoughtspot-rest-api-sdk/[PyPi, window=_blank] +* Java SDK [beta betaBackground]^Beta^ + +link:https://search.maven.org/artifact/io.github.thoughtspot/rest-api-sdk-lib[MVN Package Manager, window=_blank] +* .NET SDK + +link:https://www.nuget.org/packages/thoughtspot.rest.api.sdk[NuGet package manager, window=_blank] + +== Setup and usage + +The Playground provides installation, setup and usage instructions for each language. + +. Go to **Develop** > *REST API* > **REST Playground v2**. +. Select a programming language. +. Click *Getting Started* > **Setup and Usage** . + + +== Additional resources + +++++ +
+
+

Java SDK and libraries

+

Get started

+

API Reference

+ +
+
+
+

Python SDK and libraries

+

Get started

+

API Reference + +

+
+
+

Typescript SDK and libraries

+

Get started

+

API Reference

+
+
+
+

.NET SDK and libraries

+

Get started

+

API Reference

+
+
+
+ +
+++++ + + + +//// +

Code samples

+ +//// + diff --git a/docs/src/asciidocs/rest-api-v1.adoc b/docs/src/asciidocs/rest-api-v1.adoc new file mode 100644 index 000000000..ea2f4ba1c --- /dev/null +++ b/docs/src/asciidocs/rest-api-v1.adoc @@ -0,0 +1,50 @@ += REST API v1 +:toc: true + +:page-title: REST API v1 +:page-pageid: rest-api-v1 +:page-description: ThoughtSpot REST API provides service endpoints for administration, embedding, and data management. + +ThoughtSpot REST API v1 endpoints let you programmatically create, access, and manage ThoughtSpot objects and resources. The REST API endpoints support the following operations: + +* get Liveboard and visualization data from the ThoughtSpot application +* embed data from visualizations and Liveboards in a web page, portal, or application +* view metadata details for various types of ThoughtSpot objects +* construct a search query to get ThoughtSpot data +* manage ThoughtSpot user profiles and group privileges +* transfer ownership of objects from one user to another +* import, export, and validate scriptable files and automate deployments + +== Resource endpoints +ThoughtSpot API components or resources are represented by the URI endpoints. The URI endpoint contains the base URI and resource path to the objects that you want to query or manage. + +The base URI of the API endpoints constitutes the following: + +* The hostname or IP address of your ThoughtSpot application instance +* Port number +* Name of the ThoughtSpot API service +* The version number + +For example, in the `\https:///callosum/v1/tspublic/v1/session/login` URL + +* the base URI is `\https:///callosum/v1` +* the resource path is `/tspublic/v1/session/login` + +== HTTP request methods + +ThoughtSpot REST API endpoints support Create, Read, Update and Delete (CRUD) operations and allow applications to use the standard HTTP verbs in API requests: + +* `GET` to query information, such as getting a list of users or groups. +* `POST` to create and add new properties to a resource, such as a user, group, Answer, Worksheet, or a data object. +* `PUT` to update the properties of an existing resource, such as modifying the properties of a user or user group. +* `DELETE` to remove an object or object association. + +== Data format + +The REST APIs allow you to send and receive data in JSON format. To embed this data in your application, you can import or extract the data from the JSON file. You can also use scriptable files in ThoughtSpot Modeling Language (TML) to represent objects in a reusable, editable, and easy-to-read format. ThoughtSpot allows you to export, validate, and import these scriptable files. + +== Related information + +* xref:rest-api-getstarted.adoc[Get started with REST API v1] +* xref:api-auth-session.adoc[Authentication] +* xref:rest-api-reference.adoc[REST API v1 Reference] diff --git a/docs/src/asciidocs/rest-api-v1v2-comparison-beta.adoc b/docs/src/asciidocs/rest-api-v1v2-comparison-beta.adoc new file mode 100644 index 000000000..8baf61f71 --- /dev/null +++ b/docs/src/asciidocs/rest-api-v1v2-comparison-beta.adoc @@ -0,0 +1,131 @@ += REST API v1 and v2 comparison +:toc: true +:toclevels: 1 + +:page-title: Difference between REST API v1 and v2 +:page-pageid: v1v2-comparison-beta +:page-description: Difference between REST API v1 and v2 + +Both v1 and v2 REST API frameworks allow you to access, retrieve, create, and manage ThoughtSpot objects and resources. REST API V2 is a new framework that expands the core API functionality with additional features and improved user experience. + +[div tableContainer] +-- +[width="100%" cols="4,^5,^5"] +[options='header'] +|===== +||REST API v1| REST API V2 +|Developer Playground|Swagger API explorer + +The Swagger UI is also accessible via Developer portal|Interactive Playground in the Developer portal +|Code sample availability|[tag greyBackground]#–# |[tag greenBackground]#✓# Available + +|Authentication methods a| [tag greenBackground]#✓# Basic authentication + + +[tag greenBackground]#✓# Trusted authentication + +a| [tag greenBackground]#✓# Basic authentication + + +[tag greenBackground]#✓# OAuth Bearer token authentication + + +[tag greenBackground]#✓# Trusted authentication +|Access control| Requires admin privileges for certain API operations| Requires admin or developer privileges to access the API console +|Input and output parameters| Not fully standardized |Standardized + +|Resource collections a| * Data + +Data APIs to search data, fetch Liveboard details and export Liveboard +* admin +* connection +* dependency +* export +* group +* logs +* metadata +* TML +* security +* session +* user + +a| * Authentication +* Users +* Groups +* Connection +* Metadata +* Data +* Report +* Logs +* Security +* Admin +* Custom actions + +|API services a|[tag greenBackground]#✓# User APIs + +[tag greenBackground]#✓# Group APIs + +[tag greenBackground]#✓# Session APIs + +[tag greenBackground]#✓# Connection APIs + +[tag greenBackground]#✓# Metadata APIs + +[tag greenBackground]#✓# Admin APIs + +[tag greenBackground]#✓# TML APIs + +[tag greenBackground]#✓# APIs for dependent objects + +[tag greenBackground]#✓# Search data API + +[tag greenBackground]#✓# Liveboard data API + +[tag greenBackground]#✓# Liveboard export API + +[tag greenBackground]#✓# Security APIs + +[tag greenBackground]#✓# Log Streaming Service API + +See xref:rest-api-reference.adoc[REST API v1 Reference] for a complete list of endpoints. + + +a| +[tag greenBackground]#✓# Session APIs + +[tag greenBackground]#✓# User APIs + +[tag greenBackground]#✓# Group APIs + +[tag greenBackground]#✓# Connection APIs + +[tag greenBackground]#✓# Metadata APIs + +[tag greenBackground]#✓# Admin APIs + +[tag greenBackground]#✓# TML APIs + +[tag greenBackground]#✓# APIs for dependent objects + +[tag greenBackground]#✓# Data API + +[tag greenBackground]#✓# Visualization export API + +[tag greenBackground]#✓# Custom actions API + +[tag greenBackground]#✓# Liveboard export API + +[tag greenBackground]#✓# Security APIs + +[tag greenBackground]#✓# Log Streaming Service API + +See xref:rest-api-v2-reference.adoc[REST API V2 Reference] for a complete list of endpoints. + +|Resource URL a| +Base URI: `\https:///callosum/v1/` + +Resource path: `tspublic/v1///` + +|Base URI: `\https:///tspublic/rest/v2/` + +Resource path: `/` +|==== + +-- + diff --git a/docs/src/asciidocs/rest-api-v1v2-comparison.adoc b/docs/src/asciidocs/rest-api-v1v2-comparison.adoc new file mode 100644 index 000000000..48a8d2240 --- /dev/null +++ b/docs/src/asciidocs/rest-api-v1v2-comparison.adoc @@ -0,0 +1,457 @@ += REST API v1 and v2.0 comparison +:toc: true +:toclevels: 1 + + +:page-title: Difference between REST API v1 and v2.0 +:page-pageid: v1v2-comparison +:page-description: Difference between REST API v1 and v2.0 + +Both v1 and v2 REST API frameworks allow you to access, retrieve, create, and manage ThoughtSpot objects and resources. REST API v2.0 is a new framework that expands the core API functionality with additional features and improved user experience. + +== Feature comparison +[div tableContainer] +-- +[width="100%" cols="4,^5,^5"] +[options='header'] +|===== +|Feature|REST API v1| REST API v2.0 +|API Playground|Go to *Develop* > *REST API* > *REST API v1 Playground*. + +REST API v1 endpoints can be accessed via Swagger API explorer. + +| Go to *Develop* > *REST API* > *REST API v2.0 Playground*. +|Playground access|Requires admin or developer privilege + +|Requires admin or developer privilege +|Downloadable code samples| [tag greyBackground]#X# | [tag greenBackground]#✓# +|API documentation| [tag greenBackground]#✓# xref:rest-api-reference.adoc[Developer Documentation] a| + +[tag greenBackground]#✓# +++API Playground Help +++ + + +[tag greenBackground]#✓# xref:rest-api-v2.adoc[Developer Documentation] + +|Authentication support a| [tag greenBackground]#✓# Basic authentication + + +[tag greenBackground]#✓# Trusted authentication + +a| [tag greenBackground]#✓# Basic authentication + + +[tag greenBackground]#✓# Bearer token authentication + + +[tag greenBackground]#✓# Trusted authentication + +|Request and Response structure| Not fully standardized |Standardized + +|API services a| See xref:rest-api-v1v2-comparison.adoc##apiOps[Supported API operations] +a| See xref:rest-api-v1v2-comparison.adoc##apiOps[Supported API operations] +a| +Resource URL a| +*Base URI* + +`\https://{your-thoughtspot-hostname}/callosum/v1/` + +*Resource path* + +`tspublic/v1/{resource-group}/{resource}/` +|*Base URI* + +`\https://{your-thoughtspot-hostname}/` + +*Resource path* + +`/api/rest/2.0/{resource-group}/{resource}` +|==== +-- + + +[#apiOps] +== Supported API operations +[div tableContainer] +-- +[width="100%" cols="5,4,4"] +[options='header'] +|===== +|API service|REST API v1| REST API v2.0 +a|*Admin services* + +API endpoints for cluster-level administration | [tag greenBackground]#✓# Available a| [tag greenBackground]#✓# Available + + +__Available under *system* __ + +__Includes query APIs only__ + +|*Authentication* + +API endpoints for user login, authentication, and session management a|[tag greenBackground]#✓# Available + + +__The login, authentication, token generation, and logout services are available under **session**__. +|[tag greenBackground]#✓# Available + + +|*Data APIs* + +Data query APIs for searching data from a data source and querying a Liveboard and its visualization data.|[tag greenBackground]#✓# Available|[tag greenBackground]#✓# Available + +|*Connection and live query services* +API endpoints for CRUD operations of data connection objects |[tag greenBackground]#✓# Available| [tag greenBackground]#✓# + +|*Database services* + +Data management API services for databases such as Falcon + + +__Applicable to ThoughtSpot Software deployments only__ |[tag greenBackground]#✓# Available| [tag greyBackground]#–# + +|*Dependency services* + +API endpoints for querying dependent object details. |[tag greenBackground]#✓# Available| [tag greenBackground]#✓# Available + + +__Available as part of metadata API operations__. + +|*Groups* + +API endpoints for group administration and management|[tag greenBackground]#✓# Available| [tag greenBackground]#✓# Available + +|*Liveboard export* + +API for downloading Liveboard and visualizations data as PDF| +[tag greenBackground]#✓# Available| [tag greenBackground]#✓# Available + + +__This API service is available under *report*.__ + +|*Logs* + +API for audit logs + +__Applicable to ThoughtSpot Cloud deployments only__ |[tag greenBackground]#✓# Available| [tag greenBackground]#✓# Available + +|*Materialization services* + +API endpoint for refreshing a materialized view. + + +__Applicable to ThoughtSpot Software deployments only__ |[tag greenBackground]#✓# Available| [tag greyBackground]#–# + +|*Metadata services* + + +API for querying metadata objects, assigning tags, setting favorites, and importing and exporting TML objects|[tag greenBackground]#✓# Available + + +__The metadata API service does not support fetching SQL query information from Answer and Liveboard objects__|[tag greenBackground]#✓# Available + + +__Supports fetching SQL query information from Answer and Liveboard objects + +__Includes API services for importing and exporting TML representation of metadata objects such as Liveboard, Worksheets, and Answers__ + +|*Orgs* + +API endpoints for Org administration and management | [tag greenBackground]#✓# Available |[tag greenBackground]#✓# Available + +|*Reports* + +API endpoints for downloading Liveboards and Answers in PDF, PNG, XLS, or CSV format.| [tag greenBackground]#✓# Available + + +__The Answer download API service is not available__ |[tag greenBackground]#✓# Available + +|*Session* + +API endpoints for user login, authentication token generation, default Liveboard assignment, and user logout.| [tag greenBackground]#✓# Available |[tag greenBackground]#✓# Available + + +__The login, authentication, token generation, and logout services are available as *session* resource and are listed under the *Authentication* category in the Playground__. + +|*Security* + +API endpoints for sharing objects and assigning permissions. |[tag greenBackground]#✓# Available|[tag greenBackground]#✓# Available + +|*System* + +API endpoints for querying system information a|[tag greenBackground]#✓# Available + + +__The system administration API operations are available as **Admin services**__|[tag greenBackground]#✓# Available + +|*TML* + +API endpoints for importing and exporting TML representation of metadata objects|[tag greenBackground]#✓# Available|[tag greenBackground]#✓# Available + + +__The import and export metadata API service is available under *metadata*__. + +|*User* + +API endpoints for user administration and management |[tag greenBackground]#✓# Available|[tag greenBackground]#✓# Available + +|*Version control* + +API endpoints for Git integration and versio control |[tag greyBackground]#-# Not Available +|[tag greenBackground]#✓# Available + +|===== +-- + +== Request methods +[div tableContainer] +-- +[width="100%" cols="7,7"] +[options='header'] +|===== +|REST API v1| REST API v2.0 +a| +* `GET` for query APIs + +* `POST` for create operations. API calls that support multiple fields for filtering data also use the `POST` method. + +* `PUT` for update operations + +* `DELETE` for delete operations + + +Some `GET` and `DELETE` operations support query and path parameters, whereas the `POST` and `PUT` calls require a JSON request body. +a|* `POST` + +In REST API v2.0 framework, most of the API operations require you to use the `POST` method. + +* `GET` + +For some API operations, such as querying system information or session information, you can use the `GET` method. +|===== +-- +== Object types and naming convention + +The following table lists the metadata object types and sub-types supported in REST API v1 and REST API v2.0: + +[div tableContainer] +-- +[width="100%" cols="7,5"] +[options='header'] +|===== +|REST API v1 | REST API v2.0 +a| +Metadata object types in REST API v1: + +* `QUESTION_ANSWER_BOOK` for Answers + +* `PINBOARD_ANSWER_BOOK` for Liveboards + +* `LOGICAL_TABLE` for a Table, Worksheet, or View. + +Includes the following sub-types: +** `ONE_TO_ONE_LOGICAL` for tables + +** `WORKSHEET` for worksheets. + +** `USER_DEFINED` for data imported by users + +** `AGGR_WORKSHEET` for views + +* `TAG` for tag objects +* `DATA_SOURCE` for data source objects +* `USER` for user objects +* `USER_GROUP` for user group objects +* `LOGICAL_COLUMN` for a column of any data object such as tables, worksheets, or views +* `LOGICAL_RELATIONSHIP` for table or worksheet joins ++ +The `LOGICAL_COLUMN` and `LOGICAL_RELATIONSHIP` metadata types include the following sub-types: + +** `FORMULA` to query a list of formulas applied to a worksheet column + +** `CALENDAR_TYPE` to query the type of calendar used by the DATE TYPE column in a worksheet + +** `CALENDAR_TABLE` to query columns that have a custom calendar configured +a| Metadata object types in REST API v2.0: + +* `LIVEBOARD` for Liveboards +* `ANSWER` for saved Answer object +* `CONNECTION` for data connections +* `TAG` for tag objects +* `USER` for user objects +* `USER_GROUP` for groups +* `LOGICAL_TABLE` for Table, Worksheet, or View. +* `LOGICAL_COLUMN` for a column of any data object such as tables, worksheets, or views. +* `LOGICAL_RELATIONSHIP` for table and worksheet joins + +__Querying metadata objects by sub-types is not supported in the current release__. + +|===== +-- +== Request and response structure + +In REST API v2.0, the API endpoints let you pass several request parameters in a single API call. User and group administration and metadata query APIs support several distinct operations. + +The following example shows the REST API v1 and v2 endpoints available for user administration and provisioning: + +[.widthAuto] +[.bordered] +image::./images/v1-v2-comparison.png[REST API v1 and v2 comparison,link="./doc-images/images/v1-v2-comparison.png"] + +Although the REST API v2.0 has fewer endpoints, it supports all user administration and CRUD operations that were available with REST API v1. + +=== Request body +The following example shows the API v1 and v2 request body for user creation operation: + +REST API v1:: + +`POST /tspublic/v1/user/` + ++ +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +-d 'name=UserA&password=GuestTest123!&displayname=User A&properties={ "userContent": {"userPreferences": {"showWalkMe": true}}}&groups=["d0326b56-ef23-4c8a-8327-a30e99bcc72b"]&usertype=LOCAL_USER&visibility=DEFAULT&triggeredbyadmin=true' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/' +---- + +REST API v2.0:: + +`POST /api/rest/2.0/users/create` + ++ +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/users/create' \ + -H 'Authorization: Bearer {OAUTH_TOKEN}'\ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "name": "UserB", + "display_name": "User B", + "password": "123Cloud!", + "email": "UserA@example.com", + "account_type": "LOCAL_USER", + "account_status": "ACTIVE", + "group_identifiers": [ + "ADMINISTRATOR" + ], + "visibility": "SHARABLE", + "show_onboarding_experience": true, + "notify_on_share": true, + "home_liveboard_identifier": "eee701ad-10d2-4bd5-b268-e07c123569c8", + "favorite_metadata": [ + { + "identifier": "59a8ae34-3609-4385-9f6b-871b74c901a3", + "type": "LIVEBOARD" + }, + { + "identifier": "beb2344c-215b-46a0-b518-3e933365bfc2", + "type": "ANSWER" + } + ] +}' + +---- + +=== Response structure +[div tableContainer] +-- +[width="100%" cols="7,7"] +[options='header'] +|===== +|REST API v1| REST API v2.0 +a| +API response for `GET /tspublic/v1/user/`: + +[source,JSON] +---- +{ + "userContent": { + "userPreferences": { + "notifyOnShare": true, + "showWalkMe": true, + "analystOnboardingComplete": false, + "numTimesDisplayNameDialogShown": 1, + "preferredLocale": "en-US" + }, + "userProperties": { + "persona": "BUSINESS_USER", + "mail": "tsadmin@thoughtspot.com" + } + }, + "state": "ACTIVE", + "assignedGroups": [ + "d0326b56-ef23-4c8a-8327-a30e99bcc72b", + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "inheritedGroups": [ + "d0326b56-ef23-4c8a-8327-a30e99bcc72b", + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "privileges": [], + "type": "LOCAL_USER", + "parenttype": "USER", + "visibility": "DEFAULT", + "tenantId": "982d6da9-9cd1-479e-b9a6-35aa05f9282a", + "displayName": "Administrator", + "header": { + "id": "59481331-ee53-42be-a548-bd87be6ddd4a", + "indexVersion": 55, + "generationNum": 55, + "name": "tsadmin", + "displayName": "Administrator", + "author": "0f0dd0f7-7411-4195-a4aa-0dc6b58413c9", + "created": 1354006445722, + "modified": 1674640734259, + "modifiedBy": "59481331-ee53-42be-a548-bd87be6ddd4a", + "owner": "59481331-ee53-42be-a548-bd87be6ddd4a", + "isDeleted": false, + "isHidden": false, + "clientState": { + "preferences": { + "sageDataSource": [ + "540c4503-5bc7-4727-897b-f7f4d78dd2ff" + ], + "homePinboardId": "b2d68a4f-cf67-4723-966f-8a592fdbf8b9", + "SAGE_SEARCH_BUTTON_TOUR_SEEN": true + }, + "parameters": { + "parametersIntroSplashScreenAppearanceCount": 5 + }, + "tips": { + "navBarHelpTip": true + } + }, + "belongToAllOrgs": true, + "tags": [], + "type": "LOCAL_USER", + "isExternal": false, + "isDeprecated": false, + "isSharedViaConnection": false + }, + "complete": true, + "incompleteDetail": [], + "isSuperUser": false, + "isSystemPrincipal": true +} +---- +a| +API response for `POST /api/rest/2.0/users/search` +[source,JSON] +---- +[ + { + "id": "59481331-ee53-42be-a548-bd87be6ddd4a", + "name": "tsadmin", + "display_name": "Administrator", + "visibility": "SHARABLE", + "author_id": "0f0dd0f7-7411-4195-a4aa-0dc6b58413c9", + "can_change_password": true, + "complete_detail": true, + "creation_time_in_millis": 1354006445722, + "current_org": { + "id": 0, + "name": "Primary" + }, + "deleted": false, + "deprecated": false, + "account_type": "LOCAL_USER", + "account_status": "ACTIVE", + "email": "", + "expiration_time_in_millis": 1674636710, + "external": false, + "favorite_metadata": [], + "first_login_time_in_millis": 1638322388839, + "group_mask": 6, + "hidden": false, + "home_liveboard": null, + "incomplete_details": [], + "is_first_login": false, + "modification_time_in_millis": 1674608622609, + "modifier_id": "59481331-ee53-42be-a548-bd87be6ddd4a", + "notify_on_share": true, + "onboarding_experience_completed": false, + "orgs": null, + "owner_id": "59481331-ee53-42be-a548-bd87be6ddd4a", + "parent_type": "USER", + "privileges": [ + "ADMINISTRATION", + "AUTHORING", + "USERDATAUPLOADING", + "DATADOWNLOADING", + "DATAMANAGEMENT", + "SHAREWITHALL", + "A3ANALYSIS" + ], + "show_onboarding_experience": true, + "super_user": false, + "system_user": true, + "tags": [], + "tenant_id": "982d6da9-9cd1-479e-b9a6-35aa05f9282a", + "user_groups": [ + { + "id": "d0326b56-ef23-4c8a-8327-a30e99bcc72b", + "name": "Administrator" + } + ], + "user_inherited_groups": [ + { + "id": "d0326b56-ef23-4c8a-8327-a30e99bcc72b", + "name": "Administrator" + } + ], + "welcome_email_sent": false + } +] +---- +|===== +-- + +== Related information + +* xref:rest-api-v1.adoc[REST API v1] +* xref:rest-api-v2.adoc[REST API v2.0] +* xref:rest-api-reference.adoc[REST API v1 reference] +* xref:rest-api-v2-reference.adoc[REST API v2 reference] + diff --git a/docs/src/asciidocs/rest-api-v2-getstarted.adoc b/docs/src/asciidocs/rest-api-v2-getstarted.adoc new file mode 100644 index 000000000..2b1ff301d --- /dev/null +++ b/docs/src/asciidocs/rest-api-v2-getstarted.adoc @@ -0,0 +1,199 @@ += Get started with REST API v2.0 +:toc: true +:toclevels: 2 + +:page-title: Getting started with REST API v2.0 +:page-pageid: rest-apiv2-getstarted +:page-description: Get started with REST API v2.0 to access, create, and manage ThoughtSpot resources programmatically. + +Before you get started with REST API v2.0, visit the REST API v2.0 Playground to view the endpoints and try out the API requests. + +== Visit the API Playground + +To access the REST API v2.0 Playground, go to **Develop** > **REST API** > **REST Playground v2.0**. + +The Playground allows you to make API calls, view the request and response workflows, and create and download code samples. + +++++ +Go to Playground +++++ + +== Set up your environment + +By default, your cluster URL is set as the base path for your API requests. + +* To allow a REST client to log in to ThoughtSpot using `username` and `password`, create a local user account in ThoughtSpot. +* To use OAuth 2.0 authentication method, make sure your ThoughtSpot instance has the required configuration to support the OpenID Provider or IdP that authenticates your users. +* To trusted authentication to authenticate REST clients, make sure xref:trusted-authentication.adoc#trusted-auth-enable[Trusted authentication is enabled] on your ThoughtSpot instance, and your authenticator service has access to the `secret key`. + +== Authorize your client + +To provide secure access to ThoughtSpot resources, the REST API v2.0 framework supports token-based authentication method. However, for local development or testing purposes, you can use basic authentication with `userName` and `password`. + +To get a token that provides access to ThoughtSpot resources, you can send a `POST` request to one of the following API endpoints: + +* `/api/rest/2.0/auth/token/object` ++ +Provides a token to access a specific metadata object such as a Liveboard or saved Answer. + +* `api/rest/2.0/auth/token/full` ++ +Provides full access to ThoughtSpot. + +For example, to get a bearer token that grants full access to ThoughtSpot application, send the following attributes in the request body: + +.cURL +[sourc,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/full' \ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "username": "tsUserA", + "password": "Guest@123!" + "validity_time_in_sec": 86400 +}' +---- + +If the API request is successful, the server returns the access token in the response body. + +[source,JSON] +---- +{ + "token": "{access-token}", + "creation_time_in_millis": 1675129264089, + "expiration_time_in_millis": 1675129564089, + "scope": { + "access_type": "FULL", + "org_id": 1, + "metadata_id": null + }, + "valid_for_user_id": "59481331-ee53-42be-a548-bd87be6ddd4a", + "valid_for_username": "tsUserA" +} +---- + +[NOTE] +==== +By default, the bearer token is valid for 300 seconds. You can configure the token expiry duration as per your requirement or request a new token for your API sessions. If you send an API request with an expired token, the server returns an error. +==== + +== Log in to ThoughtSpot + +To log in to ThoughtSpot, send a `POST` request to the `/api/rest/2.0/auth/session/login` API endpoint. In your API request, you can either specify your `username` and `password` or use your bearer token in the authorization header. + +After a successful login, a session cookie is set for your subsequent API calls. REST clients accessing APIs in a non-browser environment must set session cookies in the request header when making an API call. + +== Make a test API call + +To make a test API call, send an API request to an API endpoint. For example, to get a list of Liveboard objects, send the following request: + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-host}/api/rest/2.0/metadata/search' \ + -H 'Authorization: Bearer {access_token}' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata": [ + { + "type": "LIVEBOARD" + } + ] +}' +---- + +++++ +Try it out +++++ + +=== Request headers + +Each API call must include the following headers. + +* `'Authorization: Bearer {access_token}'` ++ +The authorization header must include the OAuth token obtained from ThoughtSpot. + +* `'Content-Type: application/json'` ++ +The header to indicate the content type for the request body. + +* `'Accept: application/json'` ++ +The `Accept` header for API response format. + +//// +* `X-Requested-By` __Optional__ ++ +The `'X-Requested-By: ThoughtSpot'` header in API requests to ThoughtSpot REST endpoints. +//// +* `User-Agent` ++ +The `User-Agent` header is required for all requests. Most clients will add the `User-Agent` header automatically. However, when making API calls from code, especially `.NET`, you must add the `User-Agent` header. + ++ +The `User-Agent` can be any string; for example, you can set the header as `'User-Agent: /'`. + +=== Request body + +The API calls require you to specify the GUID or name of the object as an identifier. For example, to get details of a user object, you can specify either the GUID or name of the user. + +The API Playground indicates the required and optional parameters and provides information about the data type and allowed values. For example, to get a list of answers, you must specify the metadata `type` as `Answer`. + +The following example shows the cURL request format to get a list of answers saved in the ThoughtSpot system. + +[source,curl] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-host}/api/rest/2.0/metadata/search' \ + -H 'Authorization: Bearer {access_token}'\ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata": [ + { + "type": "ANSWER" + } + ] +} +---- + +=== API response + +A successful API call returns a response body or the 204 response code. The REST API v2.0 framework supports standard HTTP response codes to indicate the status of a request. + +* *200* ++ +Indicates a successful operation. The API returns a response body. +* *204* ++ +Indicates a successful operation. The 204 response does not include a response body. +* *400* ++ +Indicates a bad request. You may have to modify the request before making another call. +* *401* ++ +Indicates an unauthorized request. Check if you have the required credentials and object access to send the API request. + +* *403* ++ +Indicates forbidden access. Check your access privileges and user account status. + +* *415* ++ +Indicates an unsupported media type. Check the media type specified in the `Content-Type` header. + +* *500* ++ +Indicates an internal server error. Check if the data format of the request is supported. Verify if the server is available and can process the request. + +If an API call returns an error in the Playground, you can view the error details by navigating to *root* > *error* > *message* > *debug* in the error response body. + +[.widthAuto] +image::./images/rest-v2-error.png[REST API v2.0 error codes width=auto] + +== Example libraries +The link:https://github.com/thoughtspot/thoughtspot_rest_api_v1_python[thoughtspot_rest_api_v1 Python library, window=_blank] includes a `TSRestApiV2` class that implements the v2.0 REST API. You can use this as a ready-made implementation for testing back-end REST API calls or as a pattern for implementing your own library in any other programming language. diff --git a/docs/src/asciidocs/rest-api-v2-playground.adoc b/docs/src/asciidocs/rest-api-v2-playground.adoc new file mode 100644 index 000000000..6124178e3 --- /dev/null +++ b/docs/src/asciidocs/rest-api-v2-playground.adoc @@ -0,0 +1,88 @@ += REST API v2.0 Playground +:toc: true + +:page-title: ThoughtSpot REST API v2.0 Playground +:page-pageid: restV2-playground +:page-description: ThoughtSpot REST API v2.0 Playground + +The REST API v2.0 Playground offers an interactive portal with API resources, comprehensive documentation, and a code panel to view the request and response workflows. + +//// +The Playground allows you to make REST API calls in the programming language of your choice. You can also view the SDK, request and response workflow. +//// +To access the Playground, click *Develop* > *REST API* > **REST Playground v2.0**. + +[.bordered] +[.widthAuto] +image::./images/v2-0-playground.png[REST API v2.0 Playground] + +== Explore the interface + +The API Playground consists of the following areas: + +Resource pane:: + +In the resource pane, you can find a catalog of API endpoints, grouped based on the objects they operate on. You can also view the API documentation, data structure of requests, response format, and attribute enumerations. + ++ +The search bar in the resource pane allows you to search for an endpoint and navigate between different endpoints in the list. + +API request editor:: + +The middle section of the portal provides a short description of the endpoint, endpoint URL, request parameters, and response codes. For parameters that require a JSON array, you can add each string in the array as a separate item. + ++ +[.bordered] +[.widthAuto] +image::./images/array-example.png[REST API v2 Playground] + +Code explorer:: + +The code explorer offers several distinct features: + +* Code panel ++ +Shows a preview of the API request code. You can view the request body as you edit the input parameters and define attributes in the API editor area. + +* Try it out ++ +Allows you to trigger an API call. If the request succeeds, the API returns the 200 response code. You can copy or download the entire API response. You can also copy the individual attributes using the copy button that appears next to the field. To try another API call, click the **Request** tab. + +* Copy icon ++ +Allows you to copy API requests and responses. + +* Configuration panel ++ +Allows you to modify the client configuration settings. For example, you can update the access token of the client. To view this panel, click **Configure**. + +* Download icon ++ +Allows you to download the API response JSON file to your local directory. + +//// +Language selection drop-down:: + +The language selection drop-down above the code explorer allows you to switch between different programming languages and view code samples. + +You can also use this drop-down to get language-specific SDK and client libraries. +//// + +++++ +Try it out +++++ + +//// +== SDK and client libraries + +To download the SDK library for a specific language, select the language and click **Get SDK**. To know how to set up and use SDK libraries, click *Setup and Usage*. + +You can also download the SDK and API libraries from the following public resources: + +* link:https://github.com/thoughtspot/rest-api-sdk[GitHub repository, window=_blank] +* link:https://www.npmjs.com/package/@thoughtspot/rest-api-sdk[NPM site, window=_blank] +* link:https://pypi.org/project/thoughtspot-rest-api-sdk/[PyPi, window=_blank] +* link:https://www.nuget.org/packages/thoughtspot.rest.api.sdk[NuGet package manager, window=_blank] + +For more information, see xref:rest-api-sdk-libraries.adoc[REST API SDK and client libraries]. +//// diff --git a/docs/src/asciidocs/rest-api-v2-reference-beta.adoc b/docs/src/asciidocs/rest-api-v2-reference-beta.adoc new file mode 100644 index 000000000..f248436d7 --- /dev/null +++ b/docs/src/asciidocs/rest-api-v2-reference-beta.adoc @@ -0,0 +1,1037 @@ += REST API v2 ^Beta^ endpoints (Deprecated) +:toc: true + +:page-title: REST API Reference Guide +:page-pageid: rest-apiv2-beta-reference +:page-description: REST API Reference + +[div announcementBlock] +-- +Starting from the ThoughtSpot Cloud 9.0.0.cl release, REST API v2 endpoints[beta betaBackground]^Beta^ are deprecated and removed from the ThoughtSpot API Playground. The API Playground will display the REST API V2 endpoints that are qualified for General Availability (GA). + +For detailed information about the endpoints listed in this article, see link:https://visual-embed-sdk-git-redoc-api-docs-thoughtspot-site.vercel.app/docs/apiv2Beta/index.html[REST API V2 (Beta) documentation, window=_blank]. +-- + +The REST API v2 endpoints[beta betaBackground]^Beta^ includes the following resource collections and endpoints. + +== Session + +-- +`**GET** /tspublic/rest/v2/session` + +Gets details of the current session for the logged-in user. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/session/login` + +Signs in a user to ThoughtSpot. + ++++

+++ + +//// +++++ +View in Playground +++++ +//// + + +`**POST** /tspublic/rest/v2/session/gettoken` + +Gets an OAuth access token for a ThoughtSpot client. You must send this token in the `Authorization` header to authorize your API requests. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**POST** /tspublic/rest/v2/session/revoketoken` + +Revokes an existing access token assigned to a ThoughtSpot client. To make API calls, you must obtain a new access token. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**POST** /tspublic/rest/v2/session/logout` + +Logs out a ThoughtSpot user. +//// +++++ +View in Playground +++++ +//// +-- + +== Users +-- + +`*POST* /tspublic/rest/v2/user/create` + +Creates a user object. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`GET /tspublic/rest/v2/user` + +Gets details of a specific user. You must provide the username or the GUID of the user. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*PUT* /tspublic/rest/v2/user/update` + +Modifies the properties of a user object. You must specify a username or the GUID of the user. Requires administrator privileges. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`DELETE /tspublic/rest/v2/user/delete` + +Deletes a user object. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**PUT** /tspublic/rest/v2/user/addgroup` + +Assigns a user to groups. If the assigned groups have privileges configured, the user inherits these privileges. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*PUT* /tspublic/rest/v2/user/removegroup` + +Removes the groups assigned to a user. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**PUT** /tspublic/rest/v2/user/changepassword` + +Allows changing a ThoughtSpot user's password. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**POST** /tspublic/rest/v2/user/search` + +Gets a list of users available in the ThoughtSpot system. To filter your query, you can specify the user type, group, privileges, sharing visibility, and other such attributes. +//// +++++ +View in Playground +++++ +//// +-- + +== Groups + +-- +`*GET* /tspublic/rest/v2/group` + +Gets details of a specific group. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/group/create` + +Creates a group object. Requires administrator privileges. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**PUT** /tspublic/rest/v2/group/update` + +Modifies the properties of a group object. Requires administrator privileges. +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**PUT **/tspublic/rest/v2/group/addprivilege` + +Assigns privileges to a group. Requires administrator privileges. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**PUT **/tspublic/rest/v2/group/removeprivilege` + +Removes privileges assigned to a group. Requires administrator privileges. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**DELETE** /tspublic/rest/v2/group/delete` + +Deletes a group object. Requires administrator privileges. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/group/adduser` + +Assigns users to a group. Requires administrator privileges. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**PUT **/tspublic/rest/v2/group/removeuser` + +Removes one or several users assigned to a group. Requires administrator privileges. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*PUT* /tspublic/rest/v2/group/addgroup` + +Adds a group to another group object. This API request creates a hierarchy of groups. The subgroups inherit the privileges assigned to the parent group. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**PUT** /tspublic/rest/v2/group/removegroup` + +Removes a group from the parent group. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/group/search` + +Gets a list of groups created in the ThoughtSpot system. To filter your query, you can specify the group type, group name, privileges, sharing visibility, users, and other such attributes. +//// +++++ +View in Playground +++++ +//// +-- + +== Admin + +-- +`**GET ** /tspublic/rest/v2/admin/configuration` + +Gets details of the current configuration of a ThoughtSpot cluster. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*GET* /tspublic/rest/v2/admin/configuration/overrides` + +Gets details of configuration overrides. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**PUT **/tspublic/rest/v2/admin/configuration/update` + +Updates configuration settings of the ThoughtSpot cluster. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*PUT* /tspublic/rest/v2/admin/resetpassword` + +Resets the password of a user account. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/admin/syncprincipal` + +Synchronizes user account and group properties from an external database with ThoughtSpot. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/admin/changeauthor` + +Transfers the ownership of objects from one user to another. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/admin/assignauthor` + +Assigns ownership of objects to a specific user. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/admin/forcelogout` + + +Logs out specified users from ThoughtSpot. + +//// +++++ +View in Playground +++++ +//// +-- + +== Metadata + +-- +`*GET* /tspublic/rest/v2/metadata/tag` + +Gets details for the specified tag. You must specify the tag name or the GUID. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/metadata/tag/create` + +Creates a tag object. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/metadata/tag/update` + +Modifies the properties of a tag object. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/metadata/tag/assign` + +Assigns a tag to one or several metadata objects. You can assign a tag to a Liveboard, Answer, data object, and data connection objects. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/metadata/tag/unassign` + +Removes the tag assigned to an object. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*DELETE* /tspublic/rest/v2/metadata/tag/delete` + +Deletes the specified tag. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**PUT** /tspublic/rest/v2/metadata/favorite/assign` + +Adds an object such as Liveboards and answers to a user's favorites list. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**PUT ** /tspublic/rest/v2/metadata/favorite/unassign` + +Removes the specified object from the user's favorites list. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**GET** /tspublic/rest/v2/metadata/homeliveboard` + +Gets the details of the Liveboard that is set as a default Liveboard for the ThoughtSpot user. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**PUT** /tspublic/rest/v2/metadata/homeliveboard/assign` + +Assigns a Liveboard as a default Liveboard for a ThoughtSpot user. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/metadata/homeliveboard/unassign` + +Removes the default home Liveboard setting for a ThoughtSpot user. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*GET* /tspublic/rest/v2/metadata/incomplete` + +Gets a list of objects with incomplete metadata. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*GET* /tspublic/rest/v2/metadata/header` + +Gets header details for a specific metadata object. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*GET* /tspublic/rest/v2/metadata/details` + +Gets details of a specific metadata object. To filter your query, specify the metadata object type and the ID. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*GET* /tspublic/rest/v2/metadata/vizheaders` + +Gets a list of visualization headers associated with a Liveboard. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/metadata/header/search` + +Gets a list of all metadata objects in the ThoughtSpot system. To filter your query, specify the metadata object type, access level, and other such attributes. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*POST* /tspublic/rest/v2/metadata/detail/search` + +Gets details of one or several metadata objects of a specific type. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*DELETE* /tspublic/rest/v2/metadata/delete` + +Deletes the specified metadata object. You can delete answers, Liveboards, tags, worksheets, views, tables, columns, and table joins. + +Note that the endpoint does not support deleting the connection, user, and group objects. To delete these objects, use the following endpoints: + +* `DELETE /tspublic/rest/v2/connection/delete` +* `DELETE /tspublic/rest/v2/user/delete` +* `DELETE /tspublic/rest/v2/group/delete` + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/metadata/dependency` + +Gets a list of dependent metadata objects. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*POST* /tspublic/rest/v2/metadata/tml/export` + +Exports a TML object and associated metadata. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**POST** /tspublic/rest/v2/metadata/tml/import` + +Imports one or several TML objects and object associations. + +//// +++++ +View in Playground +++++ +//// +-- + +== Connections + +-- +`*GET* /tspublic/rest/v2/connection` + +Gets details of a specific data connection. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**GET** /tspublic/rest/v2/connection/database` + +Gets details of the databases associated with a connection ID. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**POST** /tspublic/rest/v2/connection/table` + +Gets details of the tables associated with a connection ID. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*POST* /tspublic/rest/v2/connection/tablecoloumn` + +Gets details of the columns of the tables associated with a connection ID. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*POST* /tspublic/rest/v2/connection/create` + +Creates a data connection. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*PUT* /tspublic/rest/v2/connection/update` + +Updates an existing data connection. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +*DELETE* /tspublic/rest/v2/connection/delete + +Deletes a data connection. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/connection/addtable` + +Adds a table to an existing data connection. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*PUT* /tspublic/rest/v2/connection/removetable` + +Removes a table from an existing data connection. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*POST* /tspublic/rest/v2/connection/search` + +Gets details of all data connections. You can also query data for a specific connection type. + +//// +++++ +View in Playground +++++ +//// +-- + +== Data + +-- +`**POST** /tspublic/rest/v2/data/search` + +Allows constructing a search query string and retrieves data from a search query. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`**POST** /tspublic/rest/v2/data/answer` + +Gets data from a saved search answer. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**POST** /tspublic/rest/v2/data/liveboard` + +Gets data from the specified Liveboard and visualization. + +//// +++++ +View in Playground +++++ +//// +-- + ++++

+++ + +`*GET* /tspublic/rest/v2/data/answer/querysql` + +Retrieves SQL for an Answer object. + +//// +++++ +View in Playground +++++ +//// +-- + ++++

+++ + +`*GET* /tspublic/rest/v2/data/liveboard/querysql` + +Retrieves SQL for a visualization on a Liveboard. + +//// +++++ +View in Playground +++++ +//// +-- + +== Report + +-- +`*POST* /tspublic/rest/v2/report/answer` + +Downloads Answer data in the specified file format, such as PDF, CSV, PNG, and XLSX. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**POST** /tspublic/rest/v2/report/liveboard` + +Downloads a given Liveboard and its visualizations as a PDF, CSV, XLSX, or PNG file. + +//// +++++ +View in Playground +++++ +//// +-- + +== Security + +`*POST* /tspublic/rest/v2/security/share/tsobject` + +Allows sharing an object with another user or group in ThoughtSpot. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**POST** /tspublic/rest/v2/security/share/visualization` + +Allows sharing a Liveboard visualization with another user or group in ThoughtSpot. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**GET** /tspublic/rest/v2/security/permission/tsobject` + +Gets access permission details for a metadata object. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*GET* /tspublic/rest/v2/security/permission/principal` + +Gets a list of objects that the specified user or group has access to. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*POST* /tspublic/rest/v2/security/permission/tsobject/search` + +Gets permission details for specific objects, and users and groups who have access to these objects. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*POST* /tspublic/rest/v2/security/permission/principal/search` + +Gets a list objects to which a user or group has `READ_ONLY` or `MODIFY` permissions. + +//// +++++ +View in Playground +++++ +//// + +== Custom actions + +`*GET* /tspublic/rest/v2/customaction` + +Gets details of a custom action. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**POST **/tspublic/rest/v2/customaction/create` + +Creates a custom action. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**PUT** /tspublic/rest/v2/customaction/update` + +Updates a custom action object. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**DELETE** /tspublic/rest/v2/customaction/delete` + +Deletes a custom action object. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**POST** /tspublic/rest/v2/customaction/search` + +Allows searching for custom actions available in ThoughtSpot. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`*GET* /tspublic/rest/v2/customaction/association` + +Gets metadata association details for a given custom action. + +//// +++++ +View in Playground +++++ +//// ++++

+++ + +`*PUT* /tspublic/rest/v2/customaction/association/update` + +Updates metadata association for a given custom action. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +`**DELETE **/tspublic/rest/v2/customactions/association/delete` + +Removes custom action association to a user, group or metadata object. + +//// +++++ +View in Playground +++++ +//// + ++++

+++ + +== Log +-- +`*GET* /tspublic/rest/v2/logs/events` + +Gets security audit logs from the ThoughtSpot system. + +//// +++++ +View in Playground +++++ +//// ++++

+++ +-- + +//// +== Materialization +-- +`*PUT* /tspublic/rest/v2/materialization/refreshview` + +Refreshes data in a materialized view. + + +This endpoint is applicable to ThoughtSpot Software deployments only. + +++++ +View in Playground +++++ ++++

+++ +-- + +== Database + +The Database endpoints are applicable to ThoughtSpot Falcon-based Software deployments only. + + +//// diff --git a/docs/src/asciidocs/rest-api-v2-reference.adoc b/docs/src/asciidocs/rest-api-v2-reference.adoc new file mode 100644 index 000000000..1c639bcf9 --- /dev/null +++ b/docs/src/asciidocs/rest-api-v2-reference.adoc @@ -0,0 +1,1179 @@ += REST API v2.0 Reference +:toc: true + + +:page-title: REST API Reference Guide +:page-pageid: rest-apiv2-reference +:page-description: REST API Reference + +This API Reference page lists the REST API v2.0 endpoints and provides basic information about the resource URLs and supported operations. If you want to try out these APIs, view detailed documentation, and download code samples, visit the +++REST API v2.0 Playground+++. + +[NOTE] +==== +Access to ThoughtSpot data is controlled based on xref:api-user-management.adoc#group-privileges[user privileges] and xref:configure-user-access.adoc#_object_level_permissions[object-level permissions]. Some operations are available to all users and may require at least view access to the metadata object. ThoughtSpot users are assigned access privileges based on the group to which they belong. Additionally, object owners can control access to a metadata object using `MODIFY` (*Can edit*), `READ_ONLY` (*Can view*), or `NO_ACCESS` permission when sharing an object with other users and groups. +==== + +== Authentication + +[div divider] +-- ++++

Get current user information

+++ + +`GET /api/rest/2.0/auth/session/user` + + +Gets session information for the currently logged-in user. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Login

+++ + +`POST /api/rest/2.0/auth/session/login` + +Creates a login session for a ThoughtSpot user. + +Requires `username` and `password`. Users can also specify the ID of the Org to which they want to log in. + +If the login is successful, a user session is established. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Get authentication token

+++ + +* `POST /api/rest/2.0/auth/token/object` ++ +Gets an authentication token from ThoughtSpot, which allows access to a specific metadata object in ThoughtSpot. The token obtained from this API call provides only view access to the object specified in the API request. ++ +** To obtain a bearer token, specify the username, password, and object ID in the API request. +** To obtain a token on behalf of a user, specify the username, secret key, and object ID. ++ +__Requires access to the `secret_key`. For more information, see xref:trusted-authentication.adoc#trusted-auth-enable[Trusted authentication]__. + ++ ++++View in Playground+++ + +* `POST /api/rest/2.0/auth/token/full` ++ +Gets an authentication token from ThoughtSpot, which provides access to the full application. ++ +** To obtain a bearer token, specify the username and password in the API request. +** To obtain a token on behalf of a user, specify the username and secret key. ++ +__Requires access to the `secret_key`. For more information, see xref:trusted-authentication.adoc#trusted-auth-enable[Trusted authentication]__. + ++ ++++View in Playground+++ + +//// +[NOTE] +==== +You can copy the `secret key` from *Develop* > *Customizations* > *Security Settings* page if xref:trusted-authentication.adoc#trusted-auth-enable[Trusted authentication] is enabled on your instance. +==== +//// + ++++
Just-in-time user provisioning
+++ + +The `/api/rest/2.0/auth/token/object` and `/api/rest/2.0/auth/token/full` API endpoints also let you provision a user just-in-time (JIT) and assign the new user to Orgs and groups. If a user is not available in ThoughtSpot, administrators can create a user profile by setting `auto_create` to `true`, and provision the user to an Org and groups in an Org. + +For more information, see xref:authentication.adoc[REST API v2.0 authentication]. +-- + +[div divider] +-- ++++

Logout

+++ + +`POST /api/rest/2.0/auth/session/logout` + + +Logs out the currently logged-in user. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Get Current User Token

+++ + +`POST /api/rest/2.0/auth/session/logout` + + +Gets authentication token details for the currently logged-in user. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Revoke token

+++ + +`POST /api/rest/2.0/auth/token/revoke` + + +Revokes authentication token granted for a user. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +== Users + +[div divider] +-- ++++

Search users

+++ + +`POST /api/rest/2.0/users/search` + +Gets user details. You can get the details of a specific user or all user objects available in the ThoughtSpot system. +You can also filter the API output based on groups, Org ID, visibility, account status, user type, user preference settings, user's favorite objects, or home Liveboard setting. + +__Available to all authenticated users__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Create a user

+++ + +`POST /api/rest/2.0/users/create` + +Creates a user in ThoughtSpot. This API also supports the following operations: + + +* add the email address of the user +* add the user to xref:orgs.adoc[Orgs] and groups. +* set account status +* define sharing visibility +* set a default Liveboard for the user +* add Liveboard, Answer, and Worksheet objects to the user's favorites list +* set user preferences to start or stop onboarding walkthrough, and receive an email notification when another user shares an object + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Update a user

+++ + +`POST /api/rest/2.0/users/{user_identifier}/update` + +Allows modifying the properties of a user object. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Delete a user

+++ + +`POST /api/rest/2.0/users/{user_identifier}/delete` + +Deletes a user from ThoughtSpot. + +[NOTE] +==== +In the current release, deleting a user removes the user from ThoughtSpot. If you want to remove a user from a specific Org, update the group and Org mapping properties of the user object via a `POST` API call to the `/api/rest/2.0/users/{user_identifier}/update` endpoint. +==== +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Import users

+++ + +`POST /api/rest/2.0/users/import` + +Allows importing user data from external databases into ThoughtSpot. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + +During this operation: + +* If the specified users are not available in ThoughtSpot, the users are created and assigned a default password. The `default_password` definition in the API request is optional. +* If the `delete_unspecified_users` property is set to `true`, users not specified in the API request, excluding `tsadmin`, `guest`, `system` and `su` users, are deleted. +* If the specified user objects are already available in ThoughtSpot, the object properties of these users are modified and synchronized as per the input data in the API request. + +A successful API call returns the object that represents the changes made in the ThoughtSpot system. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Change password

+++ + +`POST /api/rest/2.0/users/change_password` + +Allows ThoughtSpot users to change the password of their account. + +__Available to all authenticated users__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Reset password

+++ + +`POST /api/rest/2.0/users/reset_password` + +Resets the password of a user account. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Force logout

+++ + +`POST /api/rest/2.0/users/force_logout` + +Forces logout on user sessions. + +[WARNING] +* Use this API with caution as it may invalidate active user sessions and force users to re-login. +* Make sure you specify the usernames or GUIDs. If you pass null values in the API call, all user sessions on your cluster become invalid, and the users are forced to re-login. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +== System + +[div divider] +-- ++++

Get system information

+++ + +`GET /api/rest/2.0/system` + +Gets system information of your current logged-in cluster. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Get System Config

+++ + +`GET /api/rest/2.0/system` + +Gets details of the current configuration running on your cluster. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Get System Override Info

+++ + +`GET /api/rest/2.0/system/config-overrides` + +Gets details of the configuration overrides on your cluster. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Update System Config

+++ + +`POST /api/rest/2.0/system/config-update` + +Updates the current configuration of your cluster. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +== Orgs + +You can perform CRUD operations on Org objects if the Orgs feature is enabled on your cluster. For Org operations, cluster administration privileges are required. + +[NOTE] +==== +To access REST API v2.0 Playground at the Org level, make sure the *Develop* tab is enabled for Orgs on your cluster. +==== + +[div divider] +-- ++++

Search Orgs

+++ + +`POST /api/rest/2.0/orgs/search` + +Gets Org objects from ThoughtSpot. To filter the API output based on Org status, visibility, and user association, set `visibility`, `status`, and `user_identifiers` properties in your API request. + +__Requires cluster administration privileges__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Create an Org

+++ + +`POST /api/rest/2.0/orgs/create` + +Creates an Org object. + +__Requires cluster administration privileges__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Update an Org

+++ + +`POST /api/rest/2.0/orgs/{org_identifier}/update` + +Modifies the object properties of an Org. + +__Requires cluster administration privileges__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Delete an Org

+++ + +`POST /api/rest/2.0/orgs/{org_identifier}/delete` + +Deletes an Org object from ThoughtSpot. + +__Requires cluster administration privileges__. + ++++View in Playground+++ +-- + +== Tags + +API endpoints for CRUD operations on tag objects and metadata association. + +[div divider] +-- ++++

Search tags

+++ + +`POST /api/rest/2.0/tags/search` + +Gets details of tag objects from ThoughtSpot. + +__Available to all authenticated users__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Create a tag

+++ + +`POST /api/rest/2.0/tags/create` + +Creates a tag object in ThoughtSpot. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Update a tag

+++ + +`POST /api/rest/2.0/tags/{tag_identifier}/update` + +Modifies the object properties of a tag. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ + +-- + +[div divider] +-- ++++

Delete a tag

+++ + +`POST /api/rest/2.0/tags/{tag_identifier}/delete` + +Deletes a tag object from ThoughtSpot. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Assign a tag

+++ + +`POST /api/rest/2.0/tags/assign` + +Assigns a tag to metadata objects. + +__Requires edit access to the metadata object (Liveboard, saved Answer, or Worksheet)__. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Unassign a tag

+++ + +`POST /api/rest/2.0/tags/unassign` + +Removes the tag assigned to a metadata object. + +__Requires edit access to the metadata object (Liveboard, saved Answer, or Worksheet)__. + ++++View in Playground+++ +-- + + +== Groups + +API endpoints for CRUD operations on groups objects and groups data import from external databases. + +[div divider] +-- ++++

Search groups

+++ + +`POST /api/rest/2.0/groups/search` + +Gets the details of group objects from ThoughtSpot. You can get the details of a specific group or all groups available in the ThoughtSpot system. You can also filter the API output based on user association, privileges, Org ID, visibility, and group type. + +__Available to all authenticated users__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Create a group

+++ + +`POST /api/rest/2.0/groups/create` + +Creates a group in ThoughtSpot. This API also supports the following operations: + + +* assign privileges +* add users +* define sharing visibility +* add sub-groups +* set a default Liveboard for the users in a group + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Update a group

+++ + +`POST /api/rest/2.0/groups/{group_identifier}/update` + +Allows modifying the object properties of a group. You can also use this API to add or remove users, groups, and privileges. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Delete a group

+++ + +`POST /api/rest/2.0/users/{user_identifier}/delete` + +Deletes a group from ThoughtSpot. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Import groups

+++ + +`POST /api/rest/2.0/groups/import` + +Allows importing group objects from external databases into ThoughtSpot. + +During the import operation: + +* If the specified group is not available in ThoughtSpot, it will be added to ThoughtSpot. +* If the `delete_unspecified_groups` property is set to `true`, the groups not specified in the API request, excluding administrator and system user groups, are deleted. +* If the specified groups are already available in ThoughtSpot, the object properties of these groups are modified and synchronized as per the input data in the API request. + +A successful API call returns the object that represents the changes made in the ThoughtSpot system. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +== Metadata + +API endpoints for querying metadata objects, importing and exporting TML representation of metadata objects, and deleting metadata objects. + +[div divider] +-- ++++

Search metadata objects

+++ + +`POST /api/rest/2.0/metadata/search` + +Gets details of metadata objects from ThoughtSpot. + +* To fetch data for a metadata object, specify the object ID and type. +* To fetch data for a specific object type, for example, Liveboard or saved Answer, specify an object type from the `type` list: + +** `LIVEBOARD` for Liveboards +** `ANSWER` for saved Answer object +** `CONNECTION` for data connections +** `TAG` for tag objects +** `USER` for user objects +** `USER_GROUP` for groups +** `LOGICAL_TABLE` for worksheets, tables and views. +** `LOGICAL_COLUMN` for a column of any data object such as tables, worksheets, or views. +** `LOGICAL_RELATIONSHIP` for table and worksheet joins + +[NOTE] +==== +Searching by metadata sub-types such as `CALENDAR_TYPE` and `FORMULA` is not supported in REST API v2.0. +==== + +The search metadata API allows you to define several parameters to filter the output. For example, you can filter objects created or modified by specific users, or based on the tags assigned to an object. Similarly, you can exclude or include dependent, hidden, and incomplete objects in the output. + +__Requires at least view access to metadata objects. The `USER` and `USER_GROUP` metadata object queries require `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Fetch SQL query details for a Liveboard

+++ + +`POST /api/rest/2.0/metadata/liveboard/sql` + +Gets SQL query data for the visualizations on a Liveboard. + +__Requires at least view access to the Liveboard object__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Fetch SQL query details for an Answer

+++ + +`POST /api/rest/2.0/metadata/answer/sql` + +Gets SQL query data for a saved Answer. + +__Requires at least view access to the Answer object__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Import metadata objects

+++ + +`POST /api/rest/2.0/metadata/tml/import` + +Imports TML representation of the metadata objects into ThoughtSpot. + +__Requires `DATAMANAGEMENT` (**Can manage data**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Export metadata objects

+++ + +`POST /api/rest/2.0/metadata/tml/export` + +Exports TML representation of the metadata objects from ThoughtSpot in JSON or YAML format. + +__Requires `DATAMANAGEMENT` (**Can manage data**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Delete metadata objects

+++ + +`POST /api/rest/2.0/metadata/delete` + +Deletes a metadata object from ThoughtSpot. + +__Requires edit access to metadata objects__. + ++++View in Playground+++ +-- + +== Reports + +API endpoints to download Liveboard or Answer from ThoughtSpot. + +[div divider] +-- ++++

Download a Liveboard report

+++ + +`POST /api/rest/2.0/report/liveboard` + +Downloads a Liveboard and its visualizations as a PDF, CSV, XLSX, or PNG file. + +__Requires `DATADOWNLOADING` (**Can download data**) privilege and view access to the Liveboard object__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Download an Answer report

+++ + +`POST /api/rest/2.0/report/answer` + +Downloads the Answer data in PDF, CSV, PNG, or XLSX format. + +__Requires `DATADOWNLOADING` (**Can download data**) privilege and view access to the Answer object__. + ++++View in Playground+++ +-- + +== Security + +API endpoints that let you share objects and fetch permission details for metadata objects. + +[NOTE] +==== +By default, the JSON response from the `api/rest/2.0/security/principals/fetch-permissions` and `/api/rest/2.0/security/metadata/fetch-permissions` API calls show `group_permissions` as a null object. To allow ThoughtSpot to return group permission details in the API response, the `groupWisePermissionEnabled` flag must be enabled on your instance. For more information, contact ThoughtSpot Support. +==== + +[div divider] +-- ++++

Fetch object permission details for users or groups

+++ + +`POST /api/rest/2.0/security/principals/fetch-permissions` + +Gets a list of objects that a user or group has access to. You can also specify the metadata type to fetch user permission details for Liveboards, Worksheets, or Answers. + +__Requires at least view access to the metadata object__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Fetch permission details for metadata objects

+++ + +`POST /api/rest/2.0/security/metadata/fetch-permissions` + +Fetches access permission details for metadata objects. To get object access details for a user or group, specify the user or group identifiers. + +__Requires at least view access to the metadata object__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Transfer object ownership and assign author

+++ + +`POST /api/rest/2.0/security/metadata/assign` + +Assigns a new author or changes the author of a metadata object. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Share metadata objects

+++ + +`POST /api/rest/2.0/security/metadata/share` + +Allows sharing metadata objects, such as Liveboards, saved Answers, and Worksheets with another user or group in ThoughtSpot. + +__Requires edit access to the metadata object__. + ++++View in Playground+++ +-- + +== Data + +API endpoints to search data from a data source, fetch Liveboard and Answer data. + +[div divider] +-- ++++

Search data

+++ + +`POST /api/rest/2.0/searchdata` + +Allows searching data from a data source by passing query strings in the API request. + +__Requires at least view access to the data source object__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Fetch Liveboard data

+++ + +`POST /api/rest/2.0/metadata/liveboard/data` + +Gets Liveboard and visualization data from ThoughtSpot. + +__Requires at least view access to the Liveboard object__. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Fetch Answer data

+++ + +`POST /api/rest/2.0/metadata/answer/data` + +Gets Answer data from ThoughtSpot. You can fetch data for saved Answers only. + +__Requires at least view access to the Answer object__. + ++++View in Playground+++ +-- + +== Logs + +[div divider] +-- ++++

Fetch audit logs

+++ + +`POST /api/rest/2.0/logs/fetch` + +Gets security audit logs from the ThoughtSpot system. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +== Version control [beta betaBackground]^Beta^ + +[div divider] +-- ++++

Search config

+++ + +Gets Git repository connections configured on the ThoughtSpot instance. + +`POST /api/rest/2.0/vcs/git/config/search` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ + +-- + +[div divider] +-- ++++

Search Commits

+++ + +Gets Git commit history for a given metadata object. + +`POST /api/rest/2.0/vcs/git/commits/search` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ + +-- + +[div divider] +-- ++++

Create Local Config

+++ + +Allows you to connect a ThoughtSpot instance to a Git repository. Use this API endpoint to connect your ThoughtSpot development and production environments to the development and production branches of a Git repository. + +`POST /api/rest/2.0/vcs/git/config/create` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ + +-- + +[div divider] +-- ++++

Update Config

+++ + +Updates the Git repository settings configured on a ThoughtSpot instance. + +`POST /api/rest/2.0/vcs/git/config/update` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ + +-- + +[div divider] +-- ++++

Delete Config

+++ + +Removes the connection to the Git repository. + +`POST /api/rest/2.0/vcs/git/config/delete` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Delete Config

+++ + +Deletes the Git configuration details from the ThoughtSpot instance. + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ + +-- + +[div divider] +-- ++++

Commit branch

+++ + +Commits the TML files of the metadata objects to the Git branch configured on your instance. + +`POST /api/rest/2.0/vcs/git/branches/commit` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Revert commit

+++ + +Reverts TML objects to a previous commit in the Git branch. + +`POST /api/rest/2.0/vcs/git/branches/commit` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Validate merge

+++ + +Validates the content of your source branch against the objects in your destination environment. + +`POST /api/rest/2.0/vcs/git/branches/commit` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Deploy commit

+++ + +Allows you to deploy a commit and publish TML content to the ThoughtSpot instance. + +`POST /api/rest/2.0/vcs/git/branches/commit` + +__Requires `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + + +== Connections + +The `Connections` API endpoints allow you to perform CRUD operations on data connection objects. ThoughtSpot users with `ADMINISTRATION` or `DATAMANAGEMENT` privilege can create a connection to any of the following types of data warehouses and let users search from these external data sources to generate the information they need: + +* Amazon Redshift +* Azure Synapse +* Databricks +* Dremio +* Denodo +* Google BigQuery +* Oracle ADW +* Presto +* SAP HANA +* Snowflake +* Starburst +* Teradata +* Trino + +[div divider] +-- ++++

Search connection

+++ + +`POST /api/rest/2.0/connection/search` + +Gets connection objects from ThoughtSpot. + +__Requires `DATAMANAGEMENT` (**Can manage data**) or `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + +You can send an API request to fetch details of a specific connection by specifying the connection name or GUID. You can also customize your search to filter the API response by the data warehouse type. + +* To fetch details of a connection object, specify the connection object GUID or name. The `name_pattern` attribute allows passing partial text with `%` for a wildcard match. +* To get details of the database, schemas, tables, or columns from a data connection object, specify the `data_warehouse_object_type` attribute. +* To get a specific database, schema, table, or column from a connection object, define the object type in `data_warehouse_object_type` and object properties in the `data_warehouse_objects` array. For example, to search for a column, you must pass the database, schema, and table names in the API request. ++ +``` +{ + "connections": [ + { + "identifier": "b9d1f2ef-fa65-4a4b-994e-30fa2d57b0c2", + "data_warehouse_objects": [ + { + "database": "NEBULADEV", + "schema": "INFORMATION_SCHEMA", + "table": "APPLICABLE_ROLES", + "column": "ROLE_NAME" + } + ] + } + ], + "data_warehouse_object_type": "COLUMN" +} +``` + +* To include more details about connection objects in the API response, set `include_details` to `true`. +* You can also sort the output by field names and filter connections by tags. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Create connection

+++ + +`POST /api/rest/2.0/connection/create` + +Creates a connection to the specified data warehouse. + + +__Requires `DATAMANAGEMENT` (**Can manage data**) or `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + +The endpoint requires you to define connection metadata in JSON format. The connection can be created without tables. + +[#sampleJSON] ++++
JSON sample for the data_warehouse_config attribute
+++ + +The `data_warehouse_config` attribute requires you to provide connection metadata input in JSON format. The attributes may vary based on the type of data warehouse for which the connection is being created. For example, to create a connection to a Snowflake data warehouse, the following properties and metadata are required. + +.JSON sample without tables +[%collapsible] +==== +The following example creates an empty connection without tables. When creating a connection without tables, set the `validate` property to `false`. + +[source, JSON] +---- +{ + "configuration":{ + "accountName":"thoughtspot_partner", + "user":"tsadmin", + "password":"TestConn123", + "role":"sysadmin", + "warehouse":"MEDIUM_WH" + }, + "externalDatabases":[ + + ] +} +---- +==== + +.JSON sample with tables +[%collapsible] +==== +The following example creates a Snowflake connection with tables. When creating a connection with tables, you can set the `validate` property to `true`. + +[source, JSON] +---- +{ + "configuration":{ + "accountName":"thoughtspot_partner", + "user":"tsadmin", + "password":"TestConn123", + "role":"sysadmin", + "warehouse":"MEDIUM_WH" + }, + "externalDatabases":[ + { + "name":"AllDatatypes", + "isAutoCreated":false, + "schemas":[ + { + "name":"alldatatypes", + "tables":[ + { + "name":"allDatatypes", + "type":"TABLE", + "description":"", + "selected":true, + "linked":true, + "columns":[ + { + "name":"CNUMBER", + "type":"INT64", + "canImport":true, + "selected":true, + "isLinkedActive":true, + "isImported":false, + "tableName":"allDatatypes", + "schemaName":"alldatatypes", + "dbName":"AllDatatypes" + }, + { + "name":"CDECIMAL", + "type":"INT64", + "canImport":true, + "selected":true, + "isLinkedActive":true, + "isImported":false, + "tableName":"allDatatypes", + "schemaName":"alldatatypes", + "dbName":"AllDatatypes" + } + ] + } + ] + } + ] + } + ] +} +---- +==== + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Update connection

+++ + +`POST /api/rest/2.0/connection/update` + +Updates a data connection. If you are adding tables to a connection, make sure you set the `validate` property to true. + +For information about the JSON input for `data_warehouse_config` attribute, refer to the examples in the xref:rest-api-v2-reference.adoc#sampleJSON[create connection] section. + +__Requires `DATAMANAGEMENT` (**Can manage data**) or `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Delete connection

+++ + +`POST /api/rest/2.0/connection/delete` + +Deletes a data connection. + +Before deleting a connection, check if the connection has dependent objects and remove its association to the other metadata objects in ThoughtSpot. + +__Requires `DATAMANAGEMENT` (**Can manage data**) or `ADMINISTRATION` (**Can administer ThoughtSpot**) privilege__. + ++++View in Playground+++ +-- + +== Schedules + +[div divider] +-- ++++

Create Schedule

+++ + +`POST /api/rest/2.0/schedules/create` + +Creates a link:https://docs.thoughtspot.com/cloud/latest/liveboard-schedule[Liveboard schedule job, window=_blank]. + +* The description text is mandatory. The description text appears as **Description: ** in the Liveboard schedule email notifications. +* The API endpoint supports exporting Liveboard data to the recipients in CSV or PDF format. If your Liveboard has tables, you can set `file_format` to CSV to send CSV files in the email notification to the recipients. For PDF generation, you can define PDF layout options. +* To include specific visualizations, specify the visualization GUIDs in the `visualization_identifiers` array. +* You can schedule a Liveboard job to run periodically by setting frequency parameters. You can set the schedule to run daily, weekly, monthly or every n minutes or hours. The scheduled job can also be configured to run at a specific time of the day or on specific days of the week or month. +* If the `frequency` parameters are defined, you can set the time zone to a value that matches your server's time zone. For example, `US/Central`, `Etc/UTC`, `CET`. The default time zone is `America/Los_Angeles`. + +__Requires at least edit access to Liveboards. To create a schedule on behalf of another user, you need `ADMINISTRATION` (**Can administer Org**) or `JOBSCHEDULING` (**Can schedule for others**) privilege and edit access to the Liveboard__. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Delete Schedule

+++ + +Deletes a scheduled job. + +__Requires at least edit access to Liveboards or `ADMINISTRATION` (**Can administer Org**) privilege__. + ++++View in Playground+++ +-- + +[div divider] +-- ++++

Search Schedules

+++ + +Gets a list of scheduled jobs configured for a Liveboard. To get the details of a specific scheduled job, specify the GUID of the scheduled job. + +__Requires at least view access to Liveboards__. + ++++View in Playground+++ +-- + + +[div divider] +-- ++++

Update Schedule

+++ + +Updates a scheduled job. + +The API endpoint allows you to pause a scheduled job, change the status of a paused job, and edit the properties of a schedule, such as the recipient list, frequency of the job, format of the file to send to the recipients in email notifications, PDF options, and time zone settings. + +__Requires at least edit access to Liveboards. To update a schedule on behalf of another user, you need `ADMINISTRATION` (**Can administer Org**) or `JOBSCHEDULING` (**Can schedule for others**) privilege and edit access to the Liveboard__. + ++++View in Playground+++ +-- diff --git a/docs/src/asciidocs/rest-api-v2.adoc b/docs/src/asciidocs/rest-api-v2.adoc new file mode 100644 index 000000000..addadb250 --- /dev/null +++ b/docs/src/asciidocs/rest-api-v2.adoc @@ -0,0 +1,85 @@ += REST API v2.0 +:toc: true + +:page-title: REST API v2.0 +:page-pageid: rest-api-v2 +:page-description: ThoughtSpot REST API v2.0 provides service endpoints for user management, group administration, and metadata object queries. + +The REST API v2.0 framework is built upon the existing core API functionality and data models but offers several new features and enhancements. + +Enhanced usability and developer experience:: + +With REST API v2.0, ThoughtSpot offers a user-friendly, interactive Playground to explore the endpoints, try out API requests, and view responses. The Playground provides detailed information about how to get started, authenticate to ThoughtSpot, and interact with the endpoints. ++ +For more information, see xref:rest-api-v2-playground.adoc[REST Playground v2]. +//// +The Playground provides dynamic code samples as you switch between different languages. You can also generate code samples, and download the SDK and client libraries in different programming languages. +//// + +//// +Language-specific SDK and client libraries:: + +ThoughtSpot provides Java, Python, and TypeScript SDK and client libraries. If you want to call REST APIs in a language-specific way, you can download the SDK and libraries and integrate them with your environment. ++ +For more information, see xref:rest-api-sdk-libraries.adoc[REST API SDK and client libraries]. +//// + +Token-based authentication and authorization:: + +To provide secure access to ThoughtSpot resources, REST API v2.0 supports the Bearer token and Trusted authentication methods. You must obtain an access token before making an API call and pass the token in the `Authorization` header in the subsequent API calls. + ++ +For more information, see xref:authentication.adoc[REST API v2 authentication]. + +Consistent request and response workflow:: + +With REST API v2.0, the JSON data structure for request and response payloads is standardized. + ++ +The REST API v2.0 supports the standard Create, Read, Update, and Delete (CRUD) operations, and the following HTTP verbs in API requests. + +* **GET** to query information, such as getting system or session information +* **POST** to create new objects, add, modify, or delete object properties ++ + +Simplified resource collections and endpoint categories:: ++ +The resource endpoints are grouped logically based on the objects they operate on. The endpoint URLs are easy to understand and predictable. For example, you can find all metadata resource endpoints, including TML operations, in the `/metadata/` resource collection. + +== Feature availability + +Starting with 9.0.0.cl release, the REST API v2.0 Playground and API endpoints are generally available (GA) on all ThoughtSpot instances. + +If you are not a ThoughtSpot user yet, you can preview the REST API v2.0 endpoints link:https://try-everywhere.thoughtspot.cloud/v2/#/everywhere/[ThoughtSpot API Playground, window=_blank] or sign up for a free trial to evaluate the API and Playground experience. + +== Interoperability with REST API v1 and REST API v2[beta betaBackground]^Beta^ version + +Authentication tokens generated via `POST` requests to REST API v1 endpoints can be used for authorizing REST API v2.0 requests. + +The REST API v2.0 introduces several breaking changes that may affect interoperability between REST API v1 and REST API v2.0, or REST API v2[beta betaBackground]^Beta^ and REST API v2.0 versions. + +We recommend using REST API v2.0 API endpoints for development and testing purposes in the initial release. ThoughtSpot will provide migration instructions when REST API v2.0 framework is fully ready to replace the REST API v1 endpoints in a production setup. + +== Feature limitations + +* The REST API v2.0 `session/login` endpoint does not return session cookies. However, you can use obtain a bearer token from ThoughtSpot via `/api/rest/2.0/auth/token/full` and use it to authorize your subsequent API requests. +* The following REST API v2.0 endpoints require administrator or data download privilege, and at least view access to the metadata object specified in the API request. + +** `POST /api/rest/2.0/searchdata` +** `POST /api/rest/2.0/metadata/liveboard/data` +** `POST /api/rest/2.0/metadata/answer/data` +** `POST /api/rest/2.0/report/liveboard` +** `POST /api/rest/2.0/report/answer` + +* Object sharing via `/api/rest/2.0/security/metadata/share` requires administrator privileges. +If you have edit permissions or view access to the metadata object, but don't have administrator privileges, use the REST API v1 endpoint (`/tspublic/v1/security/share`) or the *Share* action in the UI to share an object. + +== Related information + +* xref:rest-api-v2-playground.adoc[REST Playground v2] +* xref:rest-api-v2-getstarted.adoc[Get started with REST API v2] +* xref:rest-api-v2-reference.adoc[REST API v2 Reference] + +//// +* xref:rest-api-sdk-libraries.adoc[REST API SDK and client libraries] +//// diff --git a/docs/src/asciidocs/rest-apiv1-changelog.adoc b/docs/src/asciidocs/rest-apiv1-changelog.adoc new file mode 100644 index 000000000..506051766 --- /dev/null +++ b/docs/src/asciidocs/rest-apiv1-changelog.adoc @@ -0,0 +1,301 @@ += REST API v1 changelog +:toc: true +:toclevels: 1 + +:page-title: Changelog +:page-pageid: rest-v1-changelog +:page-description: Changelog of REST APIs + +This changelog lists only the changes introduced in REST API v1. For a complete list of ThoughtSpot Everywhere features and enhancements, see xref:whats-new.adoc[What's New]. + +== Versions 9.3.0.cl and 9.4.0.cl + +No new changes were introduced in the 9.3.0.cl and 9.4.0.cl releases. + +== Version 9.2.0.cl, May 2023 + +The 9.2.0.cl release introduces the following enhancements: + +* The xref:pinboarddata.adoc[`/tspublic/v1/pinboarddata`] and xref:search-data-api.adoc[`/tspublic/v1/searchdata`] API endpoints support applying parameter overrides at runtime. You can pass Worksheet parameters in the request URL when making an API call to these endpoints and adjust parameter values to optimize your queries. + +* The `/tspublic/v1/session/login` API endpoint now allows users to log in to a specific Org with basic authentication. + +== Version 9.0.0.cl, February 2023 + +The 9.0.0.cl release introduces the `/tspublic/v1/metadata/delete` endpoint, using which you can delete a metadata object. + +For more information, see xref:metadata-api.adoc#del-obj[Delete metadata objects]. + +== Version 8.10.0.cl, January 2023 + +The 8.10.0.cl release version introduces the following features and enhancements: + +TML import API:: + +The xref:tml-api.adoc#import[`/tspublic/v1/metadata/tml/import`] endpoint now supports re-using GUIDs for new objects created during the import if the `guid` in the imported TML is not being used by any other object on the server. + +APIs for Orgs:: + +This release introduces new REST API v1 endpoints and object properties to support Org operations on a multi-tenant cluster. + +Org API endpoints;; +For multi-tenant clusters with Orgs, ThoughtSpot provides new endpoints to allow CRUD operations for Org objects. ++ +For more information, see xref:org-api.adoc[Org API] and xref:org-manage-api.adoc[Org administration and management via REST API]. + +Session API endpoints;; +If the Orgs feature is enabled and Orgs are created on your cluster, the cluster administrators can use the `/tspublic/v1/session/orgs` to xref:session-api#orgSwitch[Switch between Orgs]. ++ +For deployments with the trusted authentication framework, you can use the `/tspublic/v1/session/auth/token` API endpoint lets you xref:session-api.adoc#session-authToken[create a user just-in-time and dynamically assign Orgs, groups, and privileges to that user]. + +Mapping Orgs to users and groups;; +On multi-tenant clusters with Orgs, the `user` and `group` API endpoints allow assigning users and groups to an Org object. +For more information, refer to the following articles: +* xref:user-api.adoc#create-user[create a user] +* xref:user-api.adoc#update-user[update user details] +* xref:user-api.adoc##delete-user[delete a user account] +* xref:group-api.adoc#create-group[create a group] + +== Version 8.9.0.cl, November 2022 + +Session API:: +Starting from 8.9.0.cl, the xref:session-api.adoc#session-authToken[/tspublic/v1/session/auth/token] endpoint includes the `autocreate` and `groups` properties to allow administrators to create a user just-in-time and assign groups and privileges to the user when requesting an authentication token from ThoughtSpot. + +TML API:: +In 8.9.0.cl, ThoughtSpot will rebrand the object name `pinboard` to `liveboard` in the TML. The TML objects retrieved from ThoughtSpot via xref:tml-api.adoc#export[`/tspublic/v1/metadata/tml/export`] API endpoint will show the object name as `liveboard` in the API response. + +User API:: + +The xref:user-api.adoc#create-user[POST /tspublic/v1/user/] and xref:user-api.adoc#update-user[PUT /tspublic/v1/user/{userid}] API endpoints allow you set the `triggeredbyadmin` flag to indicate if the user creation or update request is initiated by the ThoughtSpot admin or an external application. + +== Version 8.8.0.cl, October 2022 + +The 8.8.0.cl release version introduces the following enhancements to connection API endpoints: + +* The `/tspublic/v1/connection/fetchLiveColumns` and `/tspublic/v1/connection/fetchConnection` API endpoints now allow filtering API response by authentication type. ++ +For more information, see xref:connections-api.adoc#fetchLiveColums[Get column data for connections with external tables] and xref:connections-api.adoc#connMetadata[Get details of a specific connection]. + +* The `/tspublic/v1/connection/create` and `/tspublic/v1/connection/update` API endpoints now support adding and updating Trino and Presto data connections. ++ +For more information, see xref:connections-api.adoc#cre-connection[Create a data connection] and xref:connections-api.adoc#connection-metadata[Connection metadata]. + +== Version 8.7.0.cl, September 2022 + +The `/tspublic/v1/metadata/tml/export` API endpoint supports exporting FQNs of TML objects. To export FQNs, you must the `export_fqn` property to true in your API request. + +For more information, see xref:tml-api.adoc#export[Export TML]. + +== Version 8.6.0.cl, August 2022 + +The `/tspublic/v1/connection/create` and `/tspublic/v1/connection/update` API endpoints support creating and modifying Denodo data connections respectively. For more information, see xref:connections-api.adoc[Data connection APIs]. + +== Version, 8.4.0.cl, June 2022 + +The `/tspublic/v1/pinboarddata` endpoint now allows retrieving transient content from a Liveboard. The `transient_pinboard_content` parameter allows you to add a script to fetch the unsaved changes if any for a given Liveboard. + +For more information, see xref:pinboarddata.adoc[Liveboard data API]. + +== Version 8.2.0.cl, April 2022 + +New REST API v1 endpoints for data connection queries: + + +* `xref:connections-api.adoc#connMetadata[*POST* /tspublic/v1/connection/fetchConnection]` + +* `xref:connections-api.adoc#fetchLiveColums[*POST* /tspublic/v1/connection/fetchLiveColumns]` + + +== Version 8.1.0.cl, March 2022 + +Bug fixes and improvements + +== Version 8.0.0.cl, February 2022 + +REST clients using Postman for API calls can now send a `POST` request to the `/tspublic/v1/session/auth/token` endpoint. + +In the earlier releases, unauthenticated clients were not allowed to make an API call to `/tspublic/v1/session/auth/token` via Postman. + +== Version ts8.nov.cl, January 2022 + +.New API endpoint for token-based login +[%collapsible] +==== +`POST /tspublic/v1/session/login/token` + + +This API endpoint allows you to make a `POST` request with parameters in the request body. For more information, see xref:session-api.adoc#session-loginToken[Authenticate and log in a user]. +==== + +.Modified endpoints +[%collapsible] +==== +* The `/tspublic/v1/connection/create` and `/tspublic/v1/connection/update` endpoints now allow configuring and modifying a connection without importing tables. ++ +For more information, see xref:connections-api.adoc[Data connection APIs]. +* The `authorguid` attribute in `/tspublic/v1/metadata/list` now allows you to filter metadata objects by author GUIDs in API response. ++ +For more information, see xref:metadata-api.adoc#metadata-list[Get a list of metadata objects]. +==== + +== Version ts7.oct.cl, November 2021 + +.New API endpoints +[%collapsible] +==== +* `POST /tspublic/v1/group/{groupid}/users` +* `GET /tspublic/v1/group/{groupid}/users` +* `PUT /tspublic/v1/user/email` +* `POST /tspublic/v1/user/{userid}/groups` +* `GET /tspublic/v1/user/{userid}/groups` +* `PUT /tspublic/v1/user/{userid}/groups` +* `DELETE /tspublic/v1/user/{userid}/groups` +* `DELETE /tspublic/v1/group/{groupid}/users` + +For more information about these APIs, see xref:rest-api-reference.adoc[REST API Reference]. +==== + +== Version ts7.sep.cl, October 2021 + +.New API endpoints +[%collapsible] +==== +* `POST /tspublic/v1/connection/create` +* `POST /tspublic/v1/connection/update` +* `POST /tspublic/v1/connection/export` +* `POST /tspublic/v1/connection/delete` +* `POST /tspublic/v1/metadata/unassigntag` +* `GET /tspublic/v1/metadata/list` +* `GET /tspublic/v1/security/metadata/permissions` +* `GET /tspublic/v1/security/metadata/{id}/permissions` +* `GET /tspublic/v1/security/effectivepermissionbulk` +* `GET /tspublic/v1/session/info` +* `POST /tspublic/v1/user/activate` +* `POST /tspublic/v1/user/inactivate` +* `POST /tspublic/v1/user/session/invalidate` +* `POST /tspublic/v1/user/resetpassword` +* `PUT /tspublic/v1/group/{groupid}/users` +* `POST /tspublic/v1/group/{groupid}/groups` +* `PUT /tspublic/v1/group/{groupid}/groups` +* `GET /tspublic/v1/group/{groupid}/groups` +* `POST /tspublic/v1/group/addmemberships` +* `POST /tspublic/v1/group/removememberships` +* `DELETE /tspublic/v1/group/{groupid}/groups` + +For more information, see xref:rest-api-reference.adoc[REST API Reference]. +==== + +.Modified API endpoints +[%collapsible] +==== +`POST /tspublic/v1/metadata/assigntag` +==== + +== Version ts7.aug.cl, September 2021 +The ThoughtSpot 7 Cloud August release introduces several new API endpoints: + +.Admin API endpoints +[%collapsible] +==== +* `POST /tspublic/v1/admin/configinfo/update` +* `GET /tspublic/v1/admin/configinfo/overrides` +* `GET /tspublic/v1/admin/configinfo` +* `GET /tspublic/v1/admin/embed/actions` +* `GET /tspublic/v1/admin/embed/actions/{actionid}` +* `POST /tspublic/v1/admin/embed/actions` +* `DELETE /tspublic/v1/admin/embed/actions/{actionid}` +* `PUT /tspublic/v1/admin/embed/actions/{actionid}` +* `POST /tspublic/v1/admin/embed/action/{actionid}/associations` +* `GET /tspublic/v1/admin/embed/action/{actionid}/associations` +* `DELETE /tspublic/v1/admin/embed/action/{actionid}/associations` + +For more information, see xref:admin-api.adoc[Admin APIs]. +==== + +.Group API endpoints +[%collapsible] +==== +* `POST /tspublic/v1/group/` +* `GET /tspublic/v1/group/` +* `PUT /tspublic/v1/group/{groupid}` +* `POST /tspublic/v1/group/{groupid}/user/{userid}` +* `DELETE /tspublic/v1/group/{groupid}/user/{userid}` +* `DELETE /tspublic/v1/group/{groupid}` + +For more information, see xref:group-api.adoc[Group APIs]. +==== + +.User API endpoints +[%collapsible] +==== +* `GET /tspublic/v1/user/` +* `POST /tspublic/v1/user/` +* `DELETE /tspublic/v1/user/{userid}` +* `PUT /tspublic/v1/user/{userid}` + +For more information, see xref:user-api.adoc[user APIs]. +==== + +.Dependency API endpoints +[%collapsible] +==== +* `POST /tspublic/v1/dependency/listdependents +* `GET /tspublic/v1/dependency/listincomplete` +* `POST /tspublic/v1/dependency/listdependents` +* `GET /tspublic/v1/dependency/physicaltable` +* `GET /tspublic/v1/dependency/pinboard` +* `GET /tspublic/v1/dependency/logicalcolumn` +* `GET /tspublic/v1/dependency/logicaltable` +* `GET /tspublic/v1/dependency/logicalrelationship` +* `GET /tspublic/v1/dependency/physicalcolumn` + +For more information, see xref:dependency-apis.adoc[Dependent objects APIs]. +==== + +.Connection API endpoints +[%collapsible] +==== +* `GET /tspublic/v1/connection/types` +* `GET /tspublic/v1/connection/list` + +For more information, see xref:connections-api.adoc[Connection APIs]. +==== + +.Log API endpoint +[%collapsible] +==== +`GET /tspublic/v1/logs/topics/{topic}` +For more information, see xref:logs-apis.adoc[Log streaming service API]. +==== + +== Version ts7.jun.cl, July 2021 + +.New API endpoints +[%collapsible] +==== +* `POST /tspublic/v1/security/share` +* `POST /tspublic/v1/security/shareviz` +* `GET /tspublic/v1/session/login/token` +* `POST /tspublic/v1/metadata/assigntag` +* `GET /tspublic/v1/metadata/details` +* `POST /tspublic/v1/metadata/markunmarkfavoritefor` +* `DELETE /tspublic/v1/metadata/markunmarkfavoritefor` +* `POST /tspublic/v1/session/homepinboard` +* `GET /tspublic/v1/session/homepinboard` +* `DELETE /tspublic/v1/session/homepinboard` + +For more information, see xref:rest-api-reference.adoc[REST API Reference]. +==== + +.Other enhancements +[%collapsible] +==== +The `POST /tspublic/v1/user/updatepreference` API now includes the optional `username` parameter. You can use either `userid` or `username` in your API request. + +For more information, see xref:user-api.adoc#updatepreference-api[Update a user profile]. +==== + + +== Version ts7.may.cl, June 2021 + +.New endpoints +[%collapsible] +==== +* `*POST* /tspublic/v1/user/updatepreference` +* `*GET* /tspublic/v1/metadata/listas` +==== diff --git a/docs/src/asciidocs/rest-apiv2-changelog.adoc b/docs/src/asciidocs/rest-apiv2-changelog.adoc new file mode 100644 index 000000000..d4ecf59b0 --- /dev/null +++ b/docs/src/asciidocs/rest-apiv2-changelog.adoc @@ -0,0 +1,111 @@ += REST API v2.0 changelog +:toc: true +:toclevels: 1 + +:page-title: Changelog +:page-pageid: rest-v2-changelog +:page-description: Changelog of REST APIs + +This changelog lists the features and enhancements introduced in REST API v2.0. For a complete list of ThoughtSpot Everywhere features and enhancements, see xref:whats-new.adoc[What's New]. + +== Version 9.4.0.cl, August 2023 + +=== API endpoints to schedule and manage Liveboard jobs + +* `*POST* /api/rest/2.0/schedules/create` + +Creates a scheduled job for a Liveboard +* `*POST* /api/rest/2.0/schedules/{schedule_identifier}/update` + +Updates a scheduled job +* `*POST* /api/rest/2.0/schedules/search` + +Gets a list of Liveboard jobs configured on a ThoughtSpot instance +* `*POST* /api/rest/2.0/schedules/{schedule_identifier}/delete` + +Deletes a scheduled job. + +For more information, see the xref:rest-api-v2-reference.adoc#_schedules[Schedules]. + +=== API to fetch authentication token + +The `GET /api/rest/2.0/auth/session/token` API endpoint fetches the current authentication token used by the currently logged-in user. + +=== Version Control API enhancements + +* The following Version Control API endpoints support generating and maintaining a GUID mapping file on a Git branch connected to a ThoughtSpot instance: + +** `*POST* /api/rest/2.0/vcs/git/config/create` +** `*POST* /api/rest/2.0/vcs/git/config/update` + +=== User and group API enhancements + +* The `**POST** /api/rest/2.0/users/{user_identifier}/update` and `**POST** /api/rest/2.0/groups/{group_identifier}/update` support specifying the type of operation API request. For example, if you are removing a property of a user or group object, you can specify the `operation` type as `REMOVE` in the API request. +* The `**POST** /api/rest/2.0/users/{user_identifier}/update` allows you to define locale settings, preferences, and other properties for a user object. + +== Version 9.3.0.cl, June 2023 + +The following Version Control [beta betaBackground]^Beta^ API endpoints are now available for the lifecycle management of content on your deployment environments: + +* `*POST* /api/rest/2.0/vcs/git/config/search` +* `*POST* /api/rest/2.0/vcs/git/commits/search` +* `*POST* /api/rest/2.0/vcs/git/config/create` +* `*POST* /api/rest/2.0/vcs/git/config/update` +* `*POST* /api/rest/2.0/vcs/git/config/delete` +* `*POST* /api/rest/2.0/vcs/git/branches/{branch_name}/pull` +* `*POST* /api/rest/2.0/vcs/git/branches/commit` +* `*POST* /api/rest/2.0/vcs/git/commits/{commit_id}/revert` +* `*POST* /api/rest/2.0/vcs/git/branches/validate` +* `*POST* /api/rest/2.0/vcs/git/commits/deploy` + +For more information, see xref:version_control.adoc[Version control and Git integration]. + +== Version 9.2.0.cl, May 2023 + +New endpoints:: + +* System ++ +** `POST /api/rest/2.0/system/config-update` + +Updates system configuration ++ +** `GET /api/rest/2.0/system/config-overrides` + +Gets system configuration overrides + +* Connections ++ +** POST /api/rest/2.0/connection/create + +Creates a data connection + +** `POST /api/rest/2.0/connection/search` + +Gets a list of data connections + +** `POST /api/rest/2.0/connection/update` + +Updates a data connection + +** `POST /api/rest/2.0/connection/delete` + +Deletes a data connection + +Enhancements:: + +* Support for runtime filters and runtime sorting of columns + +The following REST API v2.0 endpoints support applying xref:runtime-filters.adoc#_apply_runtime_filters_in_rest_api_v2_requests[runtime filters] and xref:runtime-sort.adoc[sorting column data]: ++ +** `POST /api/rest/2.0/report/liveboard` + +** `POST /api/rest/2.0/report/answer` + +* Search users by their favorites ++ +The `/api/rest/2.0/users/search` API endpoint allows searching users by their favorite objects and home Liveboard setting. + +* Ability to log in to a specific Org ++ +The `/api/rest/2.0/auth/session/login` API endpoint now allows ThoughtSpot users to log in to a specific Org context. + +== Version 9.0.0.cl, February 2023 + +The ThoughtSpot Cloud 9.0.0.cl release introduces the REST API v2.0 endpoints and Playground. For information about REST API v2.0 endpoints and Playground, see the following articles: + +* xref:rest-api-v2.adoc[REST API v2.0] +* xref:rest-api-v2-getstarted.adoc[Get started with REST API v2.0] +* xref:rest-api-v2-reference.adoc[REST API v2.0 reference] +* xref:rest-api-v1v2-comparison.adoc[REST API v1 and v2.0 comparison] + + + diff --git a/docs/src/asciidocs/rest-apiv2-js.adoc b/docs/src/asciidocs/rest-apiv2-js.adoc new file mode 100644 index 000000000..2a8cb86fe --- /dev/null +++ b/docs/src/asciidocs/rest-apiv2-js.adoc @@ -0,0 +1,106 @@ += REST API v2.0 in JavaScript +:toc: true +:toclevels: 2 + +:page-title: Use REST API v2.0 in JavaScript +:page-pageid: rest-apiv2-js +:page-description: Examples in JavaScript of REST API v2.0 calls + +REST API v2.0 uses JSON for the request and the response format, so it is easy to implement any v2.0 call in JavaScript. + +Every REST API v2.0 endpoint uses either an HTTP GET or POST request, with or without a JSON request, so this simple async wrapper function can be used generically to build out any specific endpoint request. + +[source,javascript] +---- +/* +* Generic function to make a call to the V2.0 REST API +* +*/ +let tsHost = 'https://{yourdomain}.thoughtspot.cloud'; +async function restApiCallV2(endpoint, httpVerb, apiRequestObject){ + const publicApiUrl = 'api/rest/2.0/'; + console.log("hitting endpoint " + endpoint + " with verb " + httpVerb + " and request:"); + console.log(apiRequestObject); + const apiFullEndpoint = tsHost + "/" + publicApiUrl + endpoint; + return await fetch( + apiFullEndpoint, + { + method: httpVerb.toUpperCase(), + headers: { + "Accept": "application/json", + "X-Requested-By": "ThoughtSpot", + "Content-Type": "application/json" + }, + credentials: "include", + body: JSON.stringify(apiRequestObject) + }) + // is there always response JSON? + .then(response => response.json()) + .catch(error => { + console.error("Unable to get the" + endpoint + "response: " + error); + }); +} +---- + +You can use the `restApiCallV2` function directly in a code block, or wrap it in another function. + +Here's a direct example: + +[source,javascript] +---- +let tmlExportEndpoint = 'metadata/tml/export'; +let apiRequestForTML = { + "metadata" : [{ + "type": "LIVEBOARD", + "identifier": liveboardId + }], + "export_associated": false, + "export_fqn": true + +} + +// Place call to export the TML for the Liveboard, to get the details of the Viz +return restApiCallV2(tmlExportEndpoint, 'POST', apiRequestForTML).then( +//tmlExportRestApiCallV2(tmlRequestOptions).then( + response => { + // console.log(response); + let tmlObject = JSON.parse(response[0].edoc); + // console.log(tmlObject); + return tmlObject; + } +).then(...) + +---- + +Here's a function to call a specific endpoint: + +[source,javascript] +---- +async function callSearchDataApi(tmlSearchString, datasourceId){ + console.log("Using following Search String for Search Data API: ", tmlSearchString); + let searchDataEndpoint = 'searchdata'; + let apiRequestForSearchData = { + "query_string": tmlSearchString + , "logical_table_identifier": datasourceId + , data_format: "COMPACT" + , record_offset: 0 + , record_size: 1000 + } + + return await restApiCallV2(searchDataEndpoint, 'POST', apiRequestForSearchData).then( + response => { + console.log("Search Data response:"); + console.log(response); + //let tmlObject = JSON.parse(response[0].edoc); + //console.log(tmlObject); + return response; + } + ); +} + +let vizTmlSearchString = '[Product] [Region]'; +let dsId = '80c9b38f-1b2a-4ff4-a759-378259130f58'; +callSearchDataApi(vizTmlSearchString, dsId).then( + // process the response +) +---- diff --git a/docs/src/asciidocs/rest-playground.adoc b/docs/src/asciidocs/rest-playground.adoc new file mode 100644 index 000000000..f5f1471d8 --- /dev/null +++ b/docs/src/asciidocs/rest-playground.adoc @@ -0,0 +1,39 @@ += REST API Playground +:toc: true +:toclevels: 2 + +:page-title: REST API Playground +:page-pageid: rest-playground +:page-description: Use the REST Playground to explore the REST API endpoints, request and response workflows + +The REST API Playground provides an interactive portal to explore REST API v1 and v2.0 endpoints. + +* To view the Playground with REST API v1 endpoints, click **REST Playground v1**. + +* To explore REST API v2 endpoints, click **REST Playground v2.0**. + +== REST API v1 Playground + +The *REST Playground v1* opens the v1 API explorer and displays the available resource collections in the Swagger UI. + +To make an API call and view results: + +. Click the API service category and view a list of endpoints. +. Click on the endpoint to which you want to send an API request. +. If required, define the attributes. +. Click **Try it out** and verify the API response and HTTP status code. + +++++ +Try it out +++++ + +For more information about REST API v1 endpoints, API request and response workflow, see xref:rest-api-getstarted.adoc[Get started with REST API v1]. + +== REST API v2.0 Playground + +The REST API v2.0 Playground displays a list of v2 API endpoints, and a code panel to try out API calls. + +++++ +Try it out +++++ + +For more information, see xref:rest-api-v2-playground.adoc[REST API v2.0 Playground]. diff --git a/docs/src/asciidocs/runtime-filters.adoc b/docs/src/asciidocs/runtime-filters.adoc new file mode 100644 index 000000000..ba440ed04 --- /dev/null +++ b/docs/src/asciidocs/runtime-filters.adoc @@ -0,0 +1,624 @@ += Runtime filters +:toc: true +:toclevels: 1 + +:page-title: Runtime filters +:page-pageid: runtime-filters +:page-description: Apply filters to visualizations at runtime and pass them as URL parameters + +Runtime filters provide the ability to apply filters to a Liveboard or Answer by passing filter properties as query parameters in a Liveboard or visualization URL. You can also apply runtime filters in REST API requests when querying data from a Liveboard, Answer, or a visualization object. On embedded instances, you can use the Visual Embed SDK to apply filters to an embedded Liveboard or Answer object, and also update filters using events. + + +[NOTE] +==== +The runtime filters operation returns an error if the URL exceeds 2000 characters. +==== + +== How runtime filters work + +The runtime filters can be specified in the ThoughtSpot object URL as query parameters. When you apply a runtime filter to a Liveboard, ThoughtSpot will try to find a matching column in the Liveboard visualizations to filter data. The runtime filter requires the following attribute-value pairs. + +column name:: +__String__. Name of the column to filter by. For example, `item type` or `product`. This attribute is defined as `col1`, `col2`, `col3` in the URLs and as `columnName` in the `runtimeFilters` array in the Visual Embed SDK. + +operator:: +__String__. The xref:runtime-filters.adoc#rtOperator[runtime filter operator]. For example, `EQ` or `IN`. This attribute is defined as `op1`, `op2`, `op3` in the object URLs and as xref:runtime-filters.adoc#runtimeFilterOp[`operator` in the `runtimeFilters` array] in the Visual Embed SDK. + ++ +[#rtOperator] +.Supported runtime filter operators +[%collapsible] +==== +[width="80%" cols="1,2,2"] +[options='header'] +|=== +|Operator|Description|Number of Values + +| `EQ` +| equals +| 1 + +| `NE` +| does not equal +| 1 + +| `LT` +| less than +| 1 + +| `LE` +| less than or equal to +| 1 + +| `GT` +| greater than +| 1 + +| `GE` +| greater than or equal to +| 1 + +| `CONTAINS` +| contains +| 1 + +| `BEGINS_WITH` +| begins with +| 1 + +| `ENDS_WITH` +| ends with +| 1 + +| `BW_INC_MAX` +| between inclusive of the higher value +| 2 + +| `BW_INC_MIN` +| between inclusive of the lower value +| 2 + +| `BW_INC` +| between inclusive +| 2 + +| `BW` +| between non-inclusive +| 2 + +|`IN` +|is included in this list of values +|multiple +|=== +==== + +values:: +__String, Integer, or Boolean__. The list of operands. For example, if the column name is defined as `State`, the value can be the name of the state like `Michigan`. ++ +This attribute is defined as `val1`, `val2`, `val3` in the object URLs and REST API requests, and as `values` in the `runtimeFilters` array in the Visual Embed SDK. ++ +Some operators like `EQ`, `LE` accept a single operand, whereas `BW_INC_MAX`, `BW_INC_MIN`, `BW_INC`, `BW`, and `IN` accept multiple operands. + +=== Supported data types + +You can apply runtime filters on these data types: + +* VARCHAR +* BIGINT +* INT +* FLOAT +* DOUBLE +* BOOLEAN +* DATE +* DATE_TIME +* TIME + +[IMPORTANT] +==== +For the `DATE` and `DATE_TIME` data types, you must provide the date and time values in the Epoch time format. The Epoch time is also referred to as POSIX or Unix time. Epoch time is an integer value representing the number of seconds elapsed since 1 JAN 1970 00:00:00 UTC. You may have to convert time zones to calculate the appropriate timestamp. + +For example, if you want to filter data for 2020-05-22, you can specify the date value in the Epoch time format as `1590192000`, or use the following JavaScript method to calculate the timestamp: + +---- +new Date('2020-05-22').getTime() / 1000 +---- +==== + +== Apply runtime filters on a Liveboard or visualization + +The following examples show the runtime filter query string in a Liveboard URL: + +---- +https://{ThoughtSpot-Host}/#/pinboard/d084c256-e284-4fc4-b80c-111cb606449a?col1=State&op1=EQ&val1=California +---- + +---- +https://{ThoughtSpot-Host}/?col1=State&op1=EQ&val1=California#/pinboard/d084c256-e284-4fc4-b80c-111cb606449a +---- + +You can apply multiple filters in the same URL as shown in this example: + +---- +https://{ThoughtSpot-Host}/#/pinboard/d084c256-e284-4fc4-b80c-111cb606449a?col1=State&op1=EQ&val1=California&col2=product&op2=BEGINS_WITH&val2=Travel +---- + +//// +---- +https://{ThoughtSpot-Host}/?col1=State&op1=EQ&val1=California&col2=product&op2=BEGINS_WITH&val2=Travel#/pinboard/d084c256-e284-4fc4-b80c-111cb606449a +---- +//// + +== Apply runtime filters on embedded objects + +If you are xref:embed-without-sdk.adoc[embedding a Liveboard or visualization without using the Visual Embed SDK], you can append the filters in the embedded object URL as shown in these examples: + +---- +https://{ThoughtSpot-Host}/?embedApp=true&col1=State&op1=EQ&val1=michigan#/embed/viz/{Liveboard_id}/{visualization_id} +---- + +---- +https://{ThoughtSpot-Host}/?embedApp=true&col1=State&op1=EQ&val1=michigan&col2=product&op2=BEGINS_WITH&val2=Travel#/embed/viz/{Liveboard_id}/{visualization_id} +---- + +=== Runtime filters in Visual Embed SDK + +If you are embedding a Liveboard, visualization, or Answer using xref:visual-embed-sdk.adoc[Visual Embed SDK], you can apply filters using the `runtimeFilters` property. In the full app embed mode, ThoughtSpot applies runtime filters on all Liveboard, visualization, and Answer objects in the embedded app. + +The following example shows how to apply runtime filters on an embedded visualization in the SDK. Here, the runtime filter is operating on the `Revenue` column to filter the data matching `100000`. + +---- +liveboardEmbed.render({ + liveboardId: '133e6c5f-e522-41a0-b0ad-b9c3b066e276', + vizId: '28b73b4a-1341-4535-ab71-f76b6fe7bf92', + runtimeFilters: [{ + columnName: 'Revenue', + operator: RuntimeFilterOp.EQ, + values: ['100000' ] + }] + }); +---- + +==== Apply multiple runtime filters in the SDK + +The following examples show how to apply multiple runtime filters on Liveboard visualizations using the SDK: + +[#multiRuntimeFilters] +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'item type', // eg: color + operator: RuntimeFilterOp.EQ, + values: ['Jackets'] // eg: red + }, + { + columnName: 'Region', + operator: RuntimeFilterOp.IN, + values: ['Midwest', 'East', 'West'] + }, + { + columnName: 'Date', + operator: RuntimeFilterOp.EQ, + values: ['1656680400'] + } + ] +}); +---- + +===== Example video + +The following video shows how to apply multiple runtime filters on a Liveboard. + +[div videoContainer] +-- +video::./images/runtime-filters.mp4[width=100%,options="autoplay,loop"] +++++ + Copy sample code +Try it out in Playground + +++++ +-- + +[#runtimeFilterOp] +==== Runtime filter operator examples + +[width="100%" cols="3,7"] +[options='header'] +|===== +|Operator|Example (Visual Embed SDK) + +| `EQ` + +equals + +Number of values allowed: 1 + +a| + +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'state', + operator: RuntimeFilterOp.EQ, + values: ['california'] + }] +}); +---- + +| `NE` + +does not equal + +Number of values allowed: 1 +a| [source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'item type', + operator: RuntimeFilterOp.NE, + values: ['jackets'] + }] +}); +---- + +| `LT` + +less than + +Number of values allowed: 1 + +a| +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'revenue', + operator: RuntimeFilterOp.LT, + values: ['1000000'] + }] +}); +---- + +| `LE` + +less than or equal to + +Number of values allowed: 1 +a| +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'revenue', + operator: RuntimeFilterOp.LE, + values: ['5000000'] + }] +}); +---- + +| `GT` + +greater than + +Number of values allowed: 1 + +a| +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'revenue', + operator: RuntimeFilterOp.GT, + values: ['1000000'] + }] +}); +---- +| `GE` + +greater than or equal to + +Number of values allowed: 1 + +a| +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'revenue', + operator: RuntimeFilterOp.GE, + values: ['5000000'] + }] +}); +---- + +| `CONTAINS` + +contains + +Number of values allowed: 1 + +a| +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'item type', + operator: RuntimeFilterOp.CONTAINS, + values: ['Bags'] + }] +}); +---- + +| `BEGINS_WITH` + +begins with + +Number of values allowed: 1 + +a| +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'product', + operator: RuntimeFilterOp.BEGINS_WITH, + values: ['travel'] + }], + +}); +---- + +| `ENDS_WITH` + +ends with + +Number of values allowed: 1 + +a| [source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'item type', + operator: RuntimeFilterOp.ENDS_WITH, + values: ['shirts'] + }] +}); +---- + +| `BW_INC_MAX` + +between inclusive of the higher value + +Number of values allowed: 2 + +a| [source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'revenue', + operator: RuntimeFilterOp.BW_INC_MAX, + values: ['25','30'] + }] +}); +---- + +| `BW_INC_MIN` + +between inclusive of the lower value + +Number of values allowed: 2 + +a| [source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'revenue', + operator: RuntimeFilterOp.BW_INC_MIN, + values: ['25','50'] + }] +}); +---- + +| `BW_INC` + +between inclusive + +Number of values allowed: 2 + +a| +[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'sales', + operator: RuntimeFilterOp.BW_INC, + values: ['10','50'] + }] +}); +---- + +| `BW` + +between non-inclusive + +Number of values allowed: 2 + +a|[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'sales', + operator: RuntimeFilterOp.BW, + values: ['25','50'] + }] +}); +---- + +|`IN` + +is included in this list of values + +Number of values allowed: multiple +a|[source,JavaScript] +---- +liveboardEmbed.render({ + liveboardId: '543619d6-0015-4667-b257-eff547d13a12', + runtimeFilters: [{ + columnName: 'item type', + operator: RuntimeFilterOp.IN, + values: ['jackets', 'bags', 'shirts'] + }] +}); +---- +|===== + +==== SDK Events + +See xref:events-ref.adoc#_updateruntimefilters[UpdateRuntimeFilters] and xref:embed-events.adoc#_filters_in_embedded_ui[Filters in embedded UI]. + +== Apply runtime filters via REST API v1 endpoints + +To apply runtime filters on a Liveboard object in a REST API request, add the runtime filters to the API request URL as shown here: + +.URL format +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id={Liveboard_id}&col1={column-name}&op1={operator}&val1={value} +---- + +.Example +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=e36ee65e-64be-436b-a29a-22d8998c4fae&col1=State&op1=EQ&val1=California +---- + +The following example shows how to apply a runtime filter on a visualization object of a Liveboard: + +.URL format +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id={Liveboard_id}&vizid={visualization_id}&col1={column-name}&op1={operator}&val1={value} +---- + +.Example +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=543619d6-0015-4667-b257-eff547d13a12&vizid=%5B%224ff5b939-453d-40ff-8fc2-a1d972047c86%22%5D&col1=State&op1=EQ&val1=California +---- + +The following is another example of a REST API request URL with a filter. Here the runtime filter is operating on the column `Category` and returning values that are equal to `mfgr%2324`. + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata? +id=e36ee65e-64be-436b-a29a-22d8998c4fae&col1=Category +&op1=EQ&val1=mfgr%2324 +---- + +=== Apply additional filters + +You can add additional filters by incrementing the number at the end of each parameter in the runtime filter for each filter you add, for example, col2, op2, val2, and so on. To add additional filters on a particular column, you can specify multiple values by separating them with an ampersand (&) as shown in the example here: + +---- +val1=foo&val1=bar +---- + +You can also use the `IN` operator for multiple values, as shown in this example: + +---- +col1=&op1=IN&val1=&val1= +---- + +The following example passes multiple variables to a single column as well as multiple columns. It shows that the data values are returned as epochs. + +---- +col1=region&op1=IN&val1=midwest&val1=south&val1=northeast&col2=date&op2=BET&val2=&val2= +---- + +If the Liveboard or Answer already has one or more filters applied, runtime filters will act as an `AND` condition. This means that all filter conditions, including those supplied in the runtime filters and Liveboard filter, must match to get the desired data. + +In the following example, the OR condition is applied; That is, if at least one condition matches, the Liveboard returns data. + +.Example for OR condition +[source,JavaScript] +---- +runtimeFilters: [{ + columnName: 'product name', + operator: RuntimeFilterOp.CONTAINS, + values: ['bag', 'jackets'] +}] +---- +However, when multiple runtime filters are applied, or when the Liveboard already has a filter applied, the data must match all filter conditions. + +.Example for AND condition +[source,JavaScript] +---- +runtimeFilters: [{ + columnName: 'product name', + operator: RuntimeFilterOp.CONTAINS, + values: ['vest'] + }, + { + columnName: 'product name', + operator: RuntimeFilterOp.CONTAINS, + values: ['hoody'] + } +] +---- + +== Apply runtime filters via REST API v2.0 endpoints + +The following v2.0 endpoints support runtime filters in REST API requests: + +* `POST /api/rest/2.0/report/liveboard` ++ +Allows downloading Liveboard data in PDF, XLSX, CSV, and PNG format + +* `POST /api/rest/2.0/report/answer` ++ +Allows downloading Answer data in PDF, XLSX, CSV, and PNG format + +The following examples show the request body with runtime filter parameters. Note that you can add additional filters by incrementing the number at the end of each parameter: for example, col2, op2, val2. Some operators, such as `CONTAINS` and `IN`, allow passing multiple values in the `val` attribute. + +.Answer report + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/report/answer' \ + -H 'Authorization: Bearer {access-token} '\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata_identifier": "fa68ae91-7588-4136-bacd-d71fb12dda69", + "file_format": "XLSX", + "runtime_filter": { + "col1": "item type", + "op1": "CONTAINS", + "val1": [ + "Bags", + "Shirts" + ], + "col2": "state", + "op2": "EQ", + "val2": "California" + } +}' +---- + +.Liveboard report + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/report/liveboard' \ + -H 'Authorization: Bearer {access-token} '\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata_identifier": "0c68a0a1-930b-4ba0-b7a0-59ea49b09848", + "file_format": "PDF", + "runtime_filter": { + "col1": "item type", + "op1": "CONTAINS", + "val1": [ + "Bags", + "Shirts" + ], + "col2": "region", + "op2": "EQ", + "val2": "West", + "col3": "state", + "op3": "IN", + "val3": [ + "California", + "Nevada" + ] + } +}' +---- + +== Limitations of runtime filters + +* The `DATE` and `DATE_TIME` data types must be specified as EPOCH time (Unix or POSIX time) in runtime filters. +* Runtime filters work only on Answers and Liveboard visualizations built from Worksheets. Runtime filters on visualizations and Answers built directly from Tables, Views, and SQL Views do not work because the possibility of multiple join paths and join path choice is not supported as input in runtime filters. +* Runtime filters do not allow you to apply `HAVING` filters in the URL parameters. + +//// +* You cannot apply a runtime filter on a Liveboard or visualization built from tables and worksheets that have chasm traps. + +* Runtime filters do not work directly on top of tables. You must create a Worksheet if you want to use runtime filters. This means that the Liveboard or visualization on which you apply a runtime filter must be created on top of a Worksheet. + +* If the Worksheet was created from an Answer (it is an aggregated Worksheet), runtime filters will only work if the Answer was formed using a single Worksheet. If the Answer from which the Worksheet was created includes raw tables or joins multiple worksheets, you won't be able to use runtime filters on it. This is because of the join path ambiguity that could result. +//// diff --git a/docs/src/asciidocs/runtime-parameters.adoc b/docs/src/asciidocs/runtime-parameters.adoc new file mode 100644 index 000000000..c4631213c --- /dev/null +++ b/docs/src/asciidocs/runtime-parameters.adoc @@ -0,0 +1,188 @@ += Runtime Parameter overrides +:toc: true +:toclevels: 2 + +:page-title: Runtime Parameters +:page-pageid: runtime-params +:page-description: Use Parameters to run multiple scenarios with adjustable values, without changing your answer. + +ThoughtSpot lets you create Parameters in a Worksheet and integrate them into formulas, filters, data queries, and Liveboards. Parameters are useful for 'what-if' analysis, financial planning, cohort analysis, and so on. Parameters allow users to visualize data by running different scenarios with adjustable values. With Parameters, business users can use a single report and adjust the values dynamically to fit the scenario they want to analyze. + +== How to apply Parameters +You can use Parameters within formulas when querying your data via Search, Liveboards, or Answers. For more information about creating and using Parameters, see the following articles in ThoughtSpot product documentation. + +* link:https://docs.thoughtspot.com/cloud/latest/parameters-use[Using Parameters, window=_blank] +* link:https://docs.thoughtspot.com/cloud/latest/parameters-create[Creating Parameters, window=_blank] + +== Runtime overrides + +You can apply overrides to Parameter values at runtime and visualize data with the adjusted values. Like runtime filters, you can append the Parameter attribute to the object URLs and modify the resulting output. + +[NOTE] +==== +ThoughtSpot returns an error if an object URL with Parameter attributes exceeds 2000 characters. +==== + +To apply overrides to a Liveboard or Answer object, Parameters must be defined in the Worksheet from which the data is retrieved for live analytics. + +For example, if you want to override the value of the inflation Parameter on a Liveboard or Answer, add the Parameters to the object URL as shown in these examples: + +.Liveboard +---- +https://{ThoughtSpot-host}/?param1=Discount¶mVal1=0.25#/pinboard/d084c256-e284-4fc4-b80c-111cb606449a +---- + +---- +https://{ThoughtSpot-host}/#/pinboard/d084c256-e284-4fc4-b80c-111cb606449a?param1=Discount¶mVal1=0.25 +---- + +.Saved Answer +---- +https://{ThoughtSpot-host}/?param1=Discount¶mVal1=0.25#/saved-answer/3e84d95c-986e-4154-8362-3807906dad50 +---- + +.Search data +---- +https://{ThoughtSpot-host}/?param1=Discount¶mVal1=0.25#/answer/ +---- + +[IMPORTANT] +==== +For the `DATE` parameter, specify the value in Epoch time format. The Epoch time is also referred to as POSIX or Unix time. Epoch time is an integer value representing the number of seconds elapsed since 1 JAN 1970 00:00:00 UTC. You may have to convert time zones to calculate the appropriate timestamp. + +For example, if you want to filter data for 2020-05-22, you can specify the date value in the Epoch time format as `1590192000`, or use the following JavaScript method to calculate the timestamp: + +---- +new Date('2020-05-22').getTime() / 1000 +---- +==== + +== Apply Parameter overrides via REST API + +You can apply Parameter overrides to a Liveboard or Answer using REST v1 data API endpoints. + +[NOTE] +==== +REST API v2.0 endpoints do not support Parameter overrides. +==== + +=== Liveboard data +Before applying a Parameter override on a Liveboard, make sure the Worksheet used for generating visualizations contains Parameters. + +To apply overrides to a Liveboard via REST API, add Parameters to the xref:pinboarddata.adoc[Liveboard data API] request URL as shown in the example here: + +---- +https://{ThoughtSpot-host}/callosum/v1/tspublic/v1/pinboarddata?id=86bedf72-c718-49cc-9f49-6e8870233f35&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT¶m1=Double%20list%20param¶mVal1=0 +---- + +If the API request is valid, overrides are applied to the Liveboard data, and ThoughtSpot returns the requested data in API response. + +[source,JSON] +---- +{ + "adfaa348-755b-4b95-94ff-220c94c0c8b6": { + "columnNames": [ + "Ship Mode", + "Total Tax", + "Adjusted Tax" + ], + "data": [ + [ + "fob", + 7, + 0.0 + ], + [ + "mail", + 2, + 0.0 + ] + ], + "samplingRatio": 1.0, + "totalRowCount": 2, + "rowCount": 2, + "pageSize": 100000, + "offset": 0, + "name": "Parameters Answer" + } +} +---- + +=== Answer data + +Before applying a Parameter override on an Answer object, make sure the Worksheet used for generating the Answer data has the Parameters and formula configured. + +To apply overrides on an Answer obtained from a new search query, append the Parameter attributes to the xref:search-data-api.adoc[search data API] request URL as shown here: + +---- +https://{ThoughtSpot-host}/callosum/v1/tspublic/v1/searchdata?query_string=%20%5BTax%5D%5BShip%20Mode%5D&data_source_guid=540c4503-5bc7-4727-897b-f7f4d78dd2ff&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT¶m1=Double%20list%20param¶mVal1=0 +---- + +The following example shows the API response for the above request: + +[source,JSON] +---- +{ + "columnNames": [ + "Ship Mode", + "Total Tax" + ], + "data": [ + [ + "air", + 2888 + ], + [ + "fob", + 2802 + ], + [ + "mail", + 2833 + ], + [ + "rail", + 2885 + ], + [ + "reg air", + 3053 + ], + [ + "ship", + 2770 + ], + [ + "truck", + 2995 + ], + [ + null, + 2 + ] + ], + "samplingRatio": 1.0, + "totalRowCount": 8, + "rowCount": 8, + "pageSize": 100000, + "offset": 0 +} +---- + +=== Add additional Parameters + +You can add additional Parameters in the URL by incrementing the number for each Parameter attribute; for example, param1, param2, paramVal1, paramVal2, and so on. To add additional overrides, specify the values by separating them with an ampersand (&) as shown in the examples here: + +.URL +---- +https://{ThoughtSpot-host}/?param1=double%20list%20param¶mVal1=0¶m2=double%20param¶mVal2=0#/pinboard/d084c256-e284-4fc4-b80c-111cb606449a +---- + +.REST API request +---- +https://{ThoughtSpot-host}/callosum/v1/tspublic/v1/pinboarddata?id=e36ee65e-64be-436b-a29a-22d8998c4fae&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT¶m1=double%20list%20param¶mVal1=0¶m2=double%20param¶mVal2=0 +---- + +== Apply Parameter overrides using Visual Embed SDK + +Applying runtime Parameter overrides via Visual Embed SDK is not supported. diff --git a/docs/src/asciidocs/runtime-sort.adoc b/docs/src/asciidocs/runtime-sort.adoc new file mode 100644 index 000000000..71cd2c9de --- /dev/null +++ b/docs/src/asciidocs/runtime-sort.adoc @@ -0,0 +1,123 @@ += Runtime sorting of columns +:toc: true +:toclevels: 2 + +:page-title: Runtime sorting +:page-pageid: runtime-sort +:page-description: Use runtime parameters to sort data on a Liveboard visualization or Answer object. + +Runtime sorting allows applying sort criteria to a Liveboard or Answer object on load or when querying a Liveboard or Answer data via REST API calls. + +== How it works + +You can add runtime sort attributes as query parameters to the URL. The query parameter format of a runtime sort operation is as follows: + +---- +?sortCol1=&asc1= +---- + +sortCol1:: +__String__. Name of the column to sort by. For example, if you want to sort the `Sales` column in ascending order, you can specify the column name as `sortCol1=Sales`. + +asc1:: +__Boolean__. Optional. Indicates the sorting order. To sort a column in descending order, specify `asc1=false`. By default, the `asc1` value is set to `true`. + +The following example shows the URL parameters to sort the `Sales` column in descending order on a Liveboard. + +---- +https://{ThoughtSpot-host}/#/pinboard/c476b285-6285-4038-87af-d69d32531e48?sortCol1=Sales&asc1=false +---- + + +[NOTE] +==== +The runtime sort operation returns an error if the URL exceeds 2000 characters. +==== + +=== Support for multiple sort parameters + +You can append multiple runtime sort attributes to a Liveboard or Answer URL. Unlike runtime Filters, the runtime sort attribute-value pair must be applied in a specific order. + +The following example shows the correct order of runtime sort parameters: +---- +https://{ThoughtSpot-host}/#/pinboard/c476b285-6285-4038-87af-d69d32531e48?sortCol1=Sales&asc1=false&sortCol2=Tea&sortCol3=Revenue&asc3=false +---- + +In the above example, the `Sales` column is sorted in descending order first and then the `Tea` column is sorted alphabetically in ascending order. The `Revenue` column is sorted in descending order after the first two parameters are applied. + +If you swap the sort order of these columns, the resulting output changes accordingly. + +== Runtime sorting of columns via REST API + +You can use the REST API v1 or REST API v2 endpoints to apply runtime sorting parameters. + +=== REST API v1 + +If you are using REST API v1 endpoints, runtime sorts can be applied when fetching a Liveboard or Answer object from ThoughtSpot. + +To sort columns when fetching data from a Liveboard object, add sort properties to the Liveboard data API request URL as shown in the example here: + +---- +http://{ThoughtSpot-host}/callosum/v1/tspublic/v1/pinboarddata?id=e36ee65e-64be-436b-a29a-22d8998c4fae&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT&sortCol1=Sales&asc1=false +---- +---- +https://{ThoughtSpot-host}/callosum/v1/tspublic/v1/pinboarddata?id=e36ee65e-64be-436b-a29a-22d8998c4fae&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT&sortCol1=Sales&asc1=false&sortCol2=Tea +---- + +To sort columns of an Answer object, add the sort attributes to the search data API request URL as shown in the following examples: +---- +https://{ThoughtSpot-host}/callosum/v1/tspublic/v1/searchdata?batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT&sortCol1=Sales&asc1=false +---- + +---- +https://{ThoughtSpot-host}/callosum/v1/tspublic/v1/searchdata?batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT&sortCol1=Sales&asc1=false&sortCol2=Tea +---- + +=== REST API v2.0 + +The following REST API v2.0 endpoints support applying runtime sort parameters: + +* `POST /api/rest/2.0/report/liveboard` +* `POST /api/rest/2.0/report/answer` + +The following example shows the request body with runtime sort parameters: + +.Answer report + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/report/answer' \ + -H 'Authorization: Bearer {access-token} '\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata_identifier": "fa68ae91-7588-4136-bacd-d71fb12dda69", + "runtime_sort": { + "sortCol1": "sales", + "asc1": false, + "sortCol2": "region", + "asc2": true + }, + "file_format": "CSV" +}' +---- + +.Liveboard report + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/report/liveboard' \ + -H 'Authorization: Bearer {access-token} '\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata_identifier": "fa68ae91-7588-4136-bacd-d71fb12dda69", + "runtime_sort": { + "sortCol1": "sales", + "asc1": false, + "sortCol2": "region", + "asc2": true + }, + "file_format": "CSV" +}' +---- diff --git a/docs/src/asciidocs/sdk-reference.adoc b/docs/src/asciidocs/sdk-reference.adoc new file mode 100644 index 000000000..e93df9e63 --- /dev/null +++ b/docs/src/asciidocs/sdk-reference.adoc @@ -0,0 +1,31 @@ += Visual Embed SDK Reference +:toc: true + +:page-title: Visual Embed SDK Reference +:page-pageid: js-reference +:page-description: Visual Embed SDK Reference + +The ThoughtSpot Visual Embed SDK is an open source Javascript library used for embedding ThoughtSpot visualizations, Liveboards, and the entire application in web applications. The Embed SDK library allows you to connect your applications to the ThoughtSpot embedded components and programmatically import them within your application framework. + +== Visual Embed SDK libraries +The link:https://github.com/thoughtspot/visual-embed-sdk[Visual Embed SDK, window=_blank] is available for download as `@thoughtspot/visual-embed-sdk` through link:https://www.npmjs.com/package/@thoughtspot/visual-embed-sdk[NPM, window=_blank]. It exports the following classes: +//// +* link:https://visual-embed-sdk.vercel.app/docs/typedoc/classes/appembed.html[AppEmbed^, window=_blank] +* link:https://visual-embed-sdk.vercel.app/docs/typedoc/classes/LiveboardEmbed.html[LiveboardEmbed, window=_blank] +* link:https://visual-embed-sdk.vercel.app/docs/typedoc/classes/searchembed.html[SearchEmbed, window=_blank] + +For more specific information on Embed options and functions, see the link:https://visual-embed-sdk.vercel.app/docs/typedoc/modules.html[Visual Embed SDK Reference Guide, window=_blank]. + +//// +* link:{{visualEmbedSDKPrefix}}/classes/AppEmbed.html[AppEmbed^, window=_blank] +* link:{{visualEmbedSDKPrefix}}/classes/LiveboardEmbed.html[LiveboardEmbed, window=_blank] +* link:{{visualEmbedSDKPrefix}}/classes/SearchEmbed.html[SearchEmbed, window=_blank] +* link:{{visualEmbedSDKPrefix}}/classes/SearchBarEmbed.html[SearchBarEmbed, window=_blank] + +For more specific information on Embed options and functions, see the link:{{visualEmbedSDKPrefix}}/modules.html[Visual Embed SDK Reference Guide, window=_blank]. + +== Additional resources + +For information on how to use the Visual Embed SDK, see xref:getting-started.adoc[Get Started]. + +Additional examples can be found at link:https://github.com/thoughtspot/ts_everywhere_resources[ThoughtSpot Everywhere Resources on GitHub, window=_blank]. diff --git a/docs/src/asciidocs/search-assist-tse.adoc b/docs/src/asciidocs/search-assist-tse.adoc new file mode 100644 index 000000000..8228de2c4 --- /dev/null +++ b/docs/src/asciidocs/search-assist-tse.adoc @@ -0,0 +1,66 @@ += Enable Search Assist +:toc: true + +:page-title: Enable search assist +:page-pageid: search-assist +:page-description: Search Assist on embedded instances +:description: Enable Search Assist to demonstrate how to get construct your search query and view answers. + +The Search Assist feature provides sample scenarios of searching data from a Worksheet. Your application users can use this feature to familiarize themselves with the search experience and get the answers they need. + +To enable the Search Assist walkthrough on an embedded instance, the following steps are required: + +* Enable Search Assist in the Visual Embed SDK +* Configure Search Assist questions and answers (__Requires `Can manage data` privilege and edit access to a worksheet__) + +== Enable Search Assist in the SDK + +To enable Search Assist, set the `enableSearchAssist` parameter to `true`. The following example shows how to enable Search Assist in the `SearchEmbed` SDK. + +[source,JavaScript] +---- +const searchEmbed = new SearchEmbed(document.getElementById('ts-embed'), { + frameParams: { + width: '100%', + height: '100%', + }, + dataSources: ['<%=datasourceGUID%>'], + enableSearchAssist: true, + }, +}); +---- + +++++ +Try it out +++++ + + +== Configure Search Assist content + +By default, the Sample Retail link:https://docs.thoughtspot.com/cloud/latest/system-worksheet[system Worksheet, window=_blank] includes a Search Assist lesson with a predefined set of questions and instructions to guide your application users. + +To provide Search Assist walkthrough to your users with your own data, you must create a Search Assist lesson on your Worksheet. ThoughtSpot provides sample question templates, using which you can create your own Search Assist content. Any ThoughtSpot user with `Can manage data` privilege and edit access to the Worksheet can configure a Search Assist lesson. For more information about configuring a sample search lesson, see link:https://docs.thoughtspot.com/cloud/latest/search-assist-coach[Search Assist Coach, window=_blank]. + +//// +If Search Assist is enabled on your embedded instance, the sample queries and instructions will appear when your users log in to ThoughtSpot for the first time and go through the onboarding process. +//// + +== How to use Search Assist + +Search Assist walks you through simple search scenarios, using data from the Search Assist lesson created for a Worksheet. If Search Assist is enabled, and your Worksheet has the Search Assist queries configured, the embedded Search page allows you to try sample search scenarios. + +For example, if you are searching data from the Sample Retail Worksheet, the initial example asks *_What were Sales by Product in this year?_* and Search Assist guides you to select *_sales_* and press *Enter* on your keyboard. The search then returns the Answer as a table, demonstrating your total sales. + +Similarly, you can add keywords, such as *_product_* and *_this year_* to your search and press *Enter* to get an Answer with the total sales data for each product in the current year. + +== Feature limitations + +* Search Assist is available on instances that have ThoughtSpot Search functionality embedded using `SearchEmbed` or `AppEmbed` SDK library. +* Sample search queries and search experience walkthrough are available to users only if a Search Assist lesson is configured at the data source level. +* Search Assist lessons can be configured only on worksheets. +* To configure a Search Assist lesson on a Worksheet, make sure you have embedded the ThoughtSpot *Data* tab in your host app. + +== Related resources + +* link:https://docs.thoughtspot.com/cloud/latest/search-assist-coach[Search Assist Coach, window=_blank] +* link:https://docs.thoughtspot.com/cloud/latest/search-assist[Search Assist, window=_blank] \ No newline at end of file diff --git a/docs/src/asciidocs/search-data-api.adoc b/docs/src/asciidocs/search-data-api.adoc new file mode 100644 index 000000000..044b30f7f --- /dev/null +++ b/docs/src/asciidocs/search-data-api.adoc @@ -0,0 +1,348 @@ += Search data API +:toc: true +:toclevels: 1 + +:page-title: Search Data API +:page-pageid: search-data-api +:page-description: Search Data API + +To construct a search query string and retrieve data from ThoughtSpot programmatically, use the `/tspublic/v1/searchdata` REST API. + +== Supported operations + +include::{path}/search-api-list.adoc[] + +== Required permissions + +You must have view access to the data source objects to run a search query. + +== Search query + +When issuing a query through the ThoughtSpot UI, users make selections to disambiguate a query. It is often difficult to programmatically use the result set of a query that runs in the ThoughtSpot UI search bar. Because the selection is not possible with an API approach, the API query language is modified to include query disambiguation. + +[#components] +=== Components of a search query + +In ThoughtSpot Query Language, the components of a query are classified into various types of tokens: + +* xref:Column[Column] +* xref:Operator[Operator] +* xref:Value[Value] +* xref:Date-Bucket[Date Bucket] +* xref:Keyword[Keyword] +* xref:Calendar[Calendar] + +[#Column] +Column:: +Columns must be enclosed in square brackets, [ ]. + ++ +For example, in the query revenue by ship mode, both revenue and ship mode are columns. A valid query for the API is: + +---- +[revenue] by [ship mode] +---- +[#Operator] +Operator:: ThoughtSpot supports various operators such as =, !=, >, >=, \<=, <, contains, not contains, and so on. Use these operators in the API query in the same manner as in the UI. ++ +For example, specify revenue over 1000, and limit ship mode to 'air': + ++ +---- +[revenue] > 1000 [ship mode] = 'air' +---- +[#Value] +Value:: String (text) and date values must be enclosed within quotes, ''. Do not use quotes for numeric values, except for dates. ++ +When using multiple values, separate them by a comma. + ++ +For example, when a ThoughtSpot UI query is revenue top 2 ship mode, the equivalent API query is: + ++ +---- +[revenue] top 2 [ship mode] +---- + ++ +For example, when a ThoughtSpot UI query is revenue ship mode = air, the equivalent API query is: + ++ +---- +[revenue] [ship mode] = 'air' + +---- +[#Date-Bucket] +Date Bucket:: In the ThoughtSpot UI, when there are several date columns, users can bind date bucket tokens to a specific column. When using the API, this binding between the date column and the date bucket must be made explicit. Use a period to separate the column with which the date bucket is bound, and the date bucket token. ++ +Single word date buckets can be expressed as is. Multi-word date buckets must be enclosed within quotes. + ++ +For example, when a ThoughtSpot UI query is `revenue commit date monthly`, and if monthly is bound to commit date, the equivalent API query is: + ++ +---- +[revenue] [commit date].monthly +---- ++ +When a ThoughtSpot UI query is `revenue day of week = 5`, and if day of week is bound to commit date, the equivalent API query is as follows: + ++ +---- +[revenue] [commit date].'day of week' = 5 +---- + +[#Keyword] +Keyword:: Use keywords in the API query in the same manner as in the UI. ++ +For example, when a ThoughtSpot UI query uses keywords growth of and sort by, the equivalent API query is as follows: + ++ +---- +growth of [revenue] by [commit date] +---- + +[#Calendar] +Calendar:: You can specify a custom calendar in the query. Use the calendar.calendar_name format explicitly. ++ +When the calendar name contains multiple words, enclose these words in single quotes. + ++ +For example, when a ThoughtSpot UI query is revenue by commit date fiscal, where the name of the calendar is fiscal, the equivalent API query is as follows: + ++ +---- +[revenue] by [commit date] calendar.fiscal +---- ++ +For example, when a ThoughtSpot UI query is revenue by commit date my calendar, where the name of the calendar is my calendar, the equivalent API query is: + ++ +---- +[revenue] by [commit date] calendar.'my calendar' +---- + +=== Functional limitations + +* To avoid join path ambiguities, a query can use only a single data source. + +* Search execution of query strings is not case-sensitive. + +* All column names in the data source must have unique names and must pass the _case-insensitivity_ test. ++ +For example, Columns `[Revenue]` and `[revenue]` are not unique. +* Column names cannot contain square brackets, `[` or `]`. + +* Values must be enclosed in quotes, `‘’`, but they cannot contain quotes. + +* The API does not support **in-query formula** definitions. To use a formula, create it on the Worksheet or a table using the ThoughtSpot UI, and then use the named formula inside the API query. + +* Users must be authenticated and have read access to the data source. + +* Your browser locale must be `en-US`. Swagger does not accept other variations of English, such as British English, or other languages. Your search keywords must also be in American English. Your column names and other data values do not need to be in American English. You can change your preferred locale to `en-US` in your browser settings. + +== How to search data using the API + +To query data using the API, follow these steps: + +[#get-guid] +=== Determine the GUID of the data source + +. Log in to your ThoughtSpot application instance: + +. From the top navigation menu, click *Data*. ++ +Alternatively, navigate to the following address: + ++ +---- + https:///#/data/tables/ +---- + +. Select a data source that you plan to query: a Worksheet, a table, or a View. + +. In the address bar of the web browser, note the GUID of the selected data source; it is the last string of the address. For example, in the following address string, the GUID is `9d93a6b8-ca3a-4146-a1a1-e908b71b963f`: ++ +---- +https:///#/data/tables/9d93a6b8-ca3a-4146-a1a1-e908b71b963f +---- + +. Copy and save the GUID. + +=== Run the search query + +. In another browser, navigate to the following address: + ++ +---- +https:///external/swagger/#!/tspublic%2Fv1/searchData +---- + + +. Click `**POST** /tspublic/v1/searchdata` + +. Specify values for request parameters. For more information, see xref:search-data-api.adoc#search-data-api-ref[Search data API reference]. + +. Click **Try it out**, and note the results. + ++ +You can also verify if the query returns the same data when you run it in the ThoughtSpot UI search bar (with slightly different syntax). + +[#search-data-api-ref] +== Search data API reference + +[NOTE] +==== +The search data API allows you to pass the search query string as query parameters in the URL. Therefore, ThoughtSpot recommends that you append the query string to the URL, instead of using the `-d ` option to pass these parameters in your cURL requests. +==== + +==== Browser locale + +The search data API supports the search query string or keywords in `en-US` language only. Due to this, your browser locale must be set to `en-US` for a successful API call. ThoughtSpot recommends that you set the locale to `en-US` in the HTTP header request. + +---- +Accept-Language: en-US +---- + +When making REST API call from a browser, you can set the Accept-Language header directly to override the browser locale for that request. + +[source,javascript] +---- +// Using XMLHttpRequest +var xhr = XMLHttpRequest(); +xhr.setRequestHeader('Accept-Language', 'en-US'); +// ... + +// Using Fetch +const fetchOptions = { + method: 'POST', + headers: { + 'Accept-Language': 'en-US', + 'Content-Type': 'application/json', + // ... + }, + // ... +} +---- + +=== Resource URL +---- +POST /tspublic/v1/searchdata +---- + +=== Request parameters + +[width="100%", cols="2,2"] +[options='header'] +|==================== +| Query parameter | Description +|`query_string` |__String__. The data search query string. For more information, see xref:search-data-api.adoc#components[Components of a search query]. + +|`data_source_guid` |__String__. The GUID of the data source, either a Worksheet, a View, or a table. + +|`batchsize` |__Integer__. The batch size for loading search objects. + +The system default is -1. +| `pagenumber` | __Integer__. An alternate way to set offset for the starting point of the search results returned from the query. The default value is `-1`. + +`indexingOffset = (pageNumber - 1) * batchSize` + +| `offset` |__Integer__. Attribute to offset the starting point of the search results returned from the query. Specify a 1-based offset. The default value is `-1`. + +| `formattype` |__String__. The format of the data. + +Valid values are `COMPACT` or `FULL` JSON. The default value is `COMPACT`. +|==================== + +=== Example requests + +.cURL (COMPACT) +[source, cURL] +---- +curl -X POST \ +--header 'Accept-Language: en-US' \ +--header 'Content-Type: application/json' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/searchdata?query_string=%5Bsales%5D%20%5Bstore%20region%5D&data_source_guid=06517bd1-84c0-4bc6-bd09-f57af52e8316&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT' +---- + +.cURL (FULL) +[source, cURL] +---- +curl -X POST \ +--header 'Accept-Language: en-US' \ +--header 'Content-Type: application/json' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/searchdata?query_string=%5Bsales%5D%20%5Bstore%20region%5D&data_source_guid=06517bd1-84c0-4bc6-bd09-f57af52e8316&batchsize=-1&pagenumber=-1&offset=-1&formattype=FULL’ +---- + +.Request URL (COMPACT) +[source, html] +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/searchdata?query_string=%5Bsales%5D%20%5Bstore%20region%5D&data_source_guid=06517bd1-84c0-4bc6-bd09-f57af52e8316&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT +---- + +.Request URL (FULL) +[source,html] +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/searchdata?query_string=%5Bsales%5D%20%5Bstore%20region%5D&data_source_guid=06517bd1-84c0-4bc6-bd09-f57af52e8316&batchsize=-1&pagenumber=-1&offset=-1&formattype=FULL +---- + +=== Example response + +The data the API response contains four components: + +. The `columnNames` array that contains a list of all column headers. +. The `data` array that contains a list of sub-arrays. Each sub-array represents a new row of data. +. A sampling ratio. ++ +The sampling ratio tells you the percentage of total data returned. +A sampling ratio of `1` indicates that all the data in the Answer object was returned in the API response. + +[source,JSON] +---- +{ + "columnNames": [ + "Store Region", + "Total Sales" + ], + "data": [ + [ + "east", + 18934491.05134509 + ], + [ + "midwest", + 29157090.327609923 + ], + [ + "south", + 25484693.074720126 + ], + [ + "southwest", + 34241076.52103955 + ], + [ + "west", + 30848491.458509445 + ] + ], + "samplingRatio": 1, + "totalRowCount": 5, + "rowCount": 5, + "pageSize": 100000, + "offset": 0 +} +---- + +=== Response codes + +[options="header", cols="1,2"] +|=== +|HTTP Code|Description +|**200**|Successful retrieval of data from the data source +|**400**|Invalid query/data source +|=== diff --git a/docs/src/asciidocs/security-api.adoc b/docs/src/asciidocs/security-api.adoc new file mode 100644 index 000000000..d67d3df73 --- /dev/null +++ b/docs/src/asciidocs/security-api.adoc @@ -0,0 +1,571 @@ += Security APIs +:toc: true +:toclevels: 1 + +:page-title: Security API +:page-pageid: security-api +:page-description: security API + +The Security APIs allow you to share ThoughtSpot objects, such as Liveboards and visualizations, with another user or a user group. Any ThoughtSpot user can share objects with another user or user group. + +== Supported operations + +include::{path}/security-api-list.adoc[] + +=== Required permissions + +* To query object permissions, you must have administrator access. +* To share an object or visualization with another user, you must have edit access to the object. + +[#share-object] +== Share objects with another user + +To programmatically share ThoughtSpot objects with another user or user group, use the `/tspublic/v1/security/share` API. + +When you share an object like a Liveboard or visualization, a notification with a live link is sent to the user. When the users access this object, they can view the last saved version of the object. + +=== Resource URL +---- +POST /tspublic/v1/security/share +---- + +=== Request parameters + +[div tableContainer] +-- +[width="100%" cols="1,4"] +[options='header'] +|==== +|Form parameter|Description +|`type` a|__String__. Type of metadata object. Specify one of the following values as a metadata object type: + +* `QUESTION_ANSWER_BOOK` to share answers. +* `PINBOARD_ANSWER_BOOK` to share Liveboards. +* `LOGICAL_TABLE` to share a data object such as a table, Worksheet, or View. +* `LOGICAL_COLUMN` to share a column of any data object such as tables, worksheets, or views. + +|`id`|__String__. A JSON array of the GUIDs of the objects to be shared. +|`permission` a|_String__. A string with the GUIDs of the user or user group, and the type of access privilege. + +* The format of the permission string is `{"permissions":{"":{"shareMode":""}}}`. +* You can provide `READ_ONLY` or `MODIFY` access to the objects. With `READ_ONLY` access, the user or user group can view the shared object, whereas `MODIFY` access enables users to modify the object. + +For example, to provide read-only access to a user with a GUID of `7a9a6715-e154-431b-baaf-7b58246c13dd`, specify the string as shown here: + +[source,JSON] +---- +{"permissions":{"7a9a6715-e154-431b-baaf-7b58246c13dd":{"shareMode":"READ_ONLY"}}} +---- + +The following example shows how to set the permission string to provide read-only access to multiple users: + +[source,JSON] +---- +{"permissions": {"e7040a64-7ff1-4ab9-a1b0-f1acac596866": {"shareMode": "READ_ONLY"}, "f7b8f511-317c-485d-8131-26cf084ef47b": {"shareMode": "READ_ONLY"}}} +---- + +Similarly, to share objects with one or several user groups, specify the GUIDs and access permission type in the following format: + +[source,JSON] +---- +{"permissions":{"59481331-ee53-42be-a548-bd87be6ddd4a":{"shareMode":"READ_ONLY"}}} +---- + +[source,JSON] +---- +{"permissions": {"0f7af46f-e48c-4cca-b60f-d63d5ddbe59f": {"shareMode": "MODIFY"}, "e5fc80ce-db65-4921-8ece-c7bb44fceca1": {"shareMode": "READ_ONLY"}}} +---- + +[IMPORTANT] +==== +To remove a user or user group's access to a shared object, you can set the `shareMode` in the permission string to `NO_ACCESS`. For example, if you send a POST request with the permission string as `{"permissions":{"7a9a6715-e154-431b-baaf-7b58246c13dd":{"shareMode":"NO_ACCESS"}}}`, the user with a GUID of `7a9a6715-e154-431b-baaf-7b58246c13dd` cannot access the shared object. +==== + +|`emailshares`|__Array of Strings__. Email addresses to notify when the object is shared. +|`notify` __Optional__|__Boolean__. If set to `true`, an object share notification is sent to the specified email addresses. +|`message` __Optional__|__String__. The message text to send in the object share notification email. +|`useCustomEmbedUrls`|__Boolean__. When set to `true`, ThoughtSpot sends a customized link with the host application URL in the object share notification. You can use this attribute to generate links for embedded ThoughtSpot objects. +|==== +-- + +=== Example request + +.cURL + +[source, cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' --header 'X-Requested-By: ThoughtSpot' \ +-d 'type=PINBOARD_ANSWER_BOOK&id=["237921cc-ebf5-445a-8b7b-15c301f8456e"]&permission={"permissions":{"237921cc-ebf5-445a-8b7b-15c301f8456e":{"shareMode":"READ_ONLY"}}}&emailshares=["tsuser@thoughtspot.com"]¬ify=false&useCustomEmbedUrls=true' \ +'https:///callosum/v1/tspublic/v1/security/share' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/security/share +---- + +=== Example response +---- +Response code + +204 +---- + +=== Response codes + +[options="header", cols=".^2a,.^14a"] +|==== +|HTTP status code|Description +|**204**|Successful operation +|**400**|Invalid parameter value +|==== + + +[#shareviz] +== Share a visualization with another user or user group +If you want to share a specific visualization from a Liveboard with another user or user group, use the `/tspublic/v1/security/shareviz` API. This API lets you share the visualization with specific user IDs and provide read-only access. + +=== Resource URL +---- +POST /tspublic/v1/security/shareviz +---- +=== Request parameters + +[width="100%" cols="1,4"] +[options='header'] +|==== +|Form parameter|Description +|`type`|__String__. Type of the metadata object. The valid value is `PINBOARD_ANSWER_BOOK`. +|`pinboardId`|__String__. The GUID of the Liveboard to which the visualization belongs. +|`principalids`|__String__. The GUID of the users and groups to which you want to share the visualization. +|`vizid`|__String__. The GUID of visualization. +|`emailshares`|__Sring__. Email addresses to notify when the object is shared. +|`notify` __Optional__|__Boolean__. If set to `true`, an object share notification is sent to the specified email addresses. +|`message` __Optional__|__String__. The message text to send in the notification email. +|`useCustomEmbedUrls`|__Boolean__. When set to `true`, ThoughtSpot sends a customized link with the host application URL in the object share notification. You can use this attribute to generate links for embedded ThoughtSpot objects. +|==== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' --header 'X-Requested-By: ThoughtSpot' \ +-d 'type=PINBOARD_ANSWER_BOOK&pinboardId=7a9a6715-e154-431b-baaf-7b58246c13dd&principalids=%5B%2259481331-ee53-42be-a548-bd87be6ddd4a%22%5D&vizid=e9753523-5de5-41ef-8d8c-b840f0260ea0&emailshares=%5Btsuser%40thoughtspot.com%5D¬ify=true&useCustomEmbedUrls=false' 'https:///callosum/v1/tspublic/v1/security/shareviz' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/security/shareviz +---- + +=== Example response +---- +Response code + +204 +---- + +=== Response codes + +[options="header", cols=".^2a,.^14a"] +|=== +|HTTP status code|Description +|**204**|Successful operation +|**400**|Invalid parameter value +|=== + + +[#obj-permission-all] +== Get object permission details for a specific object type + +ThoughtSpot users can get access to objects through the privileges assigned to the groups to which they belong. This type of object permission is referred to as `EFFECTIVE`. + +Users can also access objects when another user shares a Liveboard or Answer directly with them or the user group to which they belong. This type of object permission is referred to as `DEFINED`. + +To get permission details for a specific metadata type and ID, send a `GET` request to the `/tspublic/v1/security/metadata/permissions` endpoint. + +=== Resource URL +---- +GET /tspublic/v1/security/metadata/permissions +---- + +=== Request parameters +[width="100%" cols="1,1,4"] +[options='header'] +|==== +|Parameter Name|Parameter Type|Description +|`type`|Query parameter a|__String__. Type of the object. Valid values are: + +* `QUESTION_ANSWER_BOOK` for answers. +* `PINBOARD_ANSWER_BOOK` for Liveboards. +* `LOGICAL_TABLE` for any data object such as a table, Worksheet, or View. +* `LOGICAL_COLUMN` for a column of any data object such as tables, worksheets, or views. + +|`id`| Query parameter|__String__. A JSON array of the GUIDs of the objects. +|`dependentshare` __Optional__|Query parameter|__Boolean__. Object permission details for the dependent objects. When set to `true`, the API returns the permission details for the dependent objects for the specified GUIDs. +|`permissiontype`|Query parameter a|__String__. Valid values are: + +* `EFFECTIVE` for object permissions inherited from group privileges. +* `DEFINED` for the explicitly defined permissions that a user may have assigned when sharing the specified objects. +|==== + +=== Example request + +.cURL + +[source, cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/security/metadata/permissions?type=PINBOARD_ANSWER_BOOK&id=%5B%22d084c256-e284-4fc4-b80c-111cb606449a%22%2C%20%2241a39422-2da0-4601-9d4a-59c27181c5f5%22%5D&dependentshare=false&permissiontype=EFFECTIVE' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/security/metadata/permissions?type=PINBOARD_ANSWER_BOOK&id=%5B%22d084c256-e284-4fc4-b80c-111cb606449a%22%2C%20%2241a39422-2da0-4601-9d4a-59c27181c5f5%22%5D&dependentshare=false&permissiontype=EFFECTIVE +---- + +=== Example response + +If the `GET` operation is successful, the API returns a response with the permission details for the specified object IDs. + +* Note that the `shareMode` property indicates the object-level permission assigned to a given user. + +** `READ_ONLY` indicates view permissions to an object +** `MODIFY` indicates edit permissions to an object + +* If the user doesn't have access to the specified objects, the API returns a `403 unauthorized` error. +* If the user doesn't have access to one of the specified objects, the API returns only those objects to which a user has `READ_ONLY` or `MODIFY` permissions. + +[source, JSON] +---- +{ + "41a39422-2da0-4601-9d4a-59c27181c5f5": { + "permissions": { + "59481331-ee53-42be-a548-bd87be6ddd4a": { + "topLevelObjectId": "41a39422-2da0-4601-9d4a-59c27181c5f5", + "shareMode": "READ_ONLY", + "dependents": [ + { + "id": "160e1259-5838-4688-a30a-2442b6d5281e", + "name": "Credit Consumption & Usage, Top 10 Users, This Month", + "author": "41a39422-2da0-4601-9d4a-59c27181c5f5", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "41a39422-2da0-4601-9d4a-59c27181c5f5" + }, + { + "id": "835ffe9d-78de-4817-a201-4a35385df18c", + "name": "Monthly Credits Consumed, with Unique Users", + "author": "41a39422-2da0-4601-9d4a-59c27181c5f5", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "41a39422-2da0-4601-9d4a-59c27181c5f5" + } + ] + } + } + }, + "d084c256-e284-4fc4-b80c-111cb606449a": { + "permissions": { + "59481331-ee53-42be-a548-bd87be6ddd4a": { + "topLevelObjectId": "d084c256-e284-4fc4-b80c-111cb606449a", + "shareMode": "READ_ONLY", + "dependents": [ + { + "id": "a9466299-4e89-4a2f-a1b2-d87337a4afc6", + "name": "Total Sales by Store", + "author": "d084c256-e284-4fc4-b80c-111cb606449a", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "d084c256-e284-4fc4-b80c-111cb606449a" + }, + { + "id": "d766e0da-2fa6-4af5-ab44-d86f28326c3a", + "name": "Total Sales by Product Type", + "author": "d084c256-e284-4fc4-b80c-111cb606449a", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "d084c256-e284-4fc4-b80c-111cb606449a" + } + ] + } + } + } +} +---- + +=== Response codes + +[options="header", cols=".^2a,.^14a"] +|=== +|HTTP status code|Description +|**200**|Successful operation +|**400**|Invalid parameter value +|**403**|Unauthorized request +|=== + +[#obj-permission-id] +== Get permission details for a specific object ID + +To get permission details for a specific object, send a `GET` request to the `/tspublic/v1/security/metadata/permissions` endpoint. + +=== Resource URL +---- +GET /tspublic/v1/security/metadata/{id}/permissions +---- + +=== Request parameters +[width="100%" cols="1,1,4"] +[options='header'] +|==== +|Parameter Name|Parameter Type|Description +|`type`|Query parameter a|__String__. Type of the object. Valid values are: + +* `QUESTION_ANSWER_BOOK` for answers. +* `PINBOARD_ANSWER_BOOK` for Liveboards. +* `LOGICAL_TABLE` for any data object such as a table, Worksheet, or View. +* `LOGICAL_COLUMN` for a column of any data object such as tables, worksheets, or views. + +|`id`| Path parameter|__String__. The GUID of the object to query. +|`dependentshare` __Optional__|Query parameter|__Boolean__. Object permission details for the dependent objects. When set to `true`, the API returns the permission details for the dependent objects for the specified GUID. +|`permissiontype`|Query parameter a|__String__. Valid values are: + +* `EFFECTIVE` for object permissions inherited from group privileges. +* `DEFINED` for the explicitly defined permissions that a user may have assigned when sharing the specified object. +|==== + +=== Example request + +.cURL + +[source, cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/security/metadata/d084c256-e284-4fc4-b80c-111cb606449a/permissions?type=PINBOARD_ANSWER_BOOK&dependentshare=false&permissiontype=EFFECTIVE' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/security/metadata/d084c256-e284-4fc4-b80c-111cb606449a/permissions?type=PINBOARD_ANSWER_BOOK&dependentshare=false&permissiontype=EFFECTIVE' +---- + +=== Example response + +If the `GET` operation is successful, the API returns a response with the permission details for the specified object. + +* Note that the `shareMode` property indicates the object-level permission assigned to a given user. + +** `READ_ONLY` indicates view permissions to an object +** `MODIFY` indicates edit permissions to an object + +* If the user doesn't have access to the specified object, the API returns a `403 unauthorized` error. + + +[source, JSON] +---- +{ + "d084c256-e284-4fc4-b80c-111cb606449a": { + "permissions": { + "59481331-ee53-42be-a548-bd87be6ddd4a": { + "topLevelObjectId": "d084c256-e284-4fc4-b80c-111cb606449a", + "shareMode": "READ_ONLY", + "dependents": [ + { + "id": "d0f39bd0-47ae-45af-a214-bea2286e220a", + "name": "Total Quantity Purchased by Product", + "author": "d084c256-e284-4fc4-b80c-111cb606449a", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "d084c256-e284-4fc4-b80c-111cb606449a" + }, + { + "id": "a9466299-4e89-4a2f-a1b2-d87337a4afc6", + "name": "Total Sales by Store", + "author": "d084c256-e284-4fc4-b80c-111cb606449a", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "d084c256-e284-4fc4-b80c-111cb606449a" + }, + { + "id": "d766e0da-2fa6-4af5-ab44-d86f28326c3a", + "name": "Total Sales by Product Type", + "author": "d084c256-e284-4fc4-b80c-111cb606449a", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "d084c256-e284-4fc4-b80c-111cb606449a" + } + ] + } + } + } +} +---- + +=== Response codes + +[options="header", cols="2,4"] +|==== +|HTTP status code|Description +|**200**|Successful operation +|**400**|Invalid parameter value +|**403**|Unauthorized request +|==== + +[#get-obj-perm-bulk] +== Get object permission details for multiple object types + +To query object permission details for multiple object types and IDs, send a `POST` request to the `/tspublic/v1/security/effectivepermissionbulk` endpoint. + +=== Resource URL + +---- +POST /tspublic/v1/security/effectivepermissionbulk +---- + +=== Request parameters + +[width="100%" cols="1,4"] +[options='header'] +|==== +|Form parameter|Description +|`idsbytype` a|__Array of Strings__. A JSON array of the object IDs for each object type. Valid object types are: + +* `QUESTION_ANSWER_BOOK` for answers. +* `PINBOARD_ANSWER_BOOK` for Liveboards. +* `LOGICAL_TABLE` for any data object such as a table, Worksheet, or View. +* `LOGICAL_COLUMN` for a column of any data object such as tables, worksheets, or views. + +For example, to get permission details for specific Liveboards and answers, specify the value of `idsbytype` as shown here: +---- +{"PINBOARD_ANSWER_BOOK": ["d084c256-e284-4fc4-b80c-111cb606449a"], "QUESTION_ANSWER_BOOK": ["92f48c07-9c62-4bfa-81ac-55f3049165b4"]} +---- +|`dependentshare` __Optional__|__Boolean__. Object permission details for the dependent objects. When set to `true`, the API returns the permission details for the dependent objects of the specified object types and IDs. +|==== + +=== Example request + +.cURL + +[source, cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'idsbytype=%7B%20%09%22PINBOARD_ANSWER_BOOK%22%3A%20%5B%22d084c256-e284-4fc4-b80c-111cb606449a%22%5D%2C%20%09%22QUESTION_ANSWER_BOOK%22%3A%20%5B%2292f48c07-9c62-4bfa-81ac-55f3049165b4%22%5D%20%7D&dependentshare=true' \ +'https:///callosum/v1/tspublic/v1/security/effectivepermissionbulk' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/security/effectivepermissionbulk +---- + +=== Example response + +If the data query operation is successful, the API returns the object permission details for the specified object IDs and types. + +* Note that the `shareMode` property indicates the object-level permission assigned to a given user. + +** `READ_ONLY` indicates view permissions to an object +** `MODIFY` indicates edit permissions to an object + +* If the user doesn't have access to the specified objects, the API returns a `403 unauthorized` error. +* If the user doesn't have access to one of the specified objects, the API returns only those objects to which a user has `READ_ONLY` or `MODIFY` permissions. + + +[source, JSON] +---- +{ + "QUESTION_ANSWER_BOOK": { + "92f48c07-9c62-4bfa-81ac-55f3049165b4": { + "permissions": { + "59481331-ee53-42be-a548-bd87be6ddd4a": { + "topLevelObjectId": "92f48c07-9c62-4bfa-81ac-55f3049165b4", + "shareMode": "READ_ONLY", + "dependents": [ + { + "id": "44cb25f9-9032-4d45-9d74-bbf66e1502f0", + "name": "Username", + "author": "965b5f46-7162-4c16-8aac-7ab26f313b25", + "type": "LOGICAL_COLUMN", + "shareMode": "READ_ONLY", + "isHidden": false, + "owner": "965b5f46-7162-4c16-8aac-7ab26f313b25", + "ownerName": "Credit Usage Worksheet" + }, + { + "id": "5ff6043f-a340-46e0-98f1-84b4b3a96f1b", + "name": "Credit Window ID", + "author": "965b5f46-7162-4c16-8aac-7ab26f313b25", + "type": "LOGICAL_COLUMN", + "shareMode": "READ_ONLY", + "isHidden": false, + "owner": "965b5f46-7162-4c16-8aac-7ab26f313b25", + "ownerName": "Credit Usage Worksheet" + } + ], + "answerBookQueryEditable": true + } + } + } + }, + "PINBOARD_ANSWER_BOOK": { + "d084c256-e284-4fc4-b80c-111cb606449a": { + "permissions": { + "59481331-ee53-42be-a548-bd87be6ddd4a": { + "topLevelObjectId": "d084c256-e284-4fc4-b80c-111cb606449a", + "shareMode": "READ_ONLY", + "dependents": [ + { + "id": "d0f39bd0-47ae-45af-a214-bea2286e220a", + "name": "Total Quantity Purchased by Product", + "author": "d084c256-e284-4fc4-b80c-111cb606449a", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "d084c256-e284-4fc4-b80c-111cb606449a" + }, + { + "id": "d766e0da-2fa6-4af5-ab44-d86f28326c3a", + "name": "Total Sales by Product Type", + "author": "d084c256-e284-4fc4-b80c-111cb606449a", + "type": "QUESTION_ANSWER_BOOK", + "shareMode": "READ_ONLY", + "isHidden": true, + "owner": "d084c256-e284-4fc4-b80c-111cb606449a" + } + ] + } + } + } + } +} +---- + +=== Response codes + +[options="header", cols=".^2a,.^14a"] +|=== +|HTTP status code|Description +|**200**|Successful operation +|**400**|Invalid parameter value +|**403**|Unauthorized request +|=== + diff --git a/docs/src/asciidocs/security-settings.adoc b/docs/src/asciidocs/security-settings.adoc new file mode 100644 index 000000000..ae88aace2 --- /dev/null +++ b/docs/src/asciidocs/security-settings.adoc @@ -0,0 +1,178 @@ += Security settings +:toc: true + +:page-title: Security settings +:page-pageid: security-settings +:page-description: Security settings for embedding + +For security purpose, most web browsers block cross-site scripting, cross-domain requests, and third-party cookies by default. Web browsers also have built-in security mechanisms such as same-origin and content security policies. These policies restrict how applications and scripts from one origin (domain) can interact with the resources hosted on another origin (domain). + +== Add trusted domains for embed support + +If you have embedded ThoughtSpot content within your application page using an inline frame, web browsers may block the embedded content. If your host application and embedded ThoughtSpot instance are on different domains, most web browsers also block cross-domain requests by default. + +To enable seamless interaction between your host application and the embedded ThoughtSpot instance, you need to configure the following security settings in ThoughtSpot: + +** Trusted hosts for CORS ++ +To allow your application to call ThoughtSpot, access its resources, and render embedded content, you must add your domain as a trusted host and enable Cross-Origin Resource Sharing (CORS). + +** Trusted hosts for CSP ++ +To allow your application to embed ThoughtSpot and access its content via web browsers, add your application domain as a trusted host in the CSP allowlist. You need to also add the domain URLs to the `connect-src` allowlist to load script interfaces and allow Javascript events. + ++ +Users with admin or developer privileges can configure the CORS and CSP allowlists on the *Security Settings* page in the *Develop* tab of the ThoughtSpot UI. + +[#csp-viz-embed-hosts] +=== Add CSP visual embed hosts +To allow your host domain to set the `frame-ancestors` CSP policy header and embed a ThoughtSpot object within your application frame, add your application domain as a CSP visual embed host. + +. Log in to your ThoughtSpot application instance. +. Click the *Develop* tab. +. Go to *Customizations* > *Security settings*. +. Click *Edit*. +. In the *CSP visual embed hosts* text box, add the domain names. For valid domain name formats, See xref:security-settings.adoc#csp-cors-hosts[Domain name format for CSP and CORS configuration]. +. Click *Save changes*. + +[#csp-connect-src] +=== Add URLs to CSP connect-src allowlist +If you plan to create custom actions with URL targets, you must add the domain names of these URLs to the `CSP connect-src` allowlist. This allows JavaScript events triggered by the custom action URLs. + +. Log in to your ThoughtSpot application instance. +. Click the *Develop* tab. +. Go to *Customizations* > *Security settings*. +. Click *Edit*. +. In the *CSP connect-src domains* text box, add the domain names. For valid domain name formats, See xref:security-settings.adoc#csp-cors-hosts[Domain name format for CSP and CORS configuration]. +. Click *Save changes*. + +[#cors-hosts] +=== Enable CORS + +The CORS configuration for your cluster controls which domains can access and modify your application content. To allow your application to call ThoughtSpot or its REST API endpoints, and request resources, you must add your application domain to the CORS allowlist. For example, if your website is hosted on the `example.com` domain and the embedded ThoughtSpot content is hosted on the `example.thoughtspot.com`, you must add the `example.com` domain to the CORS allowlist for cross-domain communication. You can also add `\http://localhost:8080` to the CORS allowlist to test your deployments locally. However, we recommend that you disable `localhost` access in production environments. + +If you enable CORS for your application domain, ThoughtSpot adds the `Access-Control-Allow-Origin` header in its API responses when your host application sends a request to ThoughtSpot. + +To add domain names to the CORS allowlist, follow these steps: + +. Log in to your ThoughtSpot application instance. +. Click the *Develop* tab. ++ +If you are using a multi-tenant cluster with Orgs, select the Org and then click the **Develop** tab. +. Go to *Customizations* > *Security settings*. +. Click *Edit*. +. In the *CORS whitelisted domains* text box, add the domain names. For valid domain name formats, See xref:security-settings.adoc#csp-cors-hosts[Domain name format for CSP and CORS configuration]. +. Click *Save changes*. + +[NOTE] +==== +On multi-tenant clusters with Orgs, the CORS allowlist includes all the domain URLs added at the Org and cluster level. +==== +== Add trusted domains for font, CSS, and image import + +Starting from ThoughtSpot Cloud 8.10.0.cl release, you can add trusted source URLs from which images, fonts, and stylesheets can be retrieved. + +. To define an allowed list of source URLs and domains, go to *Develop* > *Customizations* > *Security Settings*. +. Click *Edit*. +. In the *CSP img-src domains* field, add the domains from which you want to load images and favicons. +. In the *CSP font-src domains* field, add the domains from which you want to load fonts. +. In the *CSP style-src domains* field, add the domains from which you want to load stylesheets. +. Make sure the domain names are valid and listed as comma-separated values. +. Click *Save changes*. + + +[#csp-cors-hosts] +== Domain name format for CSP and CORS configuration + +[IMPORTANT] +==== +[#port-protocol] +Note the following points if using port or protocol in the domain name string: + +* The UI allows you to add a domain URL with or without the protocol (`http/https`) in the CSP allowlist. To avoid long URLs in the CSP header, we recommend that you don't include the protocol in the domain name string. However, for non-HTTPS domains, such as your local testing environment, do include `http` in the domain name string. + +* Although you can add a domain URL with the protocol (`http/https`) to the CORS allowlist, ThoughtSpot ignores the protocol in the domain names of CORS hosts. Therefore, you can exclude the protocol in the domain name strings. +* If your domain URL has a non-standard port such as 8080, specify the port number in the domain name string. +==== + +The following table shows the valid domain name strings for the CORS and CSP allowlists. + +[div tableContainer] +-- + +[width="100%" cols="4,2,2,2,2"] +[options='header'] +|==== +|Domain name format|CSP Visual Embed host|CSP connect-src |CORS |CSP font-src + +CSP style-src + +CSP img-src + +a|Domain URL strings without protocol + + +* `thoughtspot.com` +* `www.thoughtspot.com` + + +|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported 2*|[tag greenBackground]#✓# Supported + +a|Domain URL strings for localhost + +* `localhost` +* `localhost:3000` +* `\http://localhost:3000` + +|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported 2*|[tag greenBackground]#✓# Supported +a|Domain URL strings without port + +* `thoughtspot.com` +* `mysite.com` + +If your domain URL has a non-standard port, for example, `mysite.com:8080`, make sure you add the port number in the domain name string. + +|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported 2*|[tag greenBackground]#✓# Supported +|Wildcard (`*`) for domain URL|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported| [tag redBackground]#x# Not supported |[tag greenBackground]#✓# Supported +|Wildcard +++(*)+++ before the domain name extension + +`\https://*.com`|[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported 2*|[tag redBackground]#x# Not supported +|Plain text string without the domain name extension. + + +`thoughtspot`|[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported 2*|[tag redBackground]#x# Not supported +|Domain name with wildcard (*) and a leading dot + + +`+++.*.thoughtspot.com +++` |[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported |[tag greenBackground]#✓# Supported |[tag redBackground]#x# Not supported + +a|Wildcard before the domain name + + +`+++*+++.thoughtspot.com` + +|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported |[tag redBackground]#x# Not supported|[tag greenBackground]#✓# Supported + +a| Domain names with space, backslash (\), and wildcard (*). + +* `www.+++*+++.+++*+++.thoughtspot.com` + +* `www.thoughtspot.com/*` + +* `thoughtspot .com` + +|[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported 2*|[tag redBackground]#x# Not supported +|URLs with query parameters + +`\http://thoughtspot.com?2rjl6`|[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported 2*|[tag redBackground]#x# Not supported +|URLs with path parameters + +`thoughtspot.com/products`|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported |[tag redBackground]#x# Not supported|[tag greenBackground]#✓# Supported +|URLs with path and query parameters + +`thoughtspot.com/products?id=1&page=2`|[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported 2*|[tag redBackground]#x# Not supported +|IPv4 addresses + +`255.255.255.255`|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported 2*|[tag greenBackground]#✓# Supported +|Semicolons as separators + +`thoughtspot.com; thoughtspot.com;`|[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported 2*|[tag redBackground]#x# Not supported +|Comma-separated values + +`thoughtspot.com, thoughtspot.com`|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported 2*|[tag greenBackground]#✓# Supported +|`mail://xyz.com`|[tag redBackground]#x# Not supported|[tag redBackground]#x# Not supported 2*|[tag redBackground]#x# Not supported +a|+++Wildcard (*) for port+++ + +`thoughtspot:*`|[tag greenBackground]#✓# Supported|[tag greenBackground]#✓# Supported 2*|[tag greenBackground]#✓# Supported +|==== +-- + +== Block access to non-embedded ThoughtSpot pages + +If you have embedded ThoughtSpot using Visual Embed SDK v1.22.0 or later, the `blockNonEmbedFullAppAccess` property is enabled by default to prevent embedded application users from navigating to the non-embedded ThoughtSpot pages. If you are embedding ThoughtSpot without the SDK, you can block access to non-embedded application pages by turning on the **Block non-embed full app access** toggle switch on the **Security Settings** page. + +From 9.4.0.cl release onwards, you can enable **Block non-embed full app access** on the **Security Settings** page at the Org level on multi-tenant clusters. However, the `blockNonEmbedFullAppAccess` setting in the Visual Embed SDK is applied at the cluster level and can override the **Block non-embed full app access** configuration setting applied at the Org level via **Develop** > **Customizations** > **Security Settings**. diff --git a/docs/src/asciidocs/session-api.adoc b/docs/src/asciidocs/session-api.adoc new file mode 100644 index 000000000..9fe95b705 --- /dev/null +++ b/docs/src/asciidocs/session-api.adoc @@ -0,0 +1,524 @@ += Session APIs +:toc: +:toclevels: 1 + +:page-title: Session API +:page-pageid: session-api +:page-description: To log in to ThoughtSpot and create user sessions, use the session API endpoints + +The Session APIs allow ThoughtSpot users to authenticate and manage their sessions. + +== Supported operations +include::{path}/session-api-list.adoc[] + +=== Required permissions + +You require ThoughtSpot login credentials to create a session object and obtain a login token. + +[#session-login] +== Sign in as a ThoughtSpot user (Basic authentication) + +include::{path}/log-in-api.adoc[] + +[#session-authToken] +== Obtain a token for trusted authentication + +include::{path}/auth-token-api.adoc[] + + +[#session-loginToken] +== Authenticate and log in with a token (Trusted authentication) +include::{path}/login-token-api.adoc[] + +[#session-logout] +== Log out of a user session + +include::{path}/log-out-api.adoc[] + + +[#session-info] +== Get session information + +To get the session information for the current logged-in user on a given ThoughtSpot cluster, send a `GET` request to the `/tspublic/v1/session/info` endpoint. + +=== Resource URL +---- +GET /tspublic/v1/session/info +---- + +=== Example request + +.cURL +[source, cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/session/info' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/session/info +---- + +=== Example response + +If the operation is successful, the API returns a response with the session information and the current configuration of the cluster. + +[source,JSON] +---- +{ + "userName": "tsuser1", + "userDisplayName": "Administrator", + "userEmail": "tsuser1@thoughtspot.com", + "userCreatedTime": 1354006445722, + "userExpirationTime": 1634345144438, + "userGUID": "59481331-ee53-42be-a548-bd87be6ddd4a", + "apiVersion": "v1", + "canChangePassword": true, + "isSystemUser": false, + "logicalModelVersion": 401, + "userGroupMask": 6, + "privileges": [ + "ADMINISTRATION", + "USERDATAUPLOADING", + "DATADOWNLOADING", + "DATAMANAGEMENT", + "SHAREWITHALL", + "A3ANALYSIS" + ], + "expirationTime": 1632154574, + "authToken": "gv4HjljdCZKbN4LMEHNn0p7ct12/4KSaCwKDfu/UVnA=", + "locale": "en_GB", + "timezone": "UTC", + "dateFormat": { + "formatPattern": "dd/MM/yyyy" + }, + "timeFormat": { + "formatPattern": "HH:mm:ss" + }, + "dateTimeFormat": { + "formatPattern": "dd/MM/yyyy HH:mm" + }, + "integerFormat": {}, + "decimalFormat": {}, + "clientState": { + "preferences": { + "HOMEPAGE_EUREKA": true, + "PANEL_STATE": "EXPANDED", + "sageDataSource": [ + "8eaf2704-9754-4c48-830d-27e5317b2c64", + "b0248372-5e68-4815-8682-67715456efb2" + ], + "OPEN_ANSWER_EDIT_PANEL": "VIZ_EDITOR" + }, + "tips": { + "chartConfigChipTip": true + } + }, + "configInfo": { + "highCardinalityMaxDataSize": 20000, + "fetchPivotSummaryFromBackend": true, + "vizRenderingQueueTimeoutMS": 30000, + "enableColumnSummariesByDefault": true, + "isAnswerV2OnByDefault": false, + "defaultChartDataSize": 5000, + "maxFilterValues": 10000, + "useDomainQualifiedName": true, + "enableInstantSearch": false, + "defaultFilterNonCascading": false, + "pinboardFilterConfiguratorDisabled": false, + "isAnswerUndoStackEnabled": false, + "answerV2Experience": true, + "enablePinboardV2": false, + "enableCJA": false, + "blinkHelpConfigList": [ + { + "enabled": true, + "title": "Keywords", + "id": "BLINK_KEYWORDS", + "url": "https://cloud-docs.thoughtspot.com/{versionNameForLink}/reference/keywords.html", + "iconFilePath": "" + }, + { + "enabled": true, + "title": "Release notes", + "id": "BLINK_RELEASE_NOTES", + "url": "https://cloud-docs.thoughtspot.com/{versionNameForLink}/release/notes.html", + "iconFilePath": "" + }, + { + "enabled": true, + "title": "Documentation", + "id": "BLINK_DOCUMENTATION", + "url": "https://cloud-docs.thoughtspot.com/{versionNameForLink}", + "iconFilePath": "" + } + ], + "blinkActionConfigList": [], + "embedActionConfigList": [ + { + "id": "598450a5-c402-4dcb-a127-8797bcda378f", + "name": "view report", + "version": "v2", + "type": "CALLBACK", + "detail": { + "link": "", + "function": "view-report", + "authSelect": "NONE", + "authToken": "", + "encodeUser": "", + "apiKey": "X-API-KEY", + "apiValue": "", + "additionalUrlHeaders": "{}" + }, + "actionAssociationMap": { + "ANSWER": { + "087f51a0-f352-4497-b39a-e69ea8b4d5a1": { + "enabled": "true", + "context": "NONE" + } + } + }, + "context": "NONE", + "availability": [ + "GLOBAL" + ] + }, +} +---- + + +=== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**200**|Successful operation. +|=== + + + +[#orgSwitch] +== Switch between Orgs + +If your ThoughtSpot instance has multiple Orgs, you can switch between Orgs by using the `/tspublic/v1/session/orgs` endpoint. + +Only the cluster administrator and users that belong to multiple Orgs can switch between the Orgs. + +=== Resource URL +---- +PUT /tspublic/v1/session/orgs +---- + +=== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Form parameter|Description +|`orgid` a|__Integer__. ID of the Org object. The org ID `0` indicates `Primary Org`. To switch to another Org, specify the Org ID. + +To know the Org IDs of the Orgs that you can access, send a GET request to the `/tspublic/v1/session/orgs` endpoint. +|=== + +=== Example request + +.cURL + +[source, cURL] +---- +curl -X PUT \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +-d 'orgid=-1' \ +'http:///callosum/v1/tspublic/v1/session/orgs' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/session/orgs +---- + +=== Example response +If the API request is successful, ThoughtSpot returns the 204 response code: + +---- +Response Code +204 +---- + +=== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**204** | Successful operation +|**400**| Invalid parameter +|**403**| Unauthorized request +|=== + +[#getOrgs] +== Get Orgs for the logged-in user + +To get a list of Orgs for the current logged-in user, send a `GET` request to the `/tspublic/v1/session/orgs` API endpoint. + + +* If the logged-in user is a cluster administrator, the API returns all active Orgs. + +* If the logged-in user belongs to more than one Org, the API returns all the active Orgs to which the user belongs. + +=== Resource URL +---- +GET /tspublic/v1/session/orgs +---- + +=== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Query parameter|Description +|`batchsize` __Optional__ |__Integer__. The batch size of the Org objects returned in the API response. The system default is -1. A value of -1 implies all items starting from the offset value. +|`offset` __Optional__ |__Integer__. The batch offset value that indicates the index point starting from which the list of Org objects are retrieved. The system default is -1, which implies the first item in the list. +|=== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +'http:///callosum/v1/tspublic/v1/session/orgs?batchsize=-1&offset=-1' +---- + +.Request URL +---- +http:///callosum/v1/tspublic/v1/session/orgs?batchsize=-1&offset=-1 +---- + +=== Example response + +If the API request is successful, ThoughtSpot returns a list of active Orgs for the logged-in user: + +[source,JSON] +---- +{ + "orgs": [ + { + "orgId": 0, + "orgName": "Primary", + "description": "Primary Org", + "allUserGroupId": "b25ee394-9d13-49e3-9385-cd97f5b253b4", + "defaultAdminUserGroupId": "d0326b56-ef23-4c8a-8327-a30e99bcc72b", + "isActive": true + }, + { + "orgId": 1776311864, + "orgName": "my-org1", + "description": "", + "allUserGroupId": "a4ef5fe2-0f90-4632-bd2c-d447428495b8", + "defaultAdminUserGroupId": "203182f3-3ae1-422f-ae65-30c72f92b665", + "isActive": true + }, + { + "orgId": 255226812, + "orgName": "my-org2", + "description": "", + "allUserGroupId": "d15f3347-1e3a-48a9-bbb5-c31c368b054e", + "defaultAdminUserGroupId": "1ce55b07-42f1-434f-b1e5-a71b2f78289d", + "isActive": true + }, + ], + "canAdministerAllOrgs": true, + "currentOrgId": 0 +} +---- + +=== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**204** | Successful operation +|**403**| Unauthorized request +|=== + +[#getOrgsForUser] +== Get Orgs for a specific user + +To get a list of Orgs for a specific user, send a `GET` request to the `tspublic/v1/session/orgs/users/{userid}` API endpoint. + + +=== Resource URL +---- +GET /tspublic/v1/session/orgs/users/{userid} +---- + +=== Request parameters +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Type|Description +|`userid` |Path parameter|__String__. GUID of the user. +|`orgScope`|Query|__String__. The Org scope. Specify `ALL` to set the Org scope to all Orgs. +|=== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +'http:///callosum/v1/tspublic/v1/session/orgs/users/59481331-ee53-42be-a548-bd87be6ddd4a?orgScope=ALL' +---- + +.Request URL +---- +http:///callosum/v1/tspublic/v1/session/orgs/users/59481331-ee53-42be-a548-bd87be6ddd4a?orgScope=ALL +---- + +=== Example response + +If the API request is successful, ThoughtSpot returns a list of active Orgs for the specified user GUID: + +[source,JSON] +---- +{ + "orgs": [ + { + "orgId": 255226812, + "orgName": "Primary", + "description": "Primary Org", + "isActive": true + } + ], + "canAdministerAllOrgs": false, + "currentOrgId": 255226812 +} +---- + +=== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**204** | Successful operation +|**400**| Invalid parameter +|**403**| Unauthorized request +|=== + +[#set-home-liveboard] +== Set a home Liveboard +To set a Liveboard as a home Liveboard for a user account, send a `POST` request to the `/tspublic/v1/session/homepinboard` API endpoint. If a home Liveboard is configured for a user account, ThoughtSpot displays it as the default home page when the user logs in. + +=== Resource URL +---- +POST /tspublic/v1/session/homepinboard +---- +=== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Form parameter|Description +|`id`|__String__. GUID of the Liveboard to be set as a home Liveboard. +|`userid` __Optional__|__String__. GUID of the user account for which you want to set the home Liveboard. If the `userid` attribute is not defined, ThoughtSpot sets the home Liveboard of the currently logged-in user. +|=== +=== Example request + +.cURL +[source, cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'id=7a9a6715-e154-431b-baaf-7b58246c13dd&userid=59481331-ee53-42be-a548-bd87be6ddd4a' \ 'https:///callosum/v1/tspublic/v1/session/homepinboard' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/session/homepinboard +---- + +=== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**204**|The specified Liveboard is set as a home Liveboard. +|**403**|The Liveboard with the given ID is not accessible. +|**401**|Unauthorized request or invalid token. +|**404**|The specified Liveboard was not found. +|=== + +[#get-home-liveboard] +== Get details of the home Liveboard + +To get the GUID of Liveboard that is currently set as a `home Liveboard`, send a `GET` request to the `/tspublic/v1/session/homepinboard` API endpoint. + +=== Resource URL +---- +GET /tspublic/v1/session/homepinboard +---- + +=== Example request + +.cURL +[source, cURL] +---- +curl -X GET \ +--header 'Accept: text/plain' \ +--header 'X-Requested-By: ThoughtSpot' 'https:///callosum/v1/tspublic/v1/session/homepinboard' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/session/homepinboard +---- + +=== Example response +If the home Liveboard is set in the currently logged-in user's account, the API returns the GUID of the Liveboard set as a home Liveboard: + +---- +7a9a6715-e154-431b-baaf-7b58246c13dd +---- + +=== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**200**|Successful operation. +|=== + +[#del-home-liveboard] +== Remove a home Liveboard +To remove the home Liveboard setting from the currently logged-in user's account, send a `DELETE` request to the `/tspublic/v1/session/homepinboard` API endpoint. + +=== Resource URL +---- +DELETE /tspublic/v1/session/homepinboard +---- + +=== Example request + +.cURL +[source, cURL] +---- +curl -X DELETE \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/session/homepinboard' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/session/homepinboard +---- + +=== Example response +If the home Liveboard is set in the currently logged-in user's account, the API returns the following response: + +---- +Response Code +200 +---- +=== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**200**|Successful operation. +|=== diff --git a/docs/src/asciidocs/spotdev-portal.adoc b/docs/src/asciidocs/spotdev-portal.adoc new file mode 100644 index 000000000..81bfc50dc --- /dev/null +++ b/docs/src/asciidocs/spotdev-portal.adoc @@ -0,0 +1,101 @@ += ThoughtSpot Developer portal +:toc: true + +:page-title: ThoughtSpot Developer Portal +:page-pageid: spotdev-portal +:page-description: Using ThoughtSpot Developer Portal + +ThoughtSpot Developer portal lets you explore the Visual Embed SDK, REST API SDK and preview the coding experience in Playground. + +The portal also allows authorized you to customize and rebrand the look and feel of the UI, create custom actions, and configure security and authentication settings. + +If you are an existing ThoughtSpot user:: +You can access the Developer portal from your ThoughtSpot application instance. +. Log in to ThoughtSpot. +. Navigate to the **Develop** tab. ++ +The *Develop* tab is available only if your user account has developer or administrator privilege. For more information about configuring developer privilege, see the xref:user-roles.adoc[Developer access]. + +If you are not an existing ThoughtSpot user:: +If you do not have a ThoughtSpot user account and you want to evaluate the APIs in the developer playground: +. Go to link:https://developers.thoughtspot.com/[developers.thoughtspot.com, window=_blank]. +. From the header bar, click *Playground*. + +[NOTE] +==== +You can also link:https://www.thoughtspot.com/trial?tsref=trialtsefaq[register for a free trial, window=_blank] and evaluate the SDK and APIs on ThoughtSpot free trial cluster. +==== + +== Find your way around + +The ThoughtSpot Developer portal includes several sections that assist you through your embedding journey. + +Home:: +The *Home* page of the Developer portal provides a pictorial view of ThoughtSpot features that you can integrate with your applications. +This page also includes links to the *Developer Guides* and *Playground*. + ++ +[.bordered] +image::./images/develop-home.png[Developer Portal] + + +Visual Embed SDK:: + +Includes the following menu items: + +Guide;; +Opens the Visual Embed documentation page. + +Playground;; +The Visual Embed SDK *Playground* allows you to explore the following Visual Embed components: +* xref:developer-playground.adoc#playground-search[Search] +* xref:developer-playground.adoc#playground-liveboard[Liveboards] +* xref:developer-playground.adoc#playground-visualization[Visualizations] +* xref:developer-playground.adoc#playground-fullapp[Full application] + ++ +++++ +Visit the Playground +++++ + +REST API:: +Includes the following menu items: + +Guide;; +Opens the REST API documentation. + +REST Playground v1;; +Opens the REST API v1 Explorer page. This page allows you to make API calls to the REST API v1 endpoints through the Swagger UI. ++ +++++ +Try it out +++++ + +REST Playground v2.0;; +Opens the REST API v2.0 Playground, which allows you to view the v2.0 endpoints, make API calls, and explore the request and response workflows. ++ +++++ +Try it out +++++ + +Customizations:: +The Developer portal displays the following customization options for Thoughtspot embedded instances: + +* *Styles* ++ +Provides a set of style customization controls to rebrand the look and feel of the ThoughtSpot UI and its elements. ++ +For more information, see xref:customize-style.adoc[Customize styles]. + +* *Custom actions* ++ +Provides UI workflows to create custom actions in the ThoughtSpot UI. For example, you can create an action that triggers a callback to your host application, or invoke a URL to send ThoughtSpot data. For more information, see xref:custom-actions.adoc[Custom actions]. + +* *Security settings* ++ + +Provides security controls to add third-party domains as xref:security-settings.adoc[trusted hosts for CORS and CSP]. The *Security settings* page also allows you to xref:trusted-authentication.adoc[enable trusted authentication] and xref:configure-saml.adoc[add a SAML redirect domain] to the allowed list of domains. + +* *Links settings* ++ +Allows you to customize the format of system-generated links. For more information, see xref:customize-links.adoc[Customize links]. diff --git a/docs/src/asciidocs/style-customization.adoc b/docs/src/asciidocs/style-customization.adoc new file mode 100644 index 000000000..c04e44b80 --- /dev/null +++ b/docs/src/asciidocs/style-customization.adoc @@ -0,0 +1,79 @@ += Customize styles and layout +:toc: true +:toclevels: 1 + +:page-title: Customize styles and layout +:page-pageid: style-customization +:page-description: Customize styles, design, and layout of embedded ThoughtSpot app using UI and custom CSS + +ThoughtSpot allows you to customize the look and feel of embedded pages and elements to match the UI style and design of your host application and the branding guidelines of your organization. Developers can use the following options to customize the appearance of embedded content and create a uniform experience for the users of their app. + +Style customization features in the ThoughtSpot UI:: + +You can customize key UI components, such as your application logo, favicon, font style for charts and tables, background color of the UI, background color of the top navigation panel, the color palette for your charts, page title, and footer text by either using the *Style customization* menu in the *Admin* tab or navigating to *Develop* > *Customizations* > *Styles*. To learn how to use these controls, see xref:customize-style.adoc[Customize layout and styles]. + +Advanced style customization with custom CSS:: +Custom CSS allows developers to override the default styles and UI element specifications in their deployments. Custom CSS provides granular control over the UI appearance and allows you to modify design elements such as buttons, labels, text styles, and typography. This feature is available only with the ThoughtSpot Everywhere Edition license. ++ +To customize themes and variables in the CSS file, developers must know the basics of HTML and CSS framework and how to build custom themes. For more information, see xref:css-customization.adoc[Advanced customization with custom CSS]. ++ + +[IMPORTANT] +==== +If you apply customization changes both via UI and custom CSS, the custom CSS changes take precedence and override the style customization settings in the UI. +==== + +== Scope of customization + +The following table lists the customizable elements: + +[div tableContainer] +-- +[width="100%" cols="4,5,5"] +[options='header'] +|===== +|UI element|Customization via UI| Customization with CSS +|Application-wide settings| [tag greenBackground]#✓# Background color application pages + + +[tag greenBackground]#✓# Navigation panel color+ + +[tag greenBackground]#✓# Logo + + +[tag greenBackground]#✓# Favicon | [tag greenBackground]#✓# Background color of Liveboard, visualization, and Answer pages + + +[tag greenBackground]#✓# Navigation panel and its contents + + +|Typography|[tag greenBackground]#✓# Font styles for charts and tables + + +[tag greenBackground]#✓# Page title + + +[tag greenBackground]#✓# Footer text + +| [tag greenBackground]#✓# Font styles, text color, and text-transform settings for the entire app + + +|Charts and visualizations| [tag greenBackground]#✓# Color palette of charts and tables | + +[tag greenBackground]#✓# Font styles, text color, and text-transform settings for visualization and Answer titles, description text, and axis labels and titles on charts + + +[tag greenBackground]#✓# Visualization tile customization; for example, border-radius and background color. + + +|Buttons elements|[tag greyBackground]#–# |[tag greenBackground]#✓# Color and border-radius of primary, secondary, and tertiary buttons +|Search bar|[tag greyBackground]#–# a|[tag greenBackground]#✓# Search text and tokens in the Search bar + +[tag greenBackground]#✓# Buttons on the search bar + + +* The *Go* button (primary button) +* Background color of the secondary button; for example, the delete icon (image:./images/icon-search-bar-close.png[]) that appears after you enter the search tokens. +|Menu components|[tag greyBackground]#–# |[tag greenBackground]#✓# Background color and text style of menu panels. +|===== +-- + +== Custom styles for Orgs on multi-tenant clusters + +You can now apply custom styles for each Org on a multi-tenant ThoughtSpot cluster. To enable this feature in your instance, contact ThoughtSpot Support. + +If per-Org customization is enabled on your instance, you can apply xref:customize-style.adoc[basic style changes on the *Develop* > *Customizations* > *Styles* page]. However, xref:css-customization.adoc[advanced style customization with custom CSS and style overrides] is not supported at the Org level. + +[NOTE] +==== +The styles applied at the Org level take precedence over style settings at the cluster (All Orgs) level. +==== \ No newline at end of file diff --git a/docs/src/asciidocs/terminology-update.adoc b/docs/src/asciidocs/terminology-update.adoc new file mode 100644 index 000000000..e0303b7b2 --- /dev/null +++ b/docs/src/asciidocs/terminology-update.adoc @@ -0,0 +1,77 @@ += Terminology changes +:toc: true + +:page-title: Terminology changes +:page-pageid: terminology +:page-description: Read through this article to know the terminology changes. + +Starting from the ThoughtSpot 8 Cloud November release, the term *Pinboard* will appear as **Liveboard** in ThoughtSpot application UI and websites. As part of rebranding, the `pinboard` terminology in ThoughtSpot application and other related interfaces has been updated. For example, the *pinboard* instances in the ThoughtSpot UI and Visual Embed SDK libraries now show as `Liveboard`. + +[IMPORTANT] +==== +We are in the process of rolling out terminology changes across all ThoughtSpot interfaces, platforms, websites, and information artifacts. During this period, your environment may show some instances of `pinboard` based on the rebranding rollout stage. For detailed information about the impacted interfaces and the terminology changes, see the following sections. +==== + +== Terminology changes in the UI + +[width="100%" cols="5,^3,^2"] +[options='header'] +|==== +|Feature location/Text occurrence| Legacy terminology |New terminology +|Primary navigation bar|Pinboards|Liveboards +|Liveboard pages|Pinboard|Liveboard +|Field description and tooltips|Pinboard + +pinboard|Liveboard +|User-defined titles and description|Pinboard + +pinboard|No change +|Develop tab|Pinboard |Liveboard +|Developer playground|Pinboard|Liveboard +|Code samples in Playground |Pinboard + +pinboard| Liveboard. For more information, see xref:terminology-update.adoc#sdk-changes[Terminology changes in the Visual Embed SDK]. +|Embedded ThoughtSpot UI| Pinboard| Liveboard +|==== + +[#sdk-changes] +== Terminology changes in the Visual Embed SDK Version 1.6.0 and later + +[width="100%" cols="5,^3,^3"] +[options='header'] +|==== +|Location| Legacy terminology |New terminology +|SDK package for Liveboard embedding|`PinboardEmbed`|`LiveboardEmbed` +|Liveboard object configuration|`PinboardEmbedViewConfig` + +`pinboardID` + +`preventPinboardFilterRemoval` +| +`LiveboardViewConfig` + +`liveboardID` + +`preventLiveboardFilterRemoval` + +|Page properties (full app embedding) +|`page.Pinboards`|`page.Liveboards` +|Action enumeration| `PinboardInfo` + +|`LiveboardInfo` + +|Object references in embed data structure|`pinboard`| No change +|==== + +== Application components and interfaces with legacy terminology + +To ensure that existing customizations and integrations work seamlessly, the following application components and interfaces will continue to use the legacy terminology: + +* REST API endpoint URLs +* Metadata object headers and dependent object references ++ +For example, `PINBOARD_ANSWER_BOOK` is a valid metadata object `type` that represents a Liveboard object. +* Query, path, and formData parameters in REST APIs +* Attribute values, object properties, and API responses +* Pinboard URLs in the application UI and system-generated links +* Object references in TML files diff --git a/docs/src/asciidocs/tml-api.adoc b/docs/src/asciidocs/tml-api.adoc new file mode 100644 index 000000000..03d7409d7 --- /dev/null +++ b/docs/src/asciidocs/tml-api.adoc @@ -0,0 +1,306 @@ += TML API +:toc: true +:toclevels: 1 + +:page-title: TML Export and Import API +:page-pageid: tml-api +:page-description: The TML API endpoints allow you to export and import TML files + +The TML API endpoints allow you to programmatically export, validate, and import scriptable link:https://cloud-docs.thoughtspot.com/admin/ts-cloud/tml.html[ThoughtSpot Modeling Language (TML), window=_blank] files. You can use these API endpoints to automate the change management and deployment processes between your development and production environments. With TML API, you can easily migrate your ThoughtSpot content from one environment to another by automating the entire change management process and thereby reducing the risk of human error. + +[NOTE] +==== +Starting with version 8.9.0.cl, ThoughtSpot exports TML files with `liveboard` as the object name instead of `pinboard`. Older TML files with the `pinboard` object name can still be imported into ThoughtSpot instances on 8.9.0.cl release version, but it will be replaced with `liveboard` during TML export. Importing a TML file generated from ThoughtSpot 8.9.0.cl into 8.8.0.cl or earlier versions is not supported if the object name is set to `liveboard`. To resolve this issue, replace `liveboard` with `pinboard` and then try to import it into earlier versions. +==== + +== Supported operations + +include::{path}/tml-api-list.adoc[] + +== Required permissions + +You must have at least view access to the objects to export the TML data. To import a modified TML object, your account must have the `DATAMANAGEMENT` privilege. + +[#import] +== Import TML +To import TML representation of objects into ThoughtSpot, use the `/tspublic/v1/metadata/tml/import` API endpoint. + +The import TML API endpoint allows you to upload multiple TML files at a time. If you are importing TML files one at a time, include the `fqn` property to distinguish objects that have the same name. For example, if you have multiple connections or tables with the same name, the connection or table you reference in your TML does not have a unique name and thus can lead to invalid object references. Adding `fqn` helps ThoughtSpot differentiate a table from another with the same name. + +By default, the `fqn` parameter is not present in the TML file. However, you can export TML with FQNs and use it during the import. + +[NOTE] +==== +You can import single or multiple objects using the `tml/import` API. If you import only a Worksheet object, it may take some time for the Worksheet to become available in the ThoughtSpot system. You may need to wait for a few seconds to create answers and Liveboards. + +However, if you import a Worksheet along with Liveboards, answers, and other dependent objects in a single API call, the imported objects will be immediately available for use. +==== + +=== Resource URL +---- +POST /tspublic/v1/metadata/tml/import +---- + +=== Request parameters +[width="100%" cols="2,4,1"] +[options='header'] +|==== +|Form parameter|Description|Default +|`import_objects` a|__String__. An `x-www-form-urlencoded` string containing a JSON array of TML objects to upload, in YAML or JSON format. + +If in YAML format within the JSON array, use escape characters for YAML quotes, and new line characters when there is a new line. + +For example: + +* To import a single object, `["guid: 3729c085-8659-48fd-9479-a67bd7307496\npinboard:\n name: …"]` +* To import multiple objects, `["guid: 3729c085-8659-48fd-9479-a67bd7307496\npinboard:\n name: …“, "guid: 5739d025-8659-48fd-9479-a67bd7704212\npinboard:\n name: …”]` +|None +|`import_policy` a|__String__. Policy to follow during import. The allowed values are: + +* `PARTIAL` +Imports all objects that validate successfully, and ignores objects that do not validate successfully. +* `ALL_OR_NONE` +Imports the objects that validate successfully. +* `VALIDATE_ONLY` +Validates the objects but does not import them.|`PARTIAL` + +a| +`force_create` a| __Boolean__. Specifies if you are updating or creating objects. To create new objects, specify `true`. + +By default, ThoughtSpot updates existing objects that have the same GUID as the objects you are importing. When set to `true`, the `guid` property in the imported TML is replaced with a new GUID if the GUID is being used by another object on the server. + +If the imported TML file includes a `guid` that is not used by any other object, ThoughtSpot creates a new object with the same `guid` from the imported TML file. + +To know GUID assigned to the new object created from TML import, check the `id_guid` property in the response headers. + +|`false`| +|==== + +=== Example request + +Make sure the API request has the following headers: + +* The `Accept` header is set as `Accept: text/plain` +* The `X-requested-by` header set as `X-Requested-By: ThoughtSpot` + +.cURL +[source,cURL] +---- +curl -X POST --header 'Accept: text/plain' --header 'X-Requested-By: ThoughtSpot' --data-urlencode 'import_objects=[{ + "guid": "12289fad-f230-485e-8c65-e36082eebf44", + "answer": { + "name": "Basic Answer 1", + "description": "This is basic answer with table and headline visualizations.", + "tables": [{ + "id": "LINEORDER", + "name": "LINEORDER", + "fqn": "2445fe81-30d6-46fa-9f42-f6b1b4e01623" + }, { + "id": "PART", + "name": "PART", + "fqn": "a7fc012e-bdb3-4e75-9ce4-b3f731d90136" + }], + "search_query": "[LINEORDER_1::Revenue] [PART_1::Color]", + "answer_columns": [{ + "name": "Total Revenue" + }, { + "name": "Color" + }], + "table": { + "table_columns": [{ + "column_id": "Color", + "headline_aggregation": "COUNT_DISTINCT" + }, { + "column_id": "Total Revenue", + "headline_aggregation": "SUM" + }], + "ordered_column_ids": ["Color", "Total Revenue"] + }, + "chart": { + "type": "COLUMN", + "chart_columns": [{ + "column_id": "Total Revenue" + }, { + "column_id": "Color" + }], + "axis_configs": [{ + "x": ["Color"], + "y": ["Total Revenue"] + }] + }, + "display_mode": "TABLE_MODE" + } +}]' +--data-urlencode 'import_policy=PARTIAL' +--data-urlencode 'force_create=true' +'http://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/metadata/tml/import' + +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/metadata/tml/import +---- + +=== Example response + +[source,JSON] +---- +{ + "object": [ + { + "response": { + "status": { + "status_code": "OK" + }, + "header": { + "id_guid": "a09a3787-e546-42cb-888f-c17260dd1229", + "name": "Basic Answer 1", + "description": "This is basic answer with table and headline visualizations.", + "author_guid": "59481331-ee53-42be-a548-bd87be6ddd4a", + "owner_guid": "a09a3787-e546-42cb-888f-c17260dd1229", + "metadata_type": "QUESTION_ANSWER_BOOK" + } + } + } + ] +} +---- + +=== Response codes + +[width="100%" cols="1,3"] +[options='header'] +|=== +|HTTP status code | Description + +| **200** +| Successful import of the TML object representations + +| **400** +| Bad request + +| **401** +| Unauthorized or wrong credentials + +| **403** +| Forbidden - incorrect permissions + +| **404** +| Not found + +| **500** +| Internal server error +|=== + +[#export] +== Export TML + +To export TML objects, use the `/tspublic/v1/metadata/tml/export` API endpoint. + +=== Resource URL +---- +POST /tspublic/v1/metadata/tml/export +---- + +=== Request parameters + +[width="100%" cols="3,6,1"] +[options='header'] +|====== +|Form parameter|Description|Default +|`export_ids` a|__String__. JSON array of the IDs of objects to export. An `x-www-form-urlencoded` string containing a JSON array of ids of objects to export. You receive results in the order you request them. + +For example: + +* To export a single object, `["226abd2843-afef-4c2f-bf2f-8fba065330e"]` +* To export multiple objects, `["226abd2843-afef-4c2f-bf2f-8fba065330e", ”22d305bc51-688b-414f-badc-94579d48308c”]` | None + +|`formattype`|__String__. The format in which to export the objects. Valid values are `JSON` and `YAML`. | `YAML` +|`export_associated`|__Boolean__. Specifies if you would like to export the associated objects. To export the objects associated with the objects specified in `export_ids`, set the value to `true`. When set to `true`, the API exports any underlying worksheets, tables, or views for a given object. By default, the API does not export these underlying objects.| `false` +a|`export_fqn` a|__Boolean__. When set to `true`, the API exports the FQNs of the referenced objects in the TML data. For example, if you are exporting a Liveboard and its associated objects, the API returns the Liveboard TML data with the FQNs of the referenced Worksheet. + +Note that the FQN of a referenced object is the same as the GUID of that object. + + +ThoughtSpot recommends adding the `fqn` property before importing the TML objects into the system, because only the name of a referenced object is not sufficient to identify the referenced object during TML import. For example, if your ThoughtSpot instance has two worksheets with the same name, the TML import for a Liveboard that uses one of these worksheets would fail unless the Liveboard TML includes the FQN of the referenced Worksheet. + + +The `export_fqn` attribute is useful when ThoughtSpot has multiple objects with the same name and you want to eliminate ambiguity during TML import. The `export_fqn=true` property adds the FQNs of the referenced objects in the TML export API response and saves the manual effort of adding FQNs for TML import. + +[NOTE] +==== +When you try to xref:tml-api.adoc#import[import] multiple objects in bulk and create objects using the `force_create` attribute, the new object may refer to an existing object with the same FQN in the ThoughtSpot system instead of the other objects provided in the TML import request. For example, when you upload a TML representation of a Liveboard and the associated Worksheet with the FQNs obtained from the TML export API, the imported Liveboard may refer to an existing Worksheet with the same FQN in the ThoughtSpot system instead of the new Worksheet created during the TML import. + +If you want the new objects created during the TML import to refer to the other associated objects created during the same import operation, set the `export_fqn` attribute to `false` during TML export or remove the FQNs manually before the TML import. +==== +|`false` +|====== + +=== Example request + +Make sure the API request has the following headers: + +* The `Accept` header is set as `Accept: text/plain` +* The `X-requested-by` header must be `X-Requested-By: ThoughtSpot` + +.cURL + +[source,curl] +---- +curl -X POST +--header 'Accept: text/plain' \ +--header 'X-Requested-By: ThoughtSpot' \ +--data-urlencode 'export_ids=["12289fad-f230-485e-8c65-e36082eebf44"]' \ +--data-urlencode 'formattype=JSON' \ +--data-urlencode 'export_associated=false' \ +--data-urlencode 'export_fqn=true' \ +'http://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/metadata/tml/export' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/metadata/tml/export +---- + +=== Example response + +[source,JSON] +---- +{ + "object":[ + { + "info":{ + "name":"Total sales", + "filename":"Total sales.pinboard.tml", + "status":{ + "status_code":"OK" + }, + "type":"pinboard", + "id":"bf3b1f36-b96e-4aa7-b619-b7743c8bd15c" + }, + "edoc":"{\"guid\": \"bf3b1f36-b96e-4aa7-b619-b7743c8bd15c\",\"liveboard\": {\"name\": \"Total sales\",\"visualizations\": [{\"id\": \"Viz_1\",\"answer\": {\"name\": \"Total sales by store\",\"tables\": [{\"id\": \"(Sample) Retail - Apparel\",\"name\": \"(Sample) Retail - Apparel\",\"fqn\": \"cd252e5c-b552-49a8-821d-3eadaa049cca\"}],\"search_query\": \"[sales] [store] [state]\",\"answer_columns\": [{\"name\": \"state\"},{\"name\": \"store\"},{\"name\": \"Total sales\"}],\"table\": {\"table_columns\": [{\"column_id\": \"store\",\"show_headline\": false},{\"column_id\": \"state\",\"show_headline\": false},{\"column_id\": \"Total sales\",\"show_headline\": false}],\"ordered_column_ids\": [\"store\",\"state\",\"Total sales\"],\"client_state\": \"\",\"client_state_v2\": \"{\\\"tableVizPropVersion\\\": \\\"V1\\\"}\"},\"chart\": {\"type\": \"GEO_AREA\",\"chart_columns\": [{\"column_id\": \"store\"},{\"column_id\": \"state\"},{\"column_id\": \"Total sales\"}],\"axis_configs\": [{\"x\": [\"state\"],\"y\": [\"Total sales\"]}],\"client_state\": \"\",\"client_state_v2\": \"{\\\"version\\\": \\\"V4DOT2\\\",\\\"chartProperties\\\": {\\\"mapviewport\\\": {\\\"center\\\": [-1.0815372462017208E7,4944187.994859374],\\\"zoomLevel\\\": 5.140063818579165},\\\"responsiveLayoutPreference\\\": \\\"AUTO_ON\\\",\\\"chartSpecific\\\": {}},\\\"axisProperties\\\": [{\\\"id\\\": \\\"be5fe824-1a94-4fc4-88f6-501198708122\\\",\\\"properties\\\": {\\\"axisType\\\": \\\"Y\\\",\\\"linkedColumns\\\": [\\\"Total sales\\\"],\\\"isOpposite\\\": false}},{\\\"id\\\": \\\"474621ab-c78c-496f-aa71-8de82a5a1af4\\\",\\\"properties\\\": {\\\"axisType\\\": \\\"X\\\",\\\"linkedColumns\\\": [\\\"state\\\"]}}],\\\"systemSeriesColors\\\": [{\\\"serieName\\\": \\\"Total sales\\\",\\\"color\\\": \\\"#48D1E0\\\"}],\\\"systemMultiColorSeriesColors\\\": [{\\\"serieName\\\": \\\"Total sales\\\",\\\"colorMap\\\": [{\\\"serieName\\\": \\\"state\\\",\\\"color\\\": [\\\"#ffffb2\\\",\\\"#fddd87\\\",\\\"#fba35d\\\",\\\"#f75534\\\",\\\"#f9140a\\\",\\\"#d70315\\\",\\\"#b10026\\\"]}]}]}\"},\"display_mode\": \"CHART_MODE\"}},{\"id\": \"Viz_2\",\"answer\": {\"name\": \"Total sales by store\",\"tables\": [{\"id\": \"(Sample) Retail - Apparel\",\"name\": \"(Sample) Retail - Apparel\",\"fqn\": \"cd252e5c-b552-49a8-821d-3eadaa049cca\"}],\"search_query\": \"[sales] [store] [quantity purchased]\",\"answer_columns\": [{\"name\": \"store\"},{\"name\": \"Total quantity purchased\"},{\"name\": \"Total sales\"}],\"table\": {\"table_columns\": [{\"column_id\": \"store\",\"show_headline\": false},{\"column_id\": \"Total sales\",\"show_headline\": false},{\"column_id\": \"Total quantity purchased\",\"show_headline\": false}],\"ordered_column_ids\": [\"store\",\"Total sales\",\"Total quantity purchased\"],\"client_state\": \"\",\"client_state_v2\": \"{\\\"tableVizPropVersion\\\": \\\"V1\\\"}\"},\"chart\": {\"type\": \"COLUMN\",\"chart_columns\": [{\"column_id\": \"store\"},{\"column_id\": \"Total sales\"},{\"column_id\": \"Total quantity purchased\"}],\"axis_configs\": [{\"x\": [\"store\"],\"y\": [\"Total sales\",\"Total quantity purchased\"]}],\"client_state\": \"\",\"client_state_v2\": \"{\\\"version\\\": \\\"V4DOT2\\\",\\\"chartProperties\\\": {\\\"responsiveLayoutPreference\\\": \\\"AUTO_ON\\\",\\\"chartSpecific\\\": {}},\\\"axisProperties\\\": [{\\\"id\\\": \\\"6cac31dc-bf75-4e9e-ab96-422053d913cd\\\",\\\"properties\\\": {\\\"axisType\\\": \\\"Y\\\",\\\"linkedColumns\\\": [\\\"Total sales\\\"],\\\"isOpposite\\\": false}},{\\\"id\\\": \\\"5f5971ce-7e5f-48a0-9ba4-2c376699f64c\\\",\\\"properties\\\": {\\\"axisType\\\": \\\"Y\\\",\\\"linkedColumns\\\": [\\\"Total quantity purchased\\\"],\\\"isOpposite\\\": true}},{\\\"id\\\": \\\"23799dc2-3d6c-4da1-9d1b-e1dba0e5cc00\\\",\\\"properties\\\": {\\\"axisType\\\": \\\"X\\\",\\\"linkedColumns\\\": [\\\"store\\\"]}}],\\\"systemSeriesColors\\\": [{\\\"serieName\\\": \\\"Total sales\\\",\\\"color\\\": \\\"#48D1E0\\\"},{\\\"serieName\\\": \\\"Total quantity purchased\\\",\\\"color\\\": \\\"#2E75F0\\\"}],\\\"systemMultiColorSeriesColors\\\": [{\\\"serieName\\\": \\\"Total sales\\\",\\\"colorMap\\\": [{\\\"serieName\\\": \\\"a3882487-1509-4b13-8430-2e91d511a865\\\",\\\"color\\\": [\\\"#ffffb2\\\",\\\"#fddd87\\\",\\\"#fba35d\\\",\\\"#f75534\\\",\\\"#f9140a\\\",\\\"#d70315\\\",\\\"#b10026\\\"]}]}]}\"},\"display_mode\": \"CHART_MODE\"}}]}}" + } + ] +} +---- + +=== Response codes + +[width="100%" cols="1,5"] +[options='header'] +|=== +|HTTP status code| Description + +| **200** +| Successful TML export operation + +| **400** +| Bad request + +| **401** +| Unauthorized - wrong credentials + +| **403** +| Forbidden - incorrect permissions + +| **404** +| Not found + +| **500** +| Internal server error +|=== diff --git a/docs/src/asciidocs/troubleshooting.adoc b/docs/src/asciidocs/troubleshooting.adoc new file mode 100644 index 000000000..b3c2ce8e4 --- /dev/null +++ b/docs/src/asciidocs/troubleshooting.adoc @@ -0,0 +1,166 @@ += Troubleshoot errors +:toc: true +:toclevels: 1 + +:page-title: Troubleshooting +:page-pageid: troubleshoot-errors +:page-description: Troubleshoot common issues with embedding + +This article helps you to troubleshoot the common problems that you might encounter when setting up or using an embedded ThoughtSpot instance. For additional help and guidance from ThoughtSpot Support, visit our link:https://community.thoughtspot.com/customers/s/topic/0TO3n000000erVyGAI/developers?tabset-80a3b=2[Community site, window=_blank]. + +== CORS and CSP + +=== Refused to frame ""... error message + +**Error**: When I try to embed in my app, I get the error `Refused to frame "" because an ancestor violates the following Content Security Policy directive`. + + +**Cause**: This error occurs when a host app domain is not added to the CSP and CORS allowlists. + + +**How to fix**: xref:security-settings.adoc[Add your host app domain as a CSP visual embed host] and xref:security-settings.adoc[enable CORS] on the *Develop* > *Customizations* > *Security Settings* page. + +=== The CORS allowlist does not allow wildcard (*) for domain URL + +**Error**: The CORS allowlist does not allow wildcard(*) expression for domain URLs. + + +**Cause**: This error occurs because ThoughtSpot does not support wildcard expression for domain URLs in the CORS allowlist. + + +**How to fix**: Specify the domain URL string in the supported format. For a complete list of allowed domain URL strings for CORS and CSP allowlists, see xref:security-settings.adoc#csp-cors-hosts[Security settings]. + +== Browser support + +=== Cannot open my embedded app in Safari + +**Error**: Unable to access the embedded app on Safari + + +**Cause**: This error may occur if third-party cookies are blocked. + + +**How to fix**: By default, Safari does not allow third-party cookies. + +If the third-party cookies are blocked, the SDK triggers the `NoCookieAccess` event. Check the console log. + +To resolve this issue: + + +* Allow cookies on Safari to view the embedded app. + +* To ensure that embedding works on browsers that block third-party cookies, you can set the domain name of your ThoughtSpot instance to the same domain as your host application. If you want to customize the domain name, contact ThoughtSpot Support. + +== Authentication + +=== Account locked + +**Error**: My account is locked and I am unable to log in to the app with my SSO credentials. + + +**Cause**: Are you using token-based authentication? In a token-based authentication deployment, this error may occur if a user's login token has expired. If a user makes multiple attempts to log in to ThoughtSpot using an invalid or expired token, they may get locked out of their accounts. + + +**How to fix**: Set the `getAuthToken` function in the SDK to return a fresh token for each re-login. + +=== The login page shows up each time a user session expires + +**Error**: The embedded UI prompts me to re-login after a session timeout. + + +**Cause**: This error may occur if `autoLogin` is disabled in the SDK. + +**How to fix**: If you are using the token-based authentication method, the SDK automatically logs in users after their user session has expired. Make sure the `autoLogin` attribute is set to `true` in the SDK. + +=== The login prompt shows up for authenticated users + +**Error**: I have logged in to my application instance, but the login page shows up when I try to access the developer Playground. + +**Cause**: This error may occur if session cookies are not enabled on your web browser. + +**How to fix**: Check if third-party cookies are enabled on your web browser. Browsers such as Safari block third-party cookies by default. If you are accessing your application on Chrome in incognito mode, allow third-party cookies. + +=== The login token request returns the 500 response code + +**Error**: ThoughtSpot returns the `500` error code for a session login token request. + + +**Cause**: This error may occur due to an invalid `username` or `secret_key`. + + +**How to fix**: Check if the `username` sent in the API request matches the name of the user in ThoughtSpot. + +Check if trusted authentication is enabled on ThoughtSpot. Make sure the `secrete_key` being sent in your API request is valid. + +For more information, see xref:trusted-authentication.adoc[Trusted authentication]. + +=== SAML SSO authentication errors + +In most cases, SAML authentication errors occur due to incorrect IdP settings and invalid SAML authentication attributes. To resolve these issues: + +* Make sure xref:configure-saml.adoc#_configuration_steps[SAML authentication support is configured, window=_blank] without errors on your ThoughtSpot instance. +* Check if the attributes, such as a user’s email address, display name, and username are mapped correctly in your IdP configuration. For example, if you are using Okta as your IdP, you must map the `userPrincipalName` in Okta to `NameId`. Similarly, you can map the email attribute value to `mail`, and the display name subject value to `displayName`. +* Make sure your SAML redirect domain is xref:configure-saml.adoc#saml-redirect[added to the allowlist]. +* Check if the `authType` property and SAML authentication attributes in the SDK are configured correctly. + * For SAML authentication, you must set the `authType` as `AuthType.SSO`. + ++ +If you are using Visual Embed SDK version 1.17.0 or later, you can set `authType` as `AuthType.SAMLRedirect`. + * You can also set redirection parameters in the SDK to handle SAML redirect scenarios. For more information, see xref:embed-authentication.adoc#_saml_redirection[SAML redirection]. +* If embedding ThoughtSpot objects in an iFrame, xref:configure-saml.adoc#_configure_idp_to_allow_iframe_embedding[configure your IdP to allow iframe embedding]. + +== Custom actions + +=== URL custom actions don't work on my app + +**Error**: When I click the URL action, ThoughtSpot UI displays the **URL action failed** error message. + + +**Cause**: This error occurs when the target URL of the URL action is not allowed to establish connections due to CSP restrictions. + + +**How to fix**: Check the target domain name configured in the URL action. Make sure it's reachable. + +Check with your administrator to know if the target URL is added to the CSP connect-src domain allowlist. If you have administrator access, you can update the CSP allowlist on the *Develop* > *Customizations* > *Security Settings* page. + + +== Embedding + +=== Liveboard filters do not work + +**Error**: When I open Liveboard filters, they are grayed out and I can’t edit them. + + +**Cause**: This issue may occur if you do not have edit access to the Liveboard or at least view access to its underlying data. + + +**How to fix**: Check if you have edit access to the Liveboard and can view its data source. If you do not have edit access to the Liveboard, click the lock icon and request access from the Liveboard owner. + + +=== I set a Runtime filter on a Liveboard, but I don’t see it on the Liveboard + +Runtime filters are applied at runtime and do not show up in the Filter bar. + +Runtime filters are applied separately from the visible Liveboard filters. Therefore, when you apply these filters together, the conditions for both must be true for data to appear. + + +For example, if `Store Region` is set to `west, southwest` in the Liveboard filter, and you set runtime filter of `Store Region` as `east`, you will get the *No data found* error because the total filter condition is `Store Region IN ('west', 'southwest') AND Store Region = 'east'`, which results in an error. + +=== ThoughtSpot navigation bar shows in the embedded mode + +**Error**: When I embed the full ThoughtSpot application in my app, the top navigation bar shows up. + +**Cause**: This issue occurs if you have enabled the `showPrimaryNavbar` property in the SDK. + +**How to fix**: Set the `showPrimaryNavbar` attribute in the Visual Embed SDK to `false`. + + +== REST API + +=== My API request returns the 401 error code + +**Error**: When I send an API request, the ThoughtSpot server returns the 401 error code in response. + +**Cause**: This issue occurs if you do not have the required privileges to create or modify the data objects. + +**How to fix**: Check if your API requests are authorized. Make sure your ThoughtSpot user account has edit privileges to access and modify ThoughtSpot objects. For more information, see xref:feature-matrix-license.adoc#_rest_api_v1_operations[REST API v1 operations] and xref:feature-matrix-license.adoc#_rest_api_v2_0_operations[REST API v2.0 operations]. + + +=== Unable to embed a Liveboard using REST API + +To embed a Liveboard using REST APIs, you must have at least view access to the Liveboard. To modify or enhance the Liveboard, you require edit privileges. + +If you have the required privileges and still get an error, perform the following checks: + +* The Liveboard and visualization GUIDs passed in the API request body are valid. + +* Your application domain is added as a xref:security-settings.adoc#cors-hosts[CORS host]. + +=== The Search Data REST API call returns an error + +**Error**: When I try to use the Search Data REST API, I get the error `Cannot create Answer from empty query`. + + +**How to fix**: Check the request URL and verify the query string. Try removing the `-d [parameters]` option and append the query string to the end of the URL as shown here: + +[source,Javascript] +---- +curl -X POST / +--header 'Content-Type: application/json' / +--header 'Accept: application/json' / +--header 'X-Requested-By: ThoughtSpot' 'https://[address]/callosum/v1/tspublic/v1/searchdata?query_string=%5Brevenue%5D%20by%20%5Bshipmode%5D&data_source_guid=7466f3c5-95a5-44b9-a17d-9cc5fad495ee&batchsize=-1&pagenumber=-1&offset=-1&formattype=COMPACT' +---- diff --git a/docs/src/asciidocs/trusted-authentication.adoc b/docs/src/asciidocs/trusted-authentication.adoc new file mode 100644 index 000000000..e9d2625f6 --- /dev/null +++ b/docs/src/asciidocs/trusted-authentication.adoc @@ -0,0 +1,343 @@ += Trusted authentication +:toc: true +:toclevels: 1 + +:page-title: trusted authentication +:page-pageid: trusted-auth +:page-description: You can configure support for token-based authentication service on ThoughtSpot. + +Trusted authentication defines a method for authenticating users with *login tokens* obtained from ThoughtSpot using REST API. The Trusted authentication mode supports cookie-based and cookieless authentication. In cookie-based authentication, the login token is only necessary during the login process, after which any request to ThoughtSpot will include session cookies that identify the signed-in user. +In cookieless authentication, the bearer token issued by the authentication server is used to authenticate API requests to ThoughtSpot. + +== Overview + +Trusted authentication establishes a ThoughtSpot session in the browser without requiring a user to sign in directly to ThoughtSpot or be redirected to a third-party IdP. It is the most seamless method of single sign-on (SSO) but requires more of the application developer to secure the process. + +The *login token* from the ThoughtSpot v1 REST API is a simple, proprietary token. + +//// +The authentication token of the v2 REST API is not currently used in the trusted authentication flow. +//// + +*Securely requesting the login token* requires passing authentication details from the embedding application securely to an *authenticator service* with access to the `secret_key` for the ThoughtSpot instance and ThoughtSpot admin user's credentials. + +The process for trusted authentication is as follows: + + 1. The Visual Embed SDK, loaded within the embedded application page, calls the `init()` function with the correct set of parameters to request a *login token*. + 2. The request for the *login token* securely provides the username and any additional details to the *authenticator service*. + 3. The *authenticator service* verifies and parses the username and other details, and issues REST API commands to ThoughtSpot, such as requesting a *login token* for the provided username. + 4. The *authenticator service* returns the *login token* to the browser and the Visual Embed SDK. + 5. The Visual Embed SDK issues requests to establish a ThoughtSpot session in the browser. + +The following figure illustrates the trusted authentication workflow with session cookies and REST API calls to v1 endpoints: + +image::./images/trusted-auth-workflow.png[Trusted Authentication Workflow] + +[#trusted-auth-enable] +== Get a secret key for trusted authentication + +To obtain an authentication token for authenticating and logging in a ThoughtSpot user, the `secret_key` is required. To generate a secret key, the ThoughtSpot administrator must enable *Trusted authentication*. + + +[NOTE] +==== +Starting from 9.2.0.cl, Org administrators can generate a unique secret key for respective Orgs. To enable this feature on your cluster, contact ThoughtSpot Support. +==== + +To generate a secret key: + +. Log in to the ThoughtSpot. +. If Orgs are configured on your instance, switch to the Org for which you want to generate a secret key. ++ +If the per-Org secret key feature is not enabled on your instance and if you want to generate a separate secret key for each Org, contact ThoughtSpot Support. ThoughtSpot also allows you to generate a secret key at the primary Org (Org 0) level and use it to obtain an authentication token for a user. +. Go to *Develop* > *Customizations* > *Security settings*. +. Click *Edit*. +. To enable trusted authentication, turn on the *Trusted authentication* toggle. +. To copy the secret key, click *Edit* again, navigate to *Trusted authentication*, and then click the clipboard icon. ++ +The following example shows a ThoughtSpot-generated secret key string. ++ +---- +b0cb26a0-351e-40b4-9e42-00fa2265d50c +---- +This key is required for making API calls to get a token for ThoughtSpot users. + +. Store the key in a secure location. +. Click *Save Changes*. + +[#trusted-auth-sdk] +== Visual Embed SDK / front-end + +The Visual Embed SDK automates the login token request, and the login process using the token obtained from ThoughtSpot. + +The request to the *authenticator service* is defined in the `init()` function of the Visual Embed SDK. When `init()` is called, the SDK checks if there is an existing ThoughtSpot session for the instance in the browser. If not, it will request a *login token* from either the `authEndpoint` URL or the `getAuthToken` callback function. + +You can use cookie-based or cookieless authentication as per your deployment needs. If you are embedding ThoughtSpot content in an app that is not in the same domain as your ThoughtSpot instance, and your web browser blocks third-party cookies, use cookieless authentication. + +For more information, see xref:embed-authentication.adoc#trusted-auth-embed[Embed user authentication page]. + +=== Secure the authentication details request +For the request to the *authenticator service* to be secure, the user in the browser cannot modify the request or make their own valid request to the *authenticator service*. + +How your particular application can most easily securely request the *login token* is up to you, but how you choose to send the message will constrain your choice between `authEndpoint` or `getAuthToken`. + +* If you choose `authEndpoint`, a GET request is made directly to the provided URL. The authentication details must be included by the browser in this automated GET request, typically in the cookies. Cookies are not sent across domains (only to sub-domains), so your *authenticator service* must be *hosted in the same domain* as the embedding application. + +* When using `getAuthToken`, you specify a function that returns a Promise that resolves with the *login token*. Within the callback function, you can define the request to the *authenticator service* with far greater control than the automated `GET` request to a URL used by the `authEndpoint` option. `getAuthToken` is the preferred method for production deployments unless your *authenticator service* is implemented within the existing API endpoints of your application and a simple GET request provides the necessary authentication detail. + ++ +The following example shows a callback function with a custom request using link:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch[Fetch, window=_blank], which returns a Promise. You can also use link:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest[XHR, window=_blank] and build the link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise, window=_blank] manually. + ++ +[source,JavaScript] +---- +init({ + thoughtSpotHost: tsURL, + authType: AuthType.TrustedAuthToken, + getAuthToken: getAuthToken, + username: username + }); + +function async getAuthToken { + const tokenURL = tokenServiceURL + "/gettoken/"; + console.log("calling token server at " + tokenURL); + + const timeoutSecs = 5 * 1000; // seconds to milliseconds + + const response = await timeout(timeoutSecs, fetch( + tokenURL, + { + method: 'POST', + mode: 'cors', + cache: 'no-cache', + headers: { + 'Content-Type': "text/plain", + 'X-TS-Auth-Token': tsAuthJWT + }, + credentials: 'include' + } + )) + + // Have to return a promise for the auth SDK. + //console.log(await response.text()); + return response.text() +} +---- + +For the cookie-based authentication method, ensure that the `username` specified in `init` matches the user name that was used for generating the token via `getAuthToken` or `authEndpoint`. + +If you choose `AuthType.TrustedAuthTokenCookieless`, a bearer token is generated. This token is stored in the app's memory and used for maintaining subsequent user sessions. You can use this authentication type if your *authenticator service* is not *hosted in the same domain* as the embedding application, and your browser restricts using third-party cookies. In this method, you do not need to specify `username`, because the token itself can be used to determine and authenticate a user. + +==== Cookie-based authentication examples + +[source,JavaScript] +---- +init({ + thoughtSpotHost: "https://:", + authType: AuthType.TrustedAuthToken, + username: "", + authEndpoint: "https://authenticator-server:/endpoint", +}); +---- + +[source,JavaScript] +---- +init({ + thoughtSpotHost: + authType: AuthType.TrustedAuthToken, + username: "", + getAuthToken: () => { + return fetch('https://my-backend.app/ts-token') + .then((response) => response.json()) + .then((data) => data.token); + }); +---- + +==== Cookieless authentication examples + +[source,JavaScript] +---- +init({ + thoughtSpotHost: "https://:", + authType: AuthType.TrustedAuthTokenCookieless, + authEndpoint: "https://authenticator-server:/endpoint", +}); +---- + +[source,JavaScript] +---- +init({ + thoughtSpotHost: + authType: AuthType.TrustedAuthTokenCookieless, + getAuthToken: () => { + return fetch('https://my-backend.app/ts-token') + .then((response) => response.json()) + .then((data) => data.token); + }); +---- + +== Authenticator service / back-end + +The authenticator service should exist at the web application tier of your networks, with secure access to the ThoughtSpot `secret_key` and the credentials of a ThoughtSpot administrator user (typically a service account). + +There are no requirements for how the authenticator service is built or hosted, other than being able to issue REST API commands to the ThoughtSpot instance and having access to the `secret_key`. ThoughtSpot generates a `secret_key` when trusted authentication is enabled on a ThoughtSpot application instance. When using a ThoughtSpot cloud instance, the authenticator service will need outbound request access to the hosted ThoughtSpot cloud instance. + +The simplest *authenticator service* does the following steps, assuming ThoughtSpot users already exist from another process: + +1. Verify and parse the authentication message to retrieve the ThoughtSpot username. +2. Request a login token from ThoughtSpot using REST API v1. +3. Return the token to the user's web browser. + +If user creation and group assignment must be performed at the time of the login token request, the *authenticator service* must follow the steps described in the xref:trusted-authentication.adoc#_just_in_time_user_provisioning_and_group_assignment[Just-in-time user provisioning and group assignment] section of this article. + +=== Verify and parse the authentication message +As mentioned in the preceding section, the exact way you send the authentication details varies with your implementation. The *authenticator service* must verify the request and then parse out the details (at minimum, the *ThoughtSpot username* value) so that they can be used in the subsequent REST API requests to ThoughtSpot. + +The *authenticator service* will need access to whatever code and other services are necessary to parse out the authentication details. For example, if you are sending through an OAuth token from an IdP, the IdP may provide a library or set of instructions using standard libraries. If using the application's existing session system, there will be some way to retrieve the username based on the session details from the request. You can also define your own JWT or some other secure way for your web application to send the message securely. + +If your *authenticator service* must also create users and give them access, you must parse out additional details from the request: + +* user email address + +* user display name + +* ThoughtSpot group names to add a user to + +* Org ID to which the user belongs + + +User password is not required in the login token request. It can be randomly generated if creating a user account in ThoughtSpot so that the user can only sign in via the embedding application. + +=== REST API session sign-in +The *authenticator service* makes REST API requests to ThoughtSpot. To make a REST API request for a login token, the *authenticator service* must have xref:api-auth-session.adoc[created an active session] as a ThoughtSpot user with *server administrator* privileges, typically a service account created only for use by the *authenticator service*. + +The authenticator service code will need logic to log in if there is no active session and secure access to the service account credentials. How you protect and securely access the service account credentials is up to you in the design of the service. Any examples with a username and password entered directly in the code are for *testing purposes only*. + +=== Login token request via REST API +The only other REST API call *necessary* after sign-in is the xref:session-api.adoc#session-authToken[request for the login token]. This is the call that utilizes the `secret_key`, which the *authenticator service* must also securely store and access along with the service account user credentials. + +When a token has been requested in `FULL` mode, it will create a full ThoughtSpot session in the browser and application. The token for `FULL` access mode persists through several sessions and stays valid until another token is generated. + +You can request a limited token using the `access_level=REPORT_BOOK_VIEW` option in REST API v1 and `/api/rest/2.0/auth/token/object` endpoint in REST API v2.0, but this is rarely used and not recommended. +Access control in ThoughtSpot (called Sharing) prohibits a signed-in user from loading any content to which they don't have access. Access control (sharing) can be granted during the login token request process by adding the user to the appropriate ThoughtSpot groups. + +=== Just-in-time user provisioning and group assignment + +Starting from 8.9.0.cl, the xref:session-api.adoc#session-authToken[/tspublic/v1/session/auth/token] endpoint supports just-in-time provisioning of users. If the user specified in the API request does not exist in the ThoughtSpot system, you can set the `autocreate` property to `true` to add the user to ThoughtSpot and assign the user to `groups`. + +The typical flow of REST API requests for user creation at the time of a login token request is as follows: + + +1. Make a REST API request to xref:user-api.adoc#get-user-details[get the user details]. +2. If the user already exists, check the `assignedGroups` property. On clusters with Orgs feature enabled, check the `orgIds` property to verify if the user mapped to any Org. +3. If the user doesn't exist in ThoughtSpot, you can either xref:user-api.adoc#create-user[create a new user] or set the `autocreate` property to `true` in your API request to the `/tspublic/v1/session/auth/token` endpoint. You can also specify the Org ID and group name to add the user to the Org and groups in the same API request. +4. If the user should be logged in to a different Org context, specify the Org ID in the `orgid` property and set `autocreate` to `true`. + ++ +[NOTE] +==== +Org IDs are integers that are created automatically when a cluster administrator creates an Org. To know the Org IDs of Orgs, you can send a `GET` request to the `/tspublic/v1/session/orgs` API endpoint. If you have cluster administrator privileges, you can use the `/tspublic/v1/org/search` endpoint to get a list of all Orgs available on your cluster. +==== + +5. If the user should belong to other groups, add group names in the `groups` property when making an API call to the `/tspublic/v1/session/auth/token` endpoint. If these groups don't exist in the specified `orgid`, set `autocreate` to `true` to add these groups to the Org. +6. Request a login token from ThoughtSpot via `/tspublic/v1/session/auth/token` API endpoint. +7. Return the token to the user's web browser. + +[NOTE] +==== +The `/api/rest/2.0/auth/token/object` and `/api/rest/2.0/auth/token/full` endpoints in REST API v2.0 also support JIT provisioning and assigning the user to groups and Orgs. +==== + +=== Additional REST API requests +Because all of ThoughtSpot administration is possible via the REST API, you can incorporate even more functionality into the *authenticator service* if necessary, building it into an authentication and authorization service. The xref:api-user-management.adoc[user and group privileges] REST API documentation covers the additional requests related to authorization. + +For example, you could use the xref:rest-api-reference.adoc#_groups_and_privileges[REST API v1] or xref:rest-api-v2-reference.adoc#_groups[REST API v2.0] group endpoints to implement ThoughtSpot groups that are intended for use in Row Level Security (RLS) rules. For these groups, the group name must match exactly with a value in a column in the data warehouse, so the name of the group itself serves as a __data entitlement__. You could adjust the flow described in the preceding section to create any group for RLS that did not already exist and assign it to the user, which would bring the process closer to a Role-based access control (RBAC) or Attribute-based access control (ABAC) pattern. + +== Disable trusted authentication + +To disable trusted authentication, follow these steps: + +. Log in to ThoughtSpot. +. If the per-Org secret key feature is enabled and Orgs are configured on your instance, switch to the Org for which you want to disable trusted authentication. +. Go to *Develop* > *Customizations* > *Security settings*. +. Click *Edit* and turn off the *Trusted authentication* toggle. ++ +A pop-up window appears and prompts you to confirm the disable action. + +. Click *Disable*. + ++ +When you disable trusted authentication, the validity of your existing secret key expires, and your app may become inoperable. +To a new secret key and generate authentication tokens, you must enable Trusted authentication. + +[#login-token] +== Login token expiration + +The login token, also referred to as the authentication token, allows users to access the requested object. It is a proprietary token format that cannot be decoded or used for any purpose other than to create a ThoughtSpot session. + +Tokens stay valid for a length of time based on the following rules: + +* A token stays valid indefinitely until another token for any user is generated. +* When a new token is generated using the same `secret_key`, the previous token will expire after five minutes. +* When a new `secret_key` is generated for the ThoughtSpot server and the first new login token is obtained using the new `secret_key`, all tokens generated using the previous `secret_key` become invalid. +* If users make multiple attempts to log in to ThoughtSpot using an invalid or expired token, they may get locked out of their accounts. + +To set a consistent five-minute expiration time, you can generate a second token to start the expiration clock for the previous login token that is sent to the user's browser. + +[NOTE] +==== +On multi-tenant clusters with Orgs, users must use the Org-specific tokens when switching between Orgs. +==== + +== Troubleshoot trusted authentication + +[NOTE] +==== +When implementing trusted authentication with session cookies, check if your browser allows third-party cookies. Chrome now blocks third-party cookies in Incognito mode by default, while Safari blocks them by default even in standard mode. If your Web browser rejects third-party cookies, the embedded content will be blocked. To workaround this issue, you can enable cookieless authentication (`AuthType.TrustedAuthTokenCookieless`) in the SDK. +==== + +== Implement without Visual Embed SDK +The Visual Embed SDK handles the final REST API request to create the session, but it is possible to perform the login using xref:session-api.adoc#session-loginToken[/session/login/token] or the xref:rest-api-v2-reference.adoc#_authentication[ REST API v2.0 token access endpoints]. For more information, see xref:api-auth-session.adoc#_authenticate_and_log_in_with_a_token_trusted_authentication[REST API v1 authentication] and xref:authentication.adoc#trusted-auth-v2[REST API v2.0 authentication]. + +[NOTE] +==== +The REST API v1 `session/login/token` and v2.0 token access endpoints are not used for establishing a REST API session for backend processes or administration scripts. Use the xref:session-api.adoc#session-login[/session/login] endpoint with `username` and `password` to create a REST API session. + +//// +* The REST API v2.0 allows using bearer or trusted authentication tokens. The authentication tokens obtained from REST API separate from the REST API v1 login token. +//// +==== + +//// +REST API clients can make a `GET` or `POST` API call to the xref:session-api.adoc#session-loginToken[tspublic/v1/session/login/token] API endpoint to log in a user. Note that the `GET` call to the `tspublic/v1/session/login/token` endpoint must include a fully-encoded URL with the authentication token and resource endpoint in the request URL. + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/session/login/token?username=tsUser&auth_token=JHNoaXJvMSRTSEEtMjU2JDUwMDAwMCRPMFA2S0ZlNm51Qlo4NFBlZUppdzZ3PT0kMnJKaSswSHN6Yy96ZGxqdXUwd1dXZkovNVlHUW40d3FLMVdBT3hYVVgxaz0&redirect_url=https:///?authtoken=&embedApp=true&primaryNavHidden=true#/embed/viz// +---- + +ThoughtSpot recommends sending the authentication attributes in a `POST` request body instead of a `GET` call. + +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +-d 'username=tsuser&auth_token=JHNoaXJvMSRTSEEtMjU2JDUwMDAwMCRtL3dWcVo2ZTdWTzYvemdXN1ZoaTh3PT0kdmlyNnQ4NHlwYXlqNFV4VzBpRlNYbmQ1bzk5T1RFK2NVZy9ZRUhvUEkvST0&redirect_url=https:///?embedV2=true#/pinboard/7a9a6715-e154-431b-baaf-7b58246c13dd%2F' \ +'https:///callosum/v1/tspublic/v1/session/login/token' +---- + +The API request must include the following attributes: + +* `username` + +_String_. The `username` of the user requesting access to the embedded ThoughtSpot content. + +* `auth_token` + +_String_. The authentication token obtained for the user. + +* `redirect_url` + +_String_. The URL to which the user is redirected after successful authentication. + ++ +---- +https:///?embedV2=true#/pinboard/7a9a6715-e154-431b-baaf-7b58246c13dd%2F +---- +//// + +== Additional resources + +* A simple Python Flask implementation of an Authenticator Service is available in the link:https://github.com/thoughtspot/ts_everywhere_resources/tree/master/examples/token_auth[ts_everywhere_resources GitHub repository, window=_blank]. + + The token_auth directory contains a link:https://github.com/thoughtspot/ts_everywhere_resources/blob/master/examples/token_auth/trusted_auth_tester.html[trusted_auth_tester.html, window=_blank] page to help verify each step of the trusted authentication process. +* link:https://github.com/thoughtspot/node-token-auth-server-example[https://github.com/thoughtspot/node-token-auth-server-example, window=_blank] +* link:https://github.com/thoughtspot/big-react-demo[React code samples, window=_blank] diff --git a/docs/src/asciidocs/tse-eco-mode.adoc b/docs/src/asciidocs/tse-eco-mode.adoc new file mode 100644 index 000000000..efd296cf8 --- /dev/null +++ b/docs/src/asciidocs/tse-eco-mode.adoc @@ -0,0 +1,104 @@ += Manage your cluster state +:toc: true +:toclevels: 1 + +:page-title: Update cluster state +:page-pageid: tse-dynamic-sense-cluster +:page-description: If you are using a ThoughtSpot Cloud cluster in the economy mode in your embedded deployments, use the APIs to restart an inactive cluster. + +If you are using a ThoughtSpot Cloud cluster for embedded deployments in your development or production environment, you can enable idle sensing to save costs and allow your cluster to operate in `economy` mode. To enable this feature on your clusters, contact ThoughtSpot Support. + +== Idle sensing and cluster states +If idle sensing is enabled on your cluster, your cluster will be automatically stopped if there is no user activity detected for a given time threshold. By default, the idle time threshold is set to 120 minutes. + +At any given time, a ThoughtSpot cluster can be in any one of the following states: + +* `ACTIVE` + +Indicates that the cluster is active and user activity is detected. +* `UNDER_MAINTENANCE` + +Indicates that the cluster is down for maintenance due to upgrade or patching. +* `STOPPED` +Indicates that the cluster is stopped and no user activity is detected. +* `STARTING`/`PENDING` + +The cluster is currently starting, or some other workflow is running on the cluster. + +== Identify the status of your cluster +By default, a ThoughtSpot cluster running the `economy` mode stops if there is no user activity for two hours. When a user tries to access a cluster that's in the `STOPPED` state, the API calls will return the `"cluster-state": "Stopped"` in the response header. + +[source,cURL] +---- + $ curl https://.thoughtspot.cloud --head + HTTP/1.1 200 OK + Server: awselb/2.0 + Date: Tue, 30 May 2023 15:27:01 GMT + Content-Type: text/html + Content-Length: 3348 + Connection: close + Cluster-State: Stopped +---- + +To restart the cluster, complete the steps described in the following section. + +== Start an inactive cluster using API +On a regular ThoughtSpot Cloud cluster, users can restart an inactive cluster using `CAPTCHA`. However, on embedded instances, the `CAPTCHA`-based cluster activation is not supported. Instead, the embedded application user can send a `GET` request to their instance with the following query parameters in the request URL: + +* `tse=true` +* `start_cluster=true` + +For example, to start an inactive cluster, send a `GET` request in the following parameters: + +.Production environment +[source,http] +---- +https://.thoughtspot.cloud/?tse=true&start_cluster=true +---- + +.Staging environment + +[source,http] +---- +https://.thoughtspotstaging.cloud/?tse=true&start_cluster=true +---- + +.Development environment + +[source,http] +---- +https://.thoughtspotdev.cloud/?tse=true&start_cluster=true +---- + +In the request header, you must also pass the `security-key`. The `security-key` is used for authenticating users and is generated when xref:trusted-authentication.adoc#trusted-auth-enable[trusted authentication is enabled] on a ThoughtSpot instance. Embedded application users can obtain the `security key` from their ThoughtSpot administrator. + +The following example shows the cURL request for restarting a cluster: + +[source, cURL] +---- +$ curl -X GET 'https://.thoughtspot.cloud/?tse=true&start_cluster=true' \ + -H 'security-key: e8ade677-c3f1-461d-8b7f-7f0fe4e024f0' --head \ + HTTP/1.1 200 OK + Server: awselb/2.0 + Date: Tue, 30 May 2023 16:04:08 GMT + Content-Type: text/html + Content-Length: 0 + Connection: keep-alive + Cluster-State: Starting +---- + +If the `GET` request is successful, the cluster starts. + +== Response header +Note the cluster state in the response header: + +* `STARTING` + +Indicates that the cluster is starting. It may take a few minutes for the cluster to become active. +* `UNKNOWN` + +Indicates a possible error. Contact your administrator or ThoughtSpot Support if the cluster does not start in 5-10 minutes. + +== Response codes +[options="header", cols="1,4"] +|=== +|HTTP status code|Description +|**200**|Successful operation +|**400**|Invalid request +|**401**|Unauthorized access +|=== diff --git a/docs/src/asciidocs/use-data-api-read.adoc b/docs/src/asciidocs/use-data-api-read.adoc new file mode 100644 index 000000000..e8467518a --- /dev/null +++ b/docs/src/asciidocs/use-data-api-read.adoc @@ -0,0 +1,75 @@ += Embed a Liveboard using REST API +:toc: true + +:page-title: Embed data +:page-pageid: embed-data +:page-description: Embed Data using REST APIs + +You can use the REST API to get an object from ThoughtSpot and embed it in a web page, portal, or application. ThoughtSpot provides an embed link for objects, such as Liveboards and Liveboard visualizations, using which you construct the URL required to make an API call. + +To get the embed link for a Liveboard: + +. Log in to ThoughtSpot from a browser. +. Navigate to the Liveboard from which you want to get data. +. Find the ID number of the object you want to get the data from. ++ +To embed a Liveboard, click the ellipses (...) icon, and select *Copy embed link*. + ++ +image::./images/copy_pinboard_link.png[Copy embed link, width=auto] + ++ +To get the embed link for a visualization: + +.. Navigate to the table or chart +.. Click the ellipses (...) icon in the upper right corner of the table or chart. +.. Click *Copy embed link* icon. ++ +image::./images/copy_link.png[Copy link, width=auto] +. Copy the ID number from the link. +Paste it somewhere so that you can use it later to construct the URL for the REST API call. + ++ +If the object is a Liveboard, copy the identifier that appears after `viz/`. + ++ +image::./images/copy_link_pinboard.png[Copy Liveboard link, width=auto] + ++ +For visualizations (table or chart), copy the IDs that appear after `viz/`. ++ +image::./images/copy_link_viz_pinboard_part.png[Copy visualization link, width=auto] + +. Construct the URL. ++ +For a Liveboard, the URL is as follows: + ++ +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id= +---- + ++ +For a visualization, the URL is as follows: + ++ +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/pinboarddata?id=&vizid=%5B%5D +---- + +. To apply filters to the data, use runtime filters. + ++ +For example, to sort values equal to `red` in the `Color` column for a visualization in a Liveboard, you can pass the runtime filter in the URL query parameters as shown here: + ++ +---- +http:///callosum/v1/tspublic/v1/pinboarddata +?id=&vizid=%5B%5D +&col1=color&op1=EQ&val1=red +---- + +. After you construct the URL, send a POST request to get data from ThoughtSpot. ++ +The Data REST API returns the data formatted as JSON. +. Retrieve the data from the JSON and embed it in your Web page, Web portal, or application. diff --git a/docs/src/asciidocs/user-api.adoc b/docs/src/asciidocs/user-api.adoc new file mode 100644 index 000000000..3207ee34d --- /dev/null +++ b/docs/src/asciidocs/user-api.adoc @@ -0,0 +1,1697 @@ += User API +:toc: true +:toclevels: 1 + +:page-title: User APIs +:page-pageid: user-api +:page-description: To create, update, and manage ThoughtSpot users programmatically, use the user API endpoints + +The User APIs allow you to programmatically create, update, and administer ThoughtSpot users. + +== Supported operations +include::{path}/user-api-list.adoc[] + +=== Required permissions + +You must have administrator access to create, edit, and delete a user, assign users to groups, transfer objects from one user to another, and invalidate, deactivate or activate a user session. + +If you have a multi-tenant instance with Orgs feature enabled, the cluster admin can create a user and associate the user to an `orgid`. For more information about Orgs, see xref:orgs.adoc[Multi-tenancy with Orgs]. + + +[#create-user] +== Create a user + +To programmatically create a user account in the ThoughtSpot system, send a POST request to `/tspublic/v1/user/` API endpoint. Using this API, you can create a user and assign a user to a group. + +[NOTE] +==== +* To create a user, you require admin user privileges. +* All users created in the ThoughtSpot system are added to ALL. +==== + +=== Resource URL +---- +POST /tspublic/v1/user/ +---- + +=== Request parameters + +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Type|Description +|`name` |Form parameter|__String__. Name of the user. The username string must be unique. +|`password`|Form parameter|__String__. Password for the user account. +|`displayname`|Form parameter|__String__. A unique display name string for the user, usually their first and last name. +|`properties` __Optional__|Form parameter|__String__. A JSON map of user properties fetched from external systems such as LDAP. If you are using Active Directory to authenticate users, and your LDAP configuration requires users to be created manually, you can upload the user properties as a JSON file. +|`groups` __Optional__|Form parameter|__Array of strings__. A JSON array of the GUIDs of groups to which you want to assign the user. The user privileges are determined by the group to which you assign the user. For example, if you assign the user to a group that has the `ADMINISTRATION` privilege, the user will have admin privileges. +|`usertype` __Optional__ a|Form parameter|__String__. Type of user. The default value is `LOCAL_USER`, which indicates that the user is created locally in the ThoughtSpot system. +|`tenantid` __Optional__|Form parameter|__String__. GUID of the tenant for which the user is being created. +|`visibility` __Optional__|Form parameter|__String__. Visibility of the user. The `visibility` attribute is set to `DEFAULT` when creating a user. The `DEFAULT` attribute makes a user visible to other users and user groups, and thus allows them to share objects. +|`orgids` + +__Optional__|Form parameter|__Integer__. A JSON array of org IDs to which you want to add the user. If `orgids` is not defined, ThoughtSpot assigns the user to an Org based on the administrator's session. For example, if the administrator sends the API request from the `Org 0` context, the user is added to `Org 0`. +|`triggeredbyadmin` a|Form parameter|__Boolean__. Indicates if the API request is initiated by a ThoughtSpot administrator or an external application. The default value is `false`. + +When set to `true`, the `displayNameLastUpdatedBy` property is set to `ADMIN` in the API response, Else, `displayNameLastUpdatedBy` is set to `AUTO`. +|`orgScope` __Optional__|Query parameter|__String__. The Org scope. When set to `ALL`, the administrator is authorized to perform cross-Org operations. By default, ThoughtSpot allows administrators to create a user in the Org context from which they make an API request. If you want to add the user to a different Org or multiple Orgs, set the Org scope to `ALL` and specify the Org ID(s) in the `orgids` attribute. +|=== +=== Example request + +.cURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'name=TS%20User&password=testy1%4022&displayname=TS%20User&usertype=LOCAL_USER&visibility=DEFAULT' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/ +---- + +=== Example response + +If the user is successfully created in ThoughtSpot, the API returns the user GUID along with the following JSON response: + +[source,JSON] +---- +{ + "userContent": { + "userPreferences": { + "notifyOnShare": true, + "showWalkMe": true, + "analystOnboardingComplete": false + }, + "userProperties": { + "displayNameLastUpdatedBy": "ADMIN" + }, + "userActivityProto": { + "first_login": -1, + "welcome_email_sent": false + } + }, + "state": "ACTIVE", + "assignedGroups": [ + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "inheritedGroups": [ + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "privileges": [], + "type": "LOCAL_USER", + "parenttype": "USER", + "visibility": "DEFAULT", + "tenantId": "982d6da9-9cd1-479e-b9a6-35aa05f9282a", + "displayName": "TS User", + "header": { + "id": "79c4cb2a-18cd-44a7-a077-6de65d1b468e", + "indexVersion": 0, + "generationNum": 0, + "name": "TS User", + "author": "59481331-ee53-42be-a548-bd87be6ddd4a", + "created": 1624796017810, + "modified": 1624796017810, + "modifiedBy": "59481331-ee53-42be-a548-bd87be6ddd4a", + "owner": "79c4cb2a-18cd-44a7-a077-6de65d1b468e", + "tags": [], + "isExternal": false, + "isDeprecated": false + }, + "complete": true, + "incompleteDetail": [], + "isSuperUser": false, + "isSystemPrincipal": false +} +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**200**| Successful operation +|**400**| Invalid parameter values + +Unauthorized user addition to an org +|**409**| Username is not unique +|**403**| Unauthorized request +|**500**| Incorrect password format +|=== + +[#update-user] +== Update user details + +To modify an existing user account, send a `PUT` request to the /tspublic/v1/user/{userid}` endpoint. + +This API allows the following modifications to a user profile: + +* Username modifications +* Password reset +* Group assignment +* User visibility for sharing objects +* User preferences, such as viewing onboarding experience, subscribing to or unsubscribing from email notifications, and so on. + +[NOTE] +==== +To add or modify the email address of a user, use the `/tspublic/v1/user/email` API endpoint. +==== + +=== Resource URL +---- +PUT /tspublic/v1/user/{userid} +---- + +=== Request parameters +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Type|Description +|`userid`|Form parameter|__String__. GUID of the user. +|`content`|Form parameter|__String__. A JSON map of strings with the user profile attributes. +|`password` __Optional__|Form parameter|__String__. Password string for the user account. Use this attribute to change the password of the user account. +|`triggeredbyadmin` a|Form parameter a|__Boolean__. Indicates if the user update API request is initiated by the ThoughtSpot administrator or an external application. By default, the `triggeredbyadmin` flag is set to `false`. The default value is `false`. + + +* When set to `true`, ThoughtSpot updates the `displayNameLastUpdatedBy` property to `ADMIN`. Else, the `displayNameLastUpdatedBy` property is set to `AUTO` for the specified user object. + +[NOTE] +==== +Starting from 8.9.0.cl, ThoughtSpot users can update their display name on the profile setting page in the UI. If a user updates their display name, ThoughtSpot sets `displayNameLastUpdatedBy` to `USER` in the object properties. +==== +|`orgScope` __Optional__|Query parameter|__String__. The Org scope. If you are making this API request for a user that belongs to a different Org than the one you are currently logged in to, specify `ALL` to authorize the cross-Org operation. +|=== + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X PUT \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'userid=6deb3976-e7c9-4f6a-94cc-90d790ee828d&content={ "userContent":{ "userPreferences":{ "notifyOnShare":true, "showWalkMe":true, "analystOnboardingComplete":false }, "userProperties":{ "displayNameLastUpdatedBy":"ADMIN" }, "userActivityProto":{ "first_login":-1, "welcome_email_sent":false } }, "state":"ACTIVE", "assignedGroups":[ "b25ee394-9d13-49e3-9385-cd97f5b253b4" ], "inheritedGroups":[ "b25ee394-9d13-49e3-9385-cd97f5b253b4" ], "privileges":[ ], "type":"LOCAL_USER", "parenttype":"USER", "visibility":"DEFAULT", "tenantId":"982d6da9-9cd1-479e-b9a6-35aa05f9282a", "displayName":"TS Test User", "header":{ "id":"6deb3976-e7c9-4f6a-94cc-90d790ee828d", "name":"tsTest", "displayName":"tsTest", "author":"59481331-ee53-42be-a548-bd87be6ddd4a", "created":1675661280328, "modified":1675661280328, "modifiedBy":"59481331-ee53-42be-a548-bd87be6ddd4a", "owner":"6deb3976-e7c9-4f6a-94cc-90d790ee828d", "isDeleted":false, "isHidden":false, "orgIds":[ 0 ], "tags":[ ], "type":"LOCAL_USER", "isExternal":false, "isDeprecated":false, "isSharedViaConnection":false }, "complete":true, "incompleteDetail":[ ], "isSuperUser":false, "isSystemPrincipal":false }&triggeredbyadmin=true'\ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/{userid}' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/{userid} +---- + +==== JSON file example for updating user profile + +[source,JSON] +---- +{ + "userContent":{ + "userPreferences":{ + "notifyOnShare":false, + "showWalkMe":true, + "analystOnboardingComplete":false + }, + "userActivityProto":{ + "first_login":-1, + "welcome_email_sent":false + } + }, + "state":"ACTIVE", + "assignedGroups":[ + "d0326b56-ef23-4c8a-8327-a30e99bcc72b", + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "inheritedGroups":[ + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "privileges":[ + + ], + "type":"LOCAL_USER", + "parenttype":"USER", + "visibility":"DEFAULT", + "tenantId":"982d6da9-9cd1-479e-b9a6-35aa05f9282a", + "displayName":"TS User2", + "header":{ + "id":"d1f4f2c8-c5bb-4f20-a81d-1f24af0b3286", + "indexVersion":0, + "generationNum":0, + "name":"TS User2", + "author":"59481331-ee53-42be-a548-bd87be6ddd4a", + "created":1624846987754, + "modified":1624846987754, + "modifiedBy":"59481331-ee53-42be-a548-bd87be6ddd4a", + "owner":"d1f4f2c8-c5bb-4f20-a81d-1f24af0b3286", + "tags":[ + + ], + "isExternal":false, + "isDeprecated":false + }, + "complete":true, + "incompleteDetail":[ + + ], + "isSuperUser":false, + "isSystemPrincipal":false +} +---- + +=== Example response + +On successful update of the user profile, the API returns the following response code: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204** | Successful operation +|**403**| Unauthorized request +|**500**| Invalid content format +|=== + +[#addEmail] + +== Add or modify the email address of a user + +To add or modify the email address of a user, send a `PUT` request to the `/tspublic/v1/user/email` API endpoint. + + +=== Resource URL + +---- +PUT /tspublic/v1/user/email +---- + +=== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Form parameter|Description +|`userid`|__String__. GUID of the user. +|`emailid`|__String__. Email address of the user. +|=== + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X PUT \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'userid=a8aeda00-dc3c-4485-b8d1-fd6ac701a819&emailid=user123%40thoughtspot.com'\ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/email' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/email +---- + +=== Example response + +If the email address is added successfully, the API returns the following response code: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204** | Successful operation +|**400**| Invalid user ID +|**500**| Invalid email format +|=== + +[#addOrg] +== Add users to an Org +To add one or several users to an org, send a `POST` request to the `POST /tspublic/v1/user/addtoorg` API endpoint. + + +=== Resource URL + +---- +POST /tspublic/v1/user/addtoorg +---- + +=== Request parameters +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Type|Description +|`userids`|Form parameter|__String__. A JSON array of user GUIDs to add to the specified org. +|`orgid`|Form parameter|__Integer__. ID of the Org object to which you want to assign the users. By default, the user is added to the Org context from which the API request is sent. To add the user to another Org, specify the Org ID and set `orgScope` to `ALL`. +|`orgScope`|Query parameter|__String__. The Org scope. For cross-Org operations, set this attribute to `ALL`. +|=== + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +-d 'userids=%5B4391d676-2dd8-4248-b6db-d973811f0122%2C37539499-624a-4d3d-8f88-e9be5653c114%5D&orgid=3' \ +'http://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/addtoorg?orgScope=ALL' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/addtoorg?orgScope=ALL +---- + +=== Example response + +If the request is successful, the API returns the 204 response code: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204** | Successful operation +|**400**| Invalid parameter +|**403**| Unauthorized request +|=== + +[#get-user-details] +== Get user details + +To get the details of a specific user account or all users in the ThoughtSpot system, send a `GET` request to `/tspublic/v1/user/` API endpoint. + +[NOTE] +==== +If you want to get a list of object headers associated with a user or user group, you can use the `xref:metadata-api.adoc#object-header[GET /tspublic/v1/metadata/listobjectheaders]` API. +==== + +=== Resource URL +---- +GET /tspublic/v1/user/ +---- + +=== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Query parameter|Description +|`userid` + +__Optional__|__String__. The GUID of the user account to query. +|`name` + +__Optional__|__String__. Username of the user that you want to query. +|=== + +[NOTE] +==== +You can use either `userid` or `name` to query data for a specific user. If using both, make sure the values for these parameters point to the same user account. If neither of these parameters is defined, the API returns metadata for all users in the ThoughtSpot system. +==== + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/?userid=b995e481-d0a7-4820-b1e8-54051ede77a2' +---- +.Request URL + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/?userid=b995e481-d0a7-4820-b1e8-54051ede77a2 +---- + +=== Example response + +[source,JSON] +---- +{ + "userContent": { + "userPreferences": { + "notifyOnShare": true, + "showWalkMe": true, + "analystOnboardingComplete": false + }, + "userProperties": { + "displayNameLastUpdatedBy": "ADMIN", + "persona": "BUSINESS_USER" + "mail": "tsUser@thoughtspot.com", + "companyName": "", + "activatedAtMs": 1649842964294 + }, + "userActivityProto": { + "first_login": -1, + "welcome_email_sent": false + } + }, + "state": "ACTIVE", + "assignedGroups": [ + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "inheritedGroups": [ + "b25ee394-9d13-49e3-9385-cd97f5b253b4" + ], + "privileges": [ + "AUTHORING" + ], + "type": "LOCAL_USER", + "parenttype": "USER", + "visibility": "DEFAULT", + "tenantId": "982d6da9-9cd1-479e-b9a6-35aa05f9282a", + "displayName": "kailash", + "header": { + "id": "b995e481-d0a7-4820-b1e8-54051ede77a2", + "indexVersion": 2602, + "generationNum": 2602, + "name": "kailash", + "displayName": "kailash", + "author": "59481331-ee53-42be-a548-bd87be6ddd4a", + "created": 1623728042624, + "modified": 1623728042624, + "modifiedBy": "59481331-ee53-42be-a548-bd87be6ddd4a", + "owner": "b995e481-d0a7-4820-b1e8-54051ede77a2", + "isDeleted": false, + "isHidden": false, + "tags": [], + "type": "LOCAL_USER", + "isExternal": false, + "isDeprecated": false + }, + "complete": true, + "incompleteDetail": [], + "isSuperUser": false, + "isSystemPrincipal": false +} + +---- + +[NOTE] +==== +If no `userid` or `name` attribute is specified, the API returns a response with the details of all users in the ThoughtSpot system. +==== + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**200** | Successful retrieval of user details +|**400**| Invalid username string +|**500**| Invalid user ID +|=== + +[#deactivate-user] +== Deactivate a user account + +To deactivate a user account, send a `POST` request to the `/tspublic/v1/user/inactivate` API endpoint. + +=== Resource URL +---- +POST /tspublic/v1/user/inactivate +---- + +=== Request parameters + +[width="100%" cols="1,4"] +[options='header'] +|=== +|Form parameter|Description +|`username`|__String__. Username of the user account to deactivate. +|`url`|__String__. The URL of the cluster on which the user account is currently active. +|=== + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: text/plain' --header 'X-Requested-By: ThoughtSpot' \ +-d 'username=usr1&url=https%3A%2F%2F.cloud%2F' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/inactivate' +---- + +.Request URL + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/inactivate +---- + +=== Example response + +If the user deactivation operation is successful, the API returns the following response: + +---- +https://{ThoughtSpot-Host}/#/activate?id=5fe00a84-e7eb-4a8b-b58d-ec205de9c645&token=JHNoaXJvMSRTSEEtMjU2JDUwMDAwMCR1WUlOQ0VLbGtWMXZyMWtXUGdKSG9nPT0kTjY3Znd2STA1bURMMXNVMDMzVUkvK2tybllaZUUwUktTUWNEUEJZNWQwbz0 +---- + +Note the user ID and auth token string. You will need this information to re-activate a user account. + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**200** |Successful operation +|**403**| Unauthorized request +|**500**| Invalid user name +|=== + +[#activate-user] +== Activate a user account + +To activate a user account that is currently inactive, send a `POST` request to the `/tspublic/v1/user/activate` API endpoint. + +[IMPORTANT] +==== +When a user account is deactivated using the `/tspublic/v1/user/inactivate` endpoint, the API returns a response with the user ID and auth token string. This auth token string and the user ID are required for reactivating a user session. + +---- +https://#/activate?id=&token= +---- +==== + +=== Resource URL +---- +POST /tspublic/v1/user/activate +---- + +=== Request parameters + +[width="100%" cols="1,4"] +[options='header'] +|=== +|Form parameter|Description +|`userid`|__String__. The GUID of the user account to activate. +|`auth_token`|__String__. The authentication token to reactivate the user account. +|`password` |__String__. The password string for the user account. +|`properties`|__Array of Strings__. A JSON map of the user properties to update the user account. +|=== + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'userid=996969b6-0a4c-4e3d-9f38-a976fe821790&auth_token=JHNoaXJvMSRTSEEtMjU2JDUwMDAwMCRKWE9MWU4yalVHYUdZaXdHS0dsbWFRPT0kUDRvODVkS1dsRHMyNWd0Njg5K0ZDZVl5R2h1MFBTKzBlQk1pRGNyaW9CQT0&password=fooFoo123!&properties=%5B%7B%22mail%22%3A%22test_user1%40thoughtspot.com%22%7D%5D' +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/activate' + +---- + +.Request URL + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/activate +---- + +=== Example response + +If the user account activation is successful, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204** |Successful operation +|**403**| Unauthorized request +|**500**| Invalid user ID +|=== + +[#invalidate-user-session] +== Invalidate a user session + +After a password of a user account is reset, you may want to invalidate a user session and force the user to re-login with the new password. To invalidate a user session, you can send a `POST` request to the `/tspublic/v1/user/session/invalidate` endpoint. + + +[WARNING] +==== +* Use this API with caution as it may invalidate active user sessions and force users to re-login. +* Make sure you specify the usernames or user IDs. If you pass null values in the API call, all user sessions on your cluster become invalid and users are forced to re-login. +==== + +=== Resource URL +---- +POST /tspublic/v1/user/session/invalidate +---- + +=== Request parameters + +[width="100%" cols="1,4"] +[options='header'] +|=== +|Form parameter|Description +|`username` +|__Array of strings__. A JSON array of usernames of the users whose sessions you want to revoke. This attribute is __Optional__ if the `userid` attribute is defined. +|`userid` +|__Array of strings__. A JSON array of the GUIDs of the user account. This attribute is __Optional__ if the `username` attribute is defined. +|=== + + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'username=%5B%22tsadmin%22%5D' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/session/invalidate' +---- + +.Request URL + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/session/invalidate +---- + +=== Example response + +If the user deactivation operation is successful, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|==== +|HTTP status code|Description +|**204**|Successful operation +|**403**| Unauthorized request +|**500**| Invalid username or userID +|==== + +[#delete-user] +== Delete a user account +To remove a user from the ThoughtSpot system, send a `DELETE` request to the `/tspublic/v1/user/{userid}` API endpoint. + +=== Resource URL +---- +DELETE /tspublic/v1/user/{userid} +---- + +=== Request parameters + +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Type|Description +|`userid`|Path|__String__. GUID of the user account to delete. +|`orgid`|Query|__Integer__. The org ID to which the user is associated. This parameter is required only if your ThoughtSpot instance has Orgs. + +If you are trying to delete a user that belongs only to the Org specified in the API request, the user is deleted from the Org and ThoughtSpot system. + +If the user belongs to multiple Orgs and you specify only one Org ID, the user is removed only from the specified Org and not from the ThoughtSpot system. + +To remove the user from all Orgs and the ThoughtSpot system, set the `orgScope` to `ALL`. +|`orgScope`|Query|__String__. The Org scope. Specify `ALL` to set the Org scope to all Orgs. +|=== +=== Example request + +.cURL + +[source,cURL] +---- +curl -X DELETE \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/ee74b737-da39-4667-95ad-cc06c81ab13d' +---- + +.Request URL + +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/ee74b737-da39-4667-95ad-cc06c81ab13d +---- +=== Example response + +On successful removal of the user account, the API returns the following response: + +---- +Response Code +204 +---- +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204** | Successful operation +|**403**| Unauthorized request +|**500**| Invalid user ID +|=== + +[#user-list] +== Get a list of users and groups + +To get a list of users and groups available in the ThoughtSpot system and view details of their inter-dependencies, use the `/tspublic/v1/user/list` API endpoint. + +=== Resource URL +---- +GET /tspublic/v1/user/list +---- + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/list' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/list +---- + +=== Example response + +[source,JSON] +---- +[ + { + "name": "Administrator", + "displayName": "Administration Group", + "created": 1354006445722, + "modified": 1354006445722, + "principalTypeEnum": "LOCAL_GROUP", + "groupNames": [], + "visibility": "DEFAULT", + "activate": false + }, + { + "name": "All", + "displayName": "All Group", + "created": 1354006445722, + "modified": 1354006445722, + "principalTypeEnum": "LOCAL_GROUP", + "groupNames": [], + "visibility": "DEFAULT", + "activate": false + }, + { + "name": "System", + "displayName": "System Management Group", + "created": 1354006445722, + "modified": 1354006445722, + "principalTypeEnum": "LOCAL_GROUP", + "groupNames": [], + "visibility": "DEFAULT", + "activate": false + }, + { + "name": "su", + "displayName": "Administrator Super-User", + "created": 1354006445722, + "modified": 1354006445722, + "mail": "", + "principalTypeEnum": "LOCAL_USER", + "groupNames": [ + "Administrator", + "All", + "System" + ], + "visibility": "DEFAULT", + "activate": false + }, + { + "name": "system", + "displayName": "System User", + "created": 1354006445722, + "modified": 1354006445722, + "mail": "", + "principalTypeEnum": "LOCAL_USER", + "groupNames": [ + "All", + "System" + ], + "visibility": "DEFAULT", + "activate": false + }, + { + "name": "aptest", + "displayName": "APtest", + "created": 1634265580100, + "modified": 1634269380481, + "mail": "user15@thoughtspot.com", + "principalTypeEnum": "LOCAL_USER", + "groupNames": [ + "Administrator", + "All" + ], + "visibility": "DEFAULT", + "activate": false + } +] +---- +==== Object properties +A typical principal object contains the following properties: + +* `name` + ++ +Name of the principal. This field, in conjunction with whether the object is a user or group, is used to identify a user or group. The name of the principal must be unique. + +* `displayName` + ++ +Display name of the principal. + +* `description` ++ +Description of the principal. + +* `mail` ++ +The email address of the user. This field is populated only for the user objects. It is ignored if the object type is a group. + +* `principalTypeEnum` ++ +Type of the user created in the ThoughtSpot system. For example: + +** `LOCAL_USER` for users that are created and authenticated locally in the ThoughtSpot system +** `LOCAL_GROUP` for groups that are saved in the local database of the ThoughtSpot system +** `SAML_USER` for SSO users authenticated by a SAML IdP +** `OIDC_USER` for SSO users authenticated by an OpenID provider via OIDC protocol +** `LDAP_GROUP` for groups synchronized from an LDAP server +** `LOCAL_GROUP` for groups that are created locally on ThoughtSpot. + +* `password` ++ +The password of the user. This field is populated only for the user object. It is ignored in the case of groups. + ++ +Password is only required: + +** if the user is of `LOCAL_USER` type +** when the user is created for the first time. In subsequent updates, the user password is not modified even if it changes in the source system. + +* `groupNames` ++ +Name of the groups to which a principal belongs. For example, `Administrator`, `All`, and so on. Users can belong to multiple groups. + +* `visibility` ++ +If the user is visible to the other ThoughtSpot users or user groups who might want to share objects. + +* `activate` + +Indicates if the user or user group needs to be activated. If the user or user group is already active, the `activate` property is set to `false`. + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP Code|Description +|**200**|Successful operation +|=== + +[#change-pwd] +== Change password +To change the password of a ThoughtSpot user account, send a `POST` request to the `/tspublic/v1/user/updatepassword` endpoint. + +=== Resource URL +---- +POST /tspublic/v1/user/updatepassword +---- +=== Request parameters + +[width="100%" cols="1,3"] +[options='header'] +|==== +|Form parameter|Description +|`name` |__String__. Name of the user account. +|`currentpassword`|__String__. The password of the currently logged-in user. +|`password`|__String__. A new password for the user specified in the `name` attribute. +|==== +=== Example request + +.cURL +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'name=guest¤tpassword=test&password=foobarfoobar' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/updatepassword' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/updatepassword +---- + +=== Example response + +If the operation is successful, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204**|Password update is successful. +|=== + +[#resetpassword] +== Reset password +To reset the password of a ThoughtSpot user account, send a `POST` request to the `/tspublic/v1/user/resetpassword` API endpoint. + + +=== Resource URL +---- +POST /tspublic/v1/user/resetpassword +---- +=== Request parameters + +[width="100%" cols="1,3"] +[options='header'] +|==== +|Form parameter|Description +|`userid` |__String__. The GUID of the user account. +|`auth_token`|__String__. The authentication token obtained for your user session. +|`password`|__String__. A new password string for the user account. +|==== + +=== Example request + +.cURL + +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'userid=59481331-ee53-42be-a548-bd87be6ddd4a&auth_token=JHNoaXJvMSRTSEEtMjU2JDUwMDAwMCRPMFA2S0ZlNm51Qlo4NFBlZUppdzZ3PT0kMnJKaSswSHN6Yy96ZGxqdXUwd1dXZkovNVlHUW40d3FLMVdBT3hYVVgxaz0&password=foobarA@123' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/resetpassword' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/resetpassword +---- + +=== Example response + +If the operation is successful, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204**|Password reset is successful +|**401**|Unauthorized request +|**500**|Invalid parameter +|=== + +[#updatepreference-api] +== Update a user profile +To update the profile settings of a ThoughtSpot user programmatically, send a `PUT` request to the `/tspublic/v1/user/updatepreference` endpoint. + +The `/tspublic/v1/user/updatepreference` API allows you to modify the following attributes of a ThoughtSpot user profile: + +* Email address ++ +The email address of the user. + +* Language preference ++ +The system locale setting. The locale setting determines the language of the ThoughtSpot UI, date, number, and currency format. + +* Notification setting ++ +User preference for receiving email notifications when another ThoughtSpot user shares answers or Liveboards. + +* Settings for revisiting the onboarding experience ++ +The user preference for revisiting the onboarding experience. + ++ +ThoughtSpot provides an interactive guided walkthrough to onboard new users. The onboarding experience leads users through a set of actions to help users get started and accomplish their tasks quickly. The users can turn off the Onboarding experience and access it again when they need assistance with the ThoughtSpot UI. + +[NOTE] +==== +The `/tspublic/v1/user/updatepreference` API does not support modifying the profile picture of a user, the password of a user account, and the Answer experience preference settings in a user profile. +==== + +=== Resource URL +---- +POST /tspublic/v1/user/updatepreference +---- + +=== Request parameters +[width="100%", cols="1,4"] +[options="header"] +|=== +|Form parameter|Description +|`userid` + __Optional__ +|__String__. The GUID of the user. +|`username` __Optional__|__String__. Username of the user. +|`preferences` a|__String__. The JSON map of user preferences. In the JSON map, you can define the attributes to set the following preferences for a user: + +* change the display language of the ThoughtSpot UI +* receive email notifications when another user shares an Answer or Liveboard +* enable the onboarding experience +|`preferencesProto` __Optional__|__String__. A 64-bit encoded string to set user preferences in a secure manner. For example, `CgoKCAgBEAEYASAB`. +|=== + +[NOTE] +==== +If your browser or OS locale is set to a xref:user-api.adoc#locale-setting[ThoughtSpot supported locale], ThoughtSpot automatically defaults to that locale. If your browser locale is not supported in ThoughtSpot, ThoughtSpot sets `en-US` (US English) as your default locale. +==== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X POST \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +-d 'userid=59481331-ee53-42be-a548-bd87be6ddd4a&preferences=%7B%22showWalkMe%22%3Atrue%2C%22notifyOnShare%22%3Atrue%2C%22analystOnboardingComplete%22%3Afalse%2C%22preferredLocale%22%3A%22en-IN%22%7D' \ +'https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/updatepreference' +---- + +.Request URL +---- +https://{ThoughtSpot-Host}/callosum/v1/tspublic/v1/user/updatepreference +---- + +.Example JSON String + +This example shows the following preference settings that you can pass as a JSON string. + +[source,JSON] +---- +{ + "showWalkMe":true, + "notifyOnShare":true, + "analystOnboardingComplete":false, + "preferredLocale":"en-CA" +} +---- +* `showWalkMe` __Boolean__ ++ +Enables or disables the guided onboarding walkthrough. When set to `true`, the user can revisit the onboarding experience. + +* `notifyOnShare` __Boolean__ ++ +Sets a notification preference for receiving emails when another user shares answers or Liveboards. + +* `analystOnboardingComplete` __Boolean__ ++ +Indicates if the user is onboarded. + +* `preferredLocale` __String__ ++ +Sets the ThoughtSpot locale for the specified user account. For example, to allow a user to view the ThoughtSpot UI in Deutsche, you can set the `preferredLocale` parameter to `de-DE`. ++ +The allowed values are: ++ +[#locale-setting] +[width="60%", cols="1,2"] +[options="header"] +|==================== +| Locale | Language +| `da-DK` | Dansk +| `de-DE` | Deutsche +| `en-AU` | English (Australia) +| `en-CA` | English (Canada) +| `en-IN` | English (India) +| `en-GB` | English (United Kingdom) +| `en-US` | English (United States) +| `es-US` | Español (Latinoamérica) +| `es-ES` | Español (España) +| `fr-CA` | Français (Canada) +| `fr-FR` | Français (France) +| `it-IT` | Italiano +| `nl-NL` | Nederland +| `nb-NO` | Norsk +| `pt-BR` | Português (Brasil) +| `pt-PT` | Português (Portugal) +| `fi-FI` | Suomi +| `sv-SE` | Svenska +| `zh-CN` | 中文(简体) +| `ja-JP` | 日本語 +|==================== + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204**| Successful update of a user profile +|**400**| Invalid user ID +|=== + +[#transfer-ownership] +== Transfer ownership + +When a user is removed from the ThoughtSpot application, you may want to transfer objects from the deleted user account to the account. Administrators can programmatically transfer the ownership of one or several objects from one ThoughtSpot user to another via the `/tspublic/v1/user/transfer/ownership` API endpoint. + +=== Resource URL +---- +POST /tspublic/v1/user/transfer/ownership +---- +=== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|==== +|Query parameter|Description +|`fromUserName`|__String__. Username to transfer from. +|`toUserName`|__String__. Username to transfer to. +a|`objectsID` + +__Optional__ a|__Array of strings__. A JSON array of ThoughtSpot object IDs. + + +* Example with multiple object IDs: + +`[7589cbdb-eb50-4d8c-89e7-08e8f4573a5d,84481cda-f92e-4ba5-a1ef-366eb61017f5,5f9bc462-eca8-4b12-b8da-36474664eada]` +* Example with a single object ID: + +`[7589cbdb-eb50-4d8c-89e7-08e8f4573a5d]` + +If you do not specify the object IDs, all the objects owned by the user specified in `fromUserName` will be transferred to the user specified in `toUserName`. +|==== + +=== Example request + +.cURL +[source,cURL] +---- +curl -X POST \ +--header 'Content-Type: application/json' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/user/transfer/ownership?fromUserName=guest&toUserName=guest1' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/user/transfer/ownership?fromUserName=guest&toUserName=guest1 +---- + +=== Example response + +If the operation is successful, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP Code|Description +|**204**|The ownership of objects is successfully transferred. +|**400**|Invalid `fromName` or `toName`, or no user in the ThoughtSpot that matches the specified username. +|=== + +[#user-sync] +== Synchronize principals +To programmatically synchronize user accounts and user groups with ThoughtSpot, use the `/tspublic/v1/user/sync` API. +The payload takes principals containing all users and groups present in the external database. A successful API call returns the object that represents the changes made in the ThoughtSpot system. + +During this operation: + +* Objects (users or groups) present in ThoughtSpot, but not present in the external list are deleted in ThoughtSpot. +* Objects present in ThoughtSpot and the external list are updated such that the object attributes in ThoughtSpot match those present in the list. ++ +This includes group membership. + +* Objects not present in ThoughtSpot, but present in the external list are created in ThoughtSpot. + +=== Resource URL +---- +POST /tspublic/v1/user/sync +---- +=== Request parameters + +This API uses the `multipart/form-data` content-type. + +[NOTE] +==== +Make sure you use a JSON file encoded as `application/json` or `text/json` for the `principals` attribute. The other arguments use standard form-encoding. Each is sent as its own part of the multi-part request. +==== + +[width="100%" cols="1,4"] +[options='header'] +|=== +|Form parameter|Description + +|`principals`|__String__. Specify a list of principal objects in xref:user-api.adoc#principalJson[the JSON file format]. The JSON file can contain all users and groups present in the external database. + +|`applyChanges`| +__Boolean__. +Specify whether to sync the users and groups to the system and apply the difference evaluated. + By default, this attribute is set to `false`. + +|`removeDeleted`| +__Boolean__. +Specify whether to remove the deleted users and user groups. By default, this attribute is set to `true`. If you do not want to remove deleted users or user groups, make sure to set `removeDeleted` to `false`. + +|`password` +|__String__. Assign a password for new users added during the sync operation. By default, all new users will have the same password. +|=== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X POST \ +--header 'X-Requested-By : ThoughtSpot' \ +--header 'Cookie : JSESSIONID=0f534ede-f096-44d0-966a-f02be91dcb68; clientId=5ea75049-cbc9-4443-b083-2d148059c235; userGUID=a0d4311a-d123-48e5-806b-8bdc35e3e835' \ +--header 'Accept: application/json' \ +-F 'applyChanges=false' \ +-F 'removeDeleted=false' +-F 'principals=@principals.json;type=application/json' \ +https:///callosum/v1/tspublic/v1/user/sync +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/user/sync +---- + +[#principalJson] +==== JSON request + +The `principals.json` file contains the JSON request to be sent for synchronizing users. Make sure the JSON file is encoded as `application/json` in the API request. + +Use the example format for the JSON requests: + +[source,JSON] +---- +[ + { "name": "Customer Success", + "displayName": "Customer Success", + "description": "CS", + "created": 1568926267025, + "modified": 1568926982242, + "principalTypeEnum": "LOCAL_GROUP", + "groupNames": [], + "visibility": "DEFAULT" }, + + { "name": "All", + "displayName": "All Group", + "created": 1354006445722, + "modified": 1354006445722, + "principalTypeEnum": "LOCAL_GROUP", + "groupNames": [], + "visibility": "DEFAULT" }, + + { "name": "Marketing", + "displayName": "Marketing", + "description": "Marketing Group", + "created": 1587573582931, + "modified": 1587573583003, + "principalTypeEnum": "LOCAL_GROUP", + "groupNames": [], + "visibility": "DEFAULT" }, + + { "name": "test1", + "displayName": "test one", + "description": "", + "created": 1587573554475, + "modified": 1587573589986, + "mail": "test1@test.com", + "principalTypeEnum": "LOCAL_USER", + "groupNames": [ "All", "Customer Success", "Marketing" ], + "visibility": "DEFAULT" }, + + { "name": "test2", + "displayName": "test two", + "created": 1587573621279, + "modified": 1587573621674, + "mail": "test2@test.com", + "principalTypeEnum": "LOCAL_USER", + "groupNames": [ "Administrator", "All" ], + "visibility": "DEFAULT" } +] +---- +[IMPORTANT] +==== +The preceding example covers user objects (with emails), group objects, and their relationships. + +* You can leave the `created` and `modified` dates blank for new users. +* You can specify if the principal is a user or user group in the `principalTypeEnum` keyword. +* In the example JSON request, the `test1` user belongs to two groups, `Customer Success` and `Marketing`, and the +`test2` user belongs to the group `Administrator`. +* `All` is a default group to which every user belongs; you may omit it from the input. +* Set `visibility` to `NON_SHARABLE` if you do not want users to share ThoughtSpot objects with other users in this group. +==== + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**200**| The user sync operation is successful +|**500**| Invalid request +|=== + +[#assignUserToGroups] +== Assign a user to groups + +To assign a user to groups that exist in the Thoughtspot system, send a `POST` request to the `/tspublic/v1/user/{userid}/groups` API endpoint. + +=== Resource URL + +---- +POST /tspublic/v1/user/{userid}/groups +---- + +=== Request parameters + +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Parameter Type|Description +|`userid`|path|__String__. The GUID of the user that you want to assign to the specified groups. +|`groupids`|query|__String__. A JSON array of the GUIDs of the user groups to which you want to add the user. +|=== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X POST \ +--header 'Content-Type: application/json' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups?groupids=%5B%2246fc2125-d424-40bd-9513-23cd5e2e92c3%22%2C%222e3f697a-e38d-4d50-b5c5-e2514e85d90e%22%5D' + +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups?groupids=%5B%2246fc2125-d424-40bd-9513-23cd5e2e92c3%22%2C%222e3f697a-e38d-4d50-b5c5-e2514e85d90e%22%5D +---- + +=== Example response + +If the user group assignment is successful, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204**| Successful operation +|**400**| Invalid parameter +|=== + +[#getGroupsUser] +== Get user group details for a specific user + +To get a list of user groups associated with a user, send a `GET` request to the `/tspublic/v1/user/{userid}/groups` API endpoint. + +=== Resource URL + +---- +GET /tspublic/v1/user/{userid}/groups +---- + +=== Request parameters + +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Path parameter||Description +|`userid`|__String__. The GUID of the user that you want to query. +|=== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X GET \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups +---- + +=== Example response + +If the GET operation is successful, the API returns the following response: + +[source,JSON] +---- +[ + { + "userGroupContent": {}, + "groupIdx": 2, + "metadataVersion": -1, + "assignedPinboards": [], + "assignedGroups": [], + "inheritedGroups": [], + "privileges": [], + "type": "LOCAL_GROUP", + "parenttype": "GROUP", + "visibility": "DEFAULT", + "tenantId": "982d6da9-9cd1-479e-b9a6-35aa05f9282a", + "displayName": "Test Group3", + "header": { + "id": "2364bf7c-7eec-4839-ac4b-e0cbb27aec37", + "indexVersion": 95, + "generationNum": 95, + "name": "TestGroup3", + "displayName": "Test Group3", + "author": "59481331-ee53-42be-a548-bd87be6ddd4a", + "created": 1634527727318, + "modified": 1634527727318, + "modifiedBy": "59481331-ee53-42be-a548-bd87be6ddd4a", + "owner": "2364bf7c-7eec-4839-ac4b-e0cbb27aec37", + "isDeleted": false, + "isHidden": false, + "tags": [], + "type": "LOCAL_GROUP", + "isExternal": false, + "isDeprecated": false + }, + "complete": true, + "incompleteDetail": [], + "isSystemPrincipal": false + }, + { + "userGroupContent": {}, + "groupIdx": 2, + "metadataVersion": -1, + "assignedPinboards": [], + "assignedGroups": [], + "inheritedGroups": [], + "privileges": [], + "type": "LOCAL_GROUP", + "parenttype": "GROUP", + "visibility": "DEFAULT", + "tenantId": "982d6da9-9cd1-479e-b9a6-35aa05f9282a", + "displayName": "Test Group2", + "header": { + "id": "2e3f697a-e38d-4d50-b5c5-e2514e85d90e", + "indexVersion": 94, + "generationNum": 94, + "name": "TestGroup2", + "displayName": "Test Group2", + "author": "59481331-ee53-42be-a548-bd87be6ddd4a", + "created": 1634527708775, + "modified": 1634527708775, + "modifiedBy": "59481331-ee53-42be-a548-bd87be6ddd4a", + "owner": "2e3f697a-e38d-4d50-b5c5-e2514e85d90e", + "isDeleted": false, + "isHidden": false, + "tags": [], + "type": "LOCAL_GROUP", + "isExternal": false, + "isDeprecated": false + }, + "complete": true, + "incompleteDetail": [], + "isSystemPrincipal": false + } +] +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**200**| Successful operation +|**400**| Invalid parameter +|=== + +[#editGroupsforUser] +== Update group association for a user + +To update the user group data for a specific user, send a `PUT` request to the `/tspublic/v1/user/{userid}/groups` API endpoint. + +=== Resource URL + +---- +PUT /tspublic/v1/user/{userid}/groups +---- + +=== Request parameters + +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Parameter Type|Description +|`userid`|path|__String__. The GUID of the user that you want to modify. +|`groupids`|query|__String__. A JSON array of the GUIDs of the user groups that you want to add or modify for the specified user. +|=== + +=== Example request + +.cURL +[source, cURL] +---- +curl -X PUT \ +--header 'Content-Type: application/json' \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ +'https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups?groupids=%5B%222e3f697a-e38d-4d50-b5c5-e2514e85d90e%22%2C%222364bf7c-7eec-4839-ac4b-e0cbb27aec37%22%2C%2246fc2125-d424-40bd-9513-23cd5e2e92c3%22%5D' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups?groupids=%5B%222e3f697a-e38d-4d50-b5c5-e2514e85d90e%22%2C%222364bf7c-7eec-4839-ac4b-e0cbb27aec37%22%2C%2246fc2125-d424-40bd-9513-23cd5e2e92c3%22%5D +---- + +=== Example response + +If the user group update operation is successful, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204**| Successful operation +|**400**| Invalid parameter +|=== + +[#removeUserGroupAssoc] + +== Remove a user from user groups + +To remove the existing group assignments for a user, send a `DELETE` request to the `/tspublic/v1/user/{userid}/groups` API endpoint. + +=== Resource URL + +---- +DELETE /tspublic/v1/user/{userid}/groups +---- + +=== Request parameters + +[width="100%" cols="1,1,4"] +[options='header'] +|=== +|Parameter|Parameter Type|Description +|`userid`|path|__String__. The GUID of the user from which you want to delete the user group association. +|`groupids`|query|__String__. A JSON array of the GUIDs of the user groups from which you want to remove the specified user object. +|=== + +=== Example request + +.cURL +[source,cURL] +---- +curl -X DELETE \ +--header 'Accept: application/json' \ +--header 'X-Requested-By: ThoughtSpot' \ 'https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups?groupids=%5B%222e3f697a-e38d-4d50-b5c5-e2514e85d90e%22%2C%222364bf7c-7eec-4839-ac4b-e0cbb27aec37%22%5D' +---- + +.Request URL +---- +https:///callosum/v1/tspublic/v1/user/a8aeda00-dc3c-4485-b8d1-fd6ac701a819/groups?groupids=%5B%222e3f697a-e38d-4d50-b5c5-e2514e85d90e%22%2C%222364bf7c-7eec-4839-ac4b-e0cbb27aec37%22%5D +---- + +=== Example response + +If the user is removed from specified user groups, the API returns the following response: + +---- +Response Code +204 +---- + +=== Response codes +[width="100%" cols="2,4"] +[options='header'] +|=== +|HTTP status code|Description +|**204**| Successful operation +|**400**| Invalid parameter +|=== diff --git a/docs/src/asciidocs/user-roles.adoc b/docs/src/asciidocs/user-roles.adoc new file mode 100644 index 000000000..c688e2f0a --- /dev/null +++ b/docs/src/asciidocs/user-roles.adoc @@ -0,0 +1,80 @@ += Developer access +:toc: true + +:page-title: User configuration +:page-pageid: developer-access +:page-description: Configure users and groups with developer privileges + +You will require a user account with `Developer` privilege to perform the following tasks in ThoughtSpot: + +* Access the *Develop* tab in ThoughtSpot application. +* Customize and rebrand the look and feel of ThoughtSpot UI. +* Add custom actions to a Liveboard or visualization. +* Customize the format of links used in system-generated emails and notifications. +* Configure visual embed hosts for CORS and CSP. + +ThoughtSpot administrators can create a user group with `Developer` privilege enabled and assign users to this group. Administrators can configure developer access either using the *Admin* tab in the UI or the Group REST APIs. + +The following sections describe how to configure developer access using the *Admin* tab in the UI. +For information about managing users and groups using REST APIs, see xref:group-api.adoc[Group APIs] and xref:user-api.adoc[User APIs]. + +== Add a user group for developers +To add a user group with developer privileges: + +. Log in to ThoughtSpot as an admin user. +. Go to *Admin* > *User management* > *Groups*. + ++ +The group configuration page appears. + +. Click *+ Add Group*. +. In the *Add a new group* dialog, enter the following details: ++ +Group name:: +Name of the group. For example, `Developer Group`. +Display name:: +Name of the group as it appears in ThoughtSpot. For example, `Embed Developer`. +Sharing visibility:: +Specify if users can share objects with this group. When set to `SHAREABLE`, ThoughtSpot allows other users to share objects with the members of this group. +Description:: +__Optional__. Enter a description for the group. +Privileges:: +Select the *Has Developer privilege* checkbox. +. Click *Add*. + +== Assign a user to a developer group + +To assign a user to a developer group: + +. Log in to ThoughtSpot. +. Go to *Admin* > *Users management* > *Users*. ++ +The user configuration page appears. + +. Click *+ Add User*. +. In the *Add a new user* dialog, enter the following details: ++ +Username:: +A unique login name for the user. Usernames must be in lowercase. +Display name:: +A unique name for the user. For example, the first and last name of the user. +Sharing visibility:: +Specify if other users can share objects with this user. When set to *SHAREABLE*, this user is visible in the *Share* dialog when another user tries to share an object. +Change password:: +A password for the user account. +Confirm password:: +Enter the password again. +Email:: +The user's email address. ThoughtSpot uses this email address for notifications. +[NOTE] +Make sure the domain address of the email provider is added to the CSP allowed list on the *Develop* > *Security Settings* page. + +Send a welcome email:: +__Optional__. When checked, this option ensures that the new user receives a welcome email. + +Email message text:: +__Optional__. Enter the text to use in the welcome email. +Groups:: +Select a group that has the Developer privilege enabled. + +. Click *Add*. diff --git a/docs/src/asciidocs/version_control.adoc b/docs/src/asciidocs/version_control.adoc new file mode 100644 index 000000000..d2be5f848 --- /dev/null +++ b/docs/src/asciidocs/version_control.adoc @@ -0,0 +1,375 @@ += Git integration and version control +:toc: true +:toclevels: 2 + +:page-title: Version control and Git integration +:page-pageid: git-integration +:page-description: The version control APIs and Git integration capability let you connect your ThoughtSpot instance to a Git repository, push changes, and deploy commits to your ThoughtSpot environment. + +When embedding or deploying a third-party application in their environments, most organizations use defined practices at various stages of their SDLC process. Developers typically use a version control system and CI-CD pipeline to push their code from development to testing and production environments. Similarly, when deploying ThoughtSpot, you may want to publish your ThoughtSpot content from a development environment to a staging or production cluster. + +ThoughtSpot objects such as Tables, Worksheets, Liveboards, and Answers are stored as link:https://cloud-docs.thoughtspot.com/admin/ts-cloud/tml.html[ThoughtSpot Modeling Language (TML), window=_blank] content. Users can download these TML files, edit these files locally, and import the updated content into ThoughtSpot. TML files are also useful when migrating content from one ThoughtSpot instance to another. + +With The Git integration [beta betaBackground]^Beta^ feature, ThoughtSpot provides the ability to connect your deployment instance to a Git repository, push TML files to CI/CD pipelines, and deploy commits from your Git repository to your production environment. + +== Git integration overview + +The Git integration [beta betaBackground]^Beta^ feature supports the following capabilities: + +* ThoughtSpot integration with Git and CI/CD workflows ++ +Ability to connect your ThoughtSpot instance to a Git repository and deploy commits via REST API. +* Ability to version control ThoughtSpot content ++ +Ability to build or modify your content locally on a development instance and push commits to a remote Git branch via APIs and version your updates. + +* Ability to address different types of deployment scenarios ++ +The simplest deployment scenario is moving content from a ThoughtSpot development instance to a production instance. + +//// +You can also deploy multiple environments on the same ThoughtSpot instance using the xref:orgs.adoc[Orgs] feature. For example, you can create separate Orgs for `Dev`, `Staging`, and `Prod` environments. The content built from the `Dev` Org can be deployed on `Staging` and `Prod` Orgs using REST API v2.0 version control endpoints. +//// + +== How it works + +The ThoughtSpot content deployment process with version control APIs and Git integration includes the following steps: + +1. xref:version_control.adoc#_enable_git_integration[Enable Git integration on ThoughtSpot]. +2. xref:version_control.adoc#connectTS[Connect your ThoughtSpot `Dev` and `Prod` environments to the `dev` and `production` branches on your Git repository]. + +The general practice is to use the `main` branch in your Git repository as a production branch to publish the release content. +3. xref:version_control.adoc#_commit_tml_files_to_git[Push your changes to the Git branch mapped to the `Dev` environment]. + ++ +ThoughtSpot users with edit access to the objects can modify their Liveboard, Answers, Worksheets, and Tables. However, to push the updated content and deploy commits via REST API, you need administrator privileges. +4. On the Git repository, xref:version_control.adoc#_merge_updates_from_dev_branch_to_main_in_git[create a pull request to merge your changes from the `dev` branch to `main`]. +5. xref:version_control.adoc[Deploy commits from the `main` branch to your `Prod` environment] and publish your changes. + +The following figure illustrates a simple Git integration workflow with ThoughtSpot `Dev` and `Prod` environments. + +image::./images/git-integration-workflow.svg[Git integration workflow] + +== Get started + +Before you begin, check the following prerequisites: + +* You have administrator access (*Can administer ThoughtSpot* privilege) to connect ThoughtSpot to a Git repository and deploy commits. +* You have a GitHub or GitHub Enterprise account and access to a repository. Ensure that your account has one of the following types of access tokens: + +** link:https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#personal-access-tokens-classic[Personal access token (Classic), window=_blank] ++ +Make sure the access token has the `repo` scope that grants full access to public and private repositories, commit and deployment status, repository invitations, and security events. + +** link:https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#fine-grained-personal-access-tokens[Fine-grained personal access token, window=_blank] ++ +Make sure the token allows `Read access to metadata` and `Read and Write access to code and commit statuses`. + +* Your Git repository has a branch that can be used as a default branch in ThoughtSpot. + + +=== Enable Git integration + +To configure Git branches and workflows, the Git integration feature must be enabled on your ThoughtSpot `Dev` and `Prod` environments. To enable this feature on your instance, contact ThoughtSpot Support. + +//// +Run the following `tscli` command on their instances. + +[source,SSH] +---- +tscli git-integration enable +---- +//// + +[#connectTS] +=== Connect your ThoughtSpot environment to a Git repository + +To connect your ThoughtSpot instance to a Git repository using REST API, send a `POST` request with the following parameters to the `/api/rest/2.0/vcs/git/config/create` REST API v2.0 endpoint. + +==== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Parameter|Description +|`repository_url`|__String__. URL of the Git repository. +|`username` +|__String__. Username to authenticate to the Git repository. +|`access_token`|__String__. Access token to authenticate to the Git repository. +|`branch_names`|__Array of strings__. List of Git branches to configure. +|`default_branch_name` + +__Optional__|__String__. Specify the default Git branch used for all operations on the cluster. +|`enable_guid_mapping` + +__Optional__ |__Boolean__. When set to `true`, ThoughtSpot maps the GUID of the TML objects on the deployment instance and generates a GUID mapping file in the specified Git branch. For more information, see xref:version_control.adoc#_guid_mapping[GUID mapping]. +|`guid_mapping_branch_name` + +__Optional__|__String__. Specify the name of the Git branch to which you want to add the GUID mapping file. +If no branch is specified, the branch name specified in the `default_branch_name` for this configuration will be considered. ThoughtSpot recommends using a separate Git branch to maintain the GUID mapping file. +|=== + +==== Request example + +The following example shows the API request format for connecting ThoughtSpot to a GitHub repository. + +[source, cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host-Dev}/api/rest/2.0/vcs/git/config/create' \ + -H 'Authorization: Bearer {Bearer_token} \ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "repository_url": "https://github.com/ts-git-user/gitdemo", + "username": "ts-git-user", + "access_token": "{ACCESS_TOKEN}", + "branch_names": [ + "dev", + "main" + ], + "default_branch_name": "dev" +}' +---- + +If the API request is successful, the ThoughtSpot instance will be connected to the Git repository. Make sure you connect all your environments (`Dev`, `Staging`, and `Prod`) to the GitHub repository. + +The following example shows the API request parameters to connect a ThoughtSpot `Prod` instance to the Git repo. Note that GUID mapping is enabled in the API request. + +[source, cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host-Prod}/api/rest/2.0/vcs/git/config/create' \ + -H 'Authorization: Bearer {Bearer_token} \ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "repository_url": "https://github.com/ts-git-user/gitdemo", + "username": "ts-git-user", + "access_token": "{ACCESS_TOKEN}", + "enable_guid_mapping": true, + "branch_names": [ + "prod" + ], + "default_branch_name": "main", + "guid_mapping_branch_name": "config" +}' +---- + +* To update the repository details or access token, send a `POST` request with Git configuration parameters to the `/api/rest/2.0/vcs/git/config/update` API endpoint. +* To get repository configuration information, send a `POST` request to `/api/rest/2.0/vcs/git/config/search` API endpoint. +* To delete the repository configuration, send a `POST` request to the `/api/rest/2.0/vcs/git/config/delete` endpoint. + +For more information about these endpoints, see the API documentation in the +++REST API v2.0 Playground+++. + +=== GUID mapping + +Every object in ThoughtSpot is assigned a unique *GUID* as a reference. When deploying TML files, if the TML representation does not have the same GUIDs for objects on the source and destination instances, it's essential to track the newly created object GUIDs on the destination environment with the GUID of the objects imported from the source cluster. + +Starting from the 9.4.0.cl release, the version control API automatically generates a GUID mapping file when deploying commits and saves this file in a Git branch. The mapping file records the GUIDs for each TML object as shown in this example: + +[source,JSON] +---- +[ + { + "originalGuid":"7485d3b6-4b4e-41a2-86be-e031d1322cc9", + "mappedGuid":"3eeec11e-fbf7-40dc-a549-2f465f640778", + "counter":0 + } +] +---- + +* `originalGuid` refers to the GUID of the object on the source environment, for example, a `Dev` cluster. +* `mappedGuid` refers to the GUID of the object on the destination environment, for example, `staging` or `prod` cluster. +* `counter` shows the number of times the mapped object was used in deploy operations. + +If GUID mapping is enabled, ThoughtSpot uses the GUID mapping file to map the object GUIDs and automatically update the object references in your TML content. + +//// +The following figure illustrates the GUID mapping during deployments: +[.bordered] +image::./images/guid-mapping.png[GUID mapping] +//// + +=== Commit TML files to Git + +Your application users can create and modify their Liveboards, Answers, Connections, Worksheets, and Tables. These objects are stored as TML representations in ThoughtSpot. Users with data management (*Can manage data*) privilege can download these objects as TML files to their local environment, xref:modify-tml.adoc[edit TML files], and import them into ThoughtSpot via UI or REST API. Administrators can push the TML files from a ThoughtSpot instance to the default Git branch using REST API. + +To commit the updates to a branch in Git repository via REST API, you need administrator (*Can administer ThoughtSpot*) privilege. + +To commit TML objects to a branch in Git, send a `POST` request with the following parameters to the `/api/rest/2.0/vcs/git/branches/commit` API endpoint. + +==== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Parameter|Description +|`metadata`|__Array of Strings__. Specify the `type` and GUID of the metadata object. +|`branch_name` + +__Optional__|__String__. Name of the branch in the Git repository to which you want to push the commit. If you do not specify the branch name, the commit will be pushed to the default branch. +|`comment`|__String__. Add a comment to the commit. +|=== + +==== Request example + +The following example shows the API request with Liveboard and Worksheet objects to commit to Git. + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/vcs/git/branches/commit' \ + -H 'Authorization: Bearer {Bearer_token}\ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata": [ + { + "identifier": "e9d54c69-d2c1-446d-9529-544759427075", + "type": "LIVEBOARD" + }, + { + "identifier": "cd252e5c-b552-49a8-821d-3eadaa049cca", + "type": "LOGICAL_TABLE" + } + ], + "comment": "Add objects", + "branch_name": "dev" +}' +---- + +If the API request is successful, the objects will be added to the specified GitHub branch. When the TML objects are added to a Git branch, subsequent commits to that branch from ThoughtSpot update the objects in the Git repository. + +When committing, if there are no changes detected between the current version in Git, and the version being committed from the ThoughtSpot instance, the API call will succeed, but a warning message is returned with a list of objects that were not updated as part of the commit. + +ThoughtSpot provides a REST API endpoint to search commits for a given TML object. A `POST` call to the `/api/rest/2.0/vcs/git/commits/search` endpoint with `metadata` identifier and `type` in the request body fetches a list of commits. + +==== Steps to revert a commit +To undo the changes committed to a repository, revert to a previous commit and restore an earlier version of an object using the `/v2/vcs/commits/{commit_id}/revert` API endpoint. + +===== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Parameter|Description +|`commit_id`|__String__. ID of the commit to which you want to revert. +|`metadata` + +__Optional__|__Array of Strings__. Specify the `type` and GUID of the metadata object. If a metadata object is not specified, the API request reverts all objects that were modified as part of the specified `commit_id`. +|`branch_name` + +__Optional__|__String__. Name of the branch to which the revert operation must be applied. If you do not specify the branch name, the API will revert the commit to the default branch configured on that ThoughtSpot instance. +|`revert_policy` a|__String__. Action to apply when reverting a commit. The allowed values are: + + +* `ALL_OR_NONE` (Default) + +Reverts all objects. If the revert operation fails for one of the objects provided in the commit, the API returns an error and does not revert any object. + +* `PARTIAL` + +Reverts partial objects. This option reverts the subset of ThoughtSpot objects that validate successfully even if the other objects in the specified commit fail to import. +|=== + +==== Request example + +The following example shows the API request for reverting a commit. + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/vcs/git/commits/afc0fea831558e30d7064ab019f49243b1f09552/revert' \ + -H 'Authorization: Bearer {Bearer_token}\\ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "metadata": [ + { + "identifier": "e9d54c69-d2c1-446d-9529-544759427075", + "type": "LIVEBOARD" + } + ], + "commit_id": "afc0fea831558e30d7064ab019f49243b1f09552", + "branch_name": "dev" +}' +---- + +If the API request is successful, the Git branch is reverted to the specified commit ID. + +=== Merge updates from `dev` branch to `main` in Git + +To merge updates, create a pull request to push changes from your `dev` branch to `main`. ThoughtSpot doesn't provide REST APIs to merge content from one branch to another. Before accepting the merge request in the Git repository, you can validate the merge on your ThoughtSpot instance using REST API. + +To validate the content of your `dev` branch against your `prod` environment, send a `POST` request from your `prod` instance to the `/api/rest/2.0/vcs/git/branches/validate` API endpoint. + +==== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Parameter|Description +|`source_branch_name`|__String__. Name of the source branch from which changes need to be picked for validation. +|`target_branch_name`|__String__. Name of the target branch into which the TML changes will be merged. +|=== + +==== Request example + +The following example shows the API request with Liveboard and Worksheet objects to commit to Git. + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/vcs/git/branches/validate' \ + -H 'Authorization: Bearer {Bearer_token}\ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "source_branch_name": "dev", + "target_branch_name": "main" +}' +---- + +After validating the merge, check for conflicts. Resolve issues if any with a new commit and merge your changes to the `main` branch. + +=== Deploy commits + +To deploy commits to the `Staging` or `Prod` instance, send a `POST` request to the `/api/rest/2.0/vcs/git/commits/deploy` API endpoint. The API will deploy the head of the branch unless a `commit_id` is specified in the API request. + +Building a release version for a `Prod` environment on the same instance requires swapping in the correct GUIDs. If you have enabled xref:_guid_mapping[GUID mapping] in the Git configuration on your deployment instance, the version control APIs will automatically generate a GUID mapping file and update object references when deploying your commits to the destination environment. + +//// +Make sure the *guid mapping file* is referenced when creating the final TML files for production rollout. +//// + +==== Request parameters +[width="100%" cols="1,4"] +[options='header'] +|=== +|Parameter|Description +|`commit_id` + +__Optional__|__String__. ID of the commit to deploy on the cluster. By default, the command will deploy the head of the branch. To deploy a specific version, specify the `commit_id`. +|`branch_name` + +__Optional__|__String__. Name of the branch from the changes must be deployed. If you do not specify the branch name, the commit from the default branch is deployed. +|`deploy_type` a| __String__. Specify one of the following options: + + +* `DELTA` (default) + +Deploys only the changes that were applied at the specified `commit_id`. For example, if three TML files were updated in the `commit_id` specified in the API request, only those changes will be deployed. +* `FULL` + +Deploys all the files in the Git branch, including the files from the `commit_id` specified in the request and all other files that were already committed. + +|`deploy_policy` a|__String__. Action to apply when deploying a commit. The allowed values are: + + +* `ALL_OR_NONE` (Default) + +Deploys all changes or none. This option cancels the deployment of all ThoughtSpot objects if at least one of them fails to import. + +* `PARTIAL` + +Deploys partial objects. This option imports the subset of ThoughtSpot objects that validate successfully even if other objects in the same deploy operations fail to import. +|=== + + +==== Request example + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/vcs/git/commits/deploy' \ + -H 'Authorization: Bearer {Bearer_token}'\ + -H 'Accept: application/json'\ + -H 'Content-Type: application/json' \ + --data-raw '{ + "import_type": "DELTA", + "deploy_type": "DELTA", + "deploy_policy": "ALL_OR_NONE", + "commit_id": "afc0fea831558e30d7064ab019f49243b1f09552", + "branch_name": "main" +}' +---- + +If the API request is successful, the changes are applied to the objects in the `prod` environment. \ No newline at end of file diff --git a/docs/src/asciidocs/visual-embed-sdk.adoc b/docs/src/asciidocs/visual-embed-sdk.adoc new file mode 100644 index 000000000..b5dc429b6 --- /dev/null +++ b/docs/src/asciidocs/visual-embed-sdk.adoc @@ -0,0 +1,105 @@ += Visual Embed SDK +:toc: true + +:page-title: Visual Embed SDK overview +:page-pageid: visual-embed-sdk +:page-description: Visual Embed SDK provides a set of APIs to embed and customize ThoughtSpot elements in your app. + +The Visual Embed SDK provides a Javascript library to embed ThoughtSpot elements in your host application. + +You can use the Visual Embed SDK for the following purposes: + +* Embed specific components of the ThoughtSpot application; for example, search, Liveboards, and visualizations. +* Render full ThoughtSpot application within a host application. + +Refer to the following articles for more information: + +[div boxDiv boxFullWidth] +-- ++++
Integration guidelines
+++ + +Read the xref:integration-overview.adoc[integration guidelines] to understand the embedding requirements and recommendations. + +-- + +[div boxDiv boxFullWidth] +-- ++++
Security settings
+++ + +Before you get started, xref:security-settings.adoc[add your application domain to the CORS and CSP allowed list] and set your application as a trusted host for secure data exchange. +-- + +[div boxDiv boxFullWidth] +-- ++++
Get Started
+++ + +Download the Visual Embed SDK package, set up your application environment, and xref:getting-started.adoc[get started with embedding]. +-- + +[div boxDiv boxFullWidth] +-- ++++
Configure authentication method
+++ + +Learn how to set up xref:configure-saml.adoc[SAML SSO] or xref:trusted-authentication.adoc[trusted authentication service], and xref:embed-authentication.adoc[configure authentication methods in SDK] to authenticate your application users. + +-- + +[div boxDiv boxFullWidth] +-- ++++
Embed search
+++ + +Learn how to embed xref:embed-searchbar.adoc[ThoughtSpot Search bar] and xref:embed-search.adoc[Search page elements] in your application. +-- + +[div boxDiv boxFullWidth] +-- ++++
Embed a visualization
+++ + +Learn how to xref:embed-a-viz.adoc[embed a ThoughtSpot visualization] in your application. + +-- + +[div boxDiv boxFullWidth] +-- ++++
Embed a Liveboard
+++ + +Learn how to xref:embed-pinboard.adoc[render Liveboards and apply runtime controls on visualizations] embedded in your application. +-- + +[div boxDiv boxFullWidth] +-- ++++
Embed full ThoughtSpot experience
+++ + +Learn how to xref:full-embed.adoc[embed full ThoughtSpot experience] in your application. + +-- + + +[div boxDiv boxFullWidth] +-- ++++
Embed ThoughtSpot in a React app
+++ + +Learn how to xref:embed-ts-react-app.adoc[Embed ThoughtSpot in a React app]. +-- + + +[div boxDiv boxFullWidth] +-- ++++
Customize your embedded view
+++ + +* Learn how to xref:embed-events.adoc[register event handlers, trigger and interact with events]. +* xref:embed-actions.adoc[Show or hide menu actions] +* Configure xref:custom-actions.adoc[custom actions] +* xref:style-customization.adoc[Customize styles and UI layout] +-- + +== Useful resources + +[div boxDiv boxFullWidth] +-- + +* link:{{visualEmbedSDKPrefix}}/modules.html[Visual Embed SDK Reference Guide, window=_blank] +* link:https://developers.thoughtspot.com/guides[Visual Embed Tutorials] +* link:https://github.com/thoughtspot/visual-embed-sdk[Visual Embed SDK GitHub repository, window=_blank] +* link:https://github.com/thoughtspot/ts_everywhere_resources[ThoughtSpot Everywhere Resources on GitHub, window=_blank] +-- diff --git a/docs/src/asciidocs/whats-new.adoc b/docs/src/asciidocs/whats-new.adoc new file mode 100644 index 000000000..0f5b53cf0 --- /dev/null +++ b/docs/src/asciidocs/whats-new.adoc @@ -0,0 +1,1382 @@ += What's new +:toc: true +:toclevels: 1 + +:page-title: What's new +:page-pageid: whats-new +:page-description: New features and enhancements + +This page provides information about new features, enhancements, and deprecated functionality in ThoughtSpot Everywhere. + +== Version 9.4.0.cl + +=== Version control and Git integration [beta betaBackground]^Beta^ + +GUID mapping:: + +If a TML file on your source environment contains GUIDs that don't match the GUIDs on your destination environment, the version control APIs can now automatically handle the mapping of GUIDs when deploying the TML content. + ++ +For more information, see xref:version_control.adoc#_guid_mapping[Git integration and version control]. + +Folder structure changes [tag redBackground]#BREAKING CHANGE#:: + +The folder structure of the TML objects in the Git repository is modified in 9.4.0.cl. In earlier releases, the TML objects were stored in the object directory of the `primary` root folder, for example `primary/liveboard`. Starting from 9.4.0.cl, the TML objects will be stored in the object folder at the root level. ThoughtSpot will not migrate your existing TML files from `primary/` to the new folder structure. You must move these files to the respective object directory at the root level. + +File naming convention [tag redBackground]#BREAKING CHANGE#:: +Starting from 9.4.0.cl, the TML files pushed to a Git branch from a ThoughtSpot instance are named in the +`..tml` format. The earlier releases used the `..tml` naming convention for TML files. This change may break your current setup. We recommend that you reconfigure the Git connection on your ThoughtSpot instance and start using the version control feature from scratch. + +=== Security settings enhancements for Orgs + +CORS settings per Org:: + +On multi-tenant clusters with Orgs, developers can now add a list of CORS hosts at the Org level. For more information, see xref:security-settings.adoc#cors-hosts[Security Settings]. + +Block user access to non-embedded application pages:: + +ThoughtSpot administrators and developers can now enable the **Block non-embed full app access** feature at the Org level. + +For more information, see xref:security-settings.adoc#_block_access_to_non_embedded_thoughtspot_pages[Security Settings]. + +=== Visual Embed SDK + +For information about the new features and enhancements introduced in Visual Embed SDK version 1.23.0, see xref:api-changelog.adoc[Visual Embed changelog]. + +=== REST API + +For information about REST API enhancements, see xref:rest-apiv1-changelog.adoc[REST API v1 changelog] and xref:rest-apiv2-changelog.adoc[REST API v2.0 changelog]. + +== Version 9.3.0.cl + +=== Support for cookieless authentication + +Developers can now enable cookieless authentication when embedding ThoughtSpot in their applications. The cookieless authentication method allows using a bearer token instead of session cookies when users interact with embedded content or initiate API requests. If the embedded content does not load from the same domain as your embedding application, and your Web browser does not allow third-party cookies, you can use Cookieless authentication in the Trusted authentication mode. + +For more information, see xref:embed-authentication.adoc#trusted-auth-embed[Trusted authentication]. + +=== Idle sensing and APIs for managing cluster states + +ThoughtSpot Cloud clusters support idle sensing in embedded deployments. With idle sensing enabled on your embedded ThoughtSpot instance, your instance becomes inactive if there is no active user session detected for a period of 120 minutes. You can restart an inactive cluster using API when required. + +For more information, see xref:tse-eco-mode.adoc[Manage your cluster state]. + +=== Per-Org style customization + +The *Develop* tab now allows customizing UI styles and layout at the Org level. To enable this feature on your multi-tenant instance, contact ThoughtSpot support. + +For more information, see xref:style-customization.adoc#_custom_styles_for_orgs_on_multi_tenant_clusters[Custom styles for Orgs on multi-tenant clusters]. + +=== Version control and Git integration via REST API [beta betaBackground]^Beta^ +You can now connect your ThoughtSpot instance to a Git repository and push commits from your application instance to a Git branch via REST API. With the Git integration [beta betaBackground]^Beta^ feature, ThoughtSpot provides the ability to integrate your application environment with Git workflows and deploy commits from a development instance to a production cluster. + +For more information, see xref:version_control.adoc[Version control with Git integration]. + +=== Visual Embed Playground enhancements + +The Visual Embed developer Playground now includes a *Try* button in the preview panel. The *Try* button is attached to an event handler. You can register a host event and click *Try* to trigger an action on the embedded page in the Playground. + +For more information, see xref:events-ref.adoc#host-events[Events reference]. + +=== Visual Embed SDK + +For information about the new features and enhancements introduced in Visual Embed SDK versions 1.22.0, see xref:api-changelog.adoc[Visual Embed changelog]. + +=== REST API + +For information about REST API enhancements, see xref:rest-apiv1-changelog.adoc[REST API v1 changelog] and xref:rest-apiv2-changelog.adoc[REST API v2.0 changelog]. + +== Version 9.2.0.cl + +.Per-Org secret key and tokens for Trusted authentication + +[%collapsible] +==== +ThoughtSpot now supports generating secret keys per Org. Org administrators can generate a secret key for trusted authentication in their Org context and allow their Org users to obtain authentication tokens using this secret key. + +Starting from 9.2.0.cl, Org users require Org-specific authentication tokens issued for their user accounts when switching between Orgs. When generating an authentication token via REST API, make sure to request separate tokens for each Org context. + +For more information, see xref:trusted-authentication.adoc#trusted-auth-enable[Trusted authentication]. +==== + +.Custom styles + +[%collapsible] +==== +The 9.2.0.cl release introduces the following new variables for custom styling of the ThoughtSpot Search page: + +* `--ts-var-search-auto-complete-font-color` +* `--ts-var-search-auto-complete-subtext-font-color` +* `--ts-var-answer-edit-panel-background-color` + +For more information, see xref:css-customization.adoc#_search_bar_and_data_panel[Customize CSS]. +==== + +.GraphQL playground [beta betaBackground]^Beta^ +[%collapsible] +==== +The *Develop* tab in the ThoughtSpot UI introduces the GraphQL playground to allow users to interact with GraphQL endpoints and run query and mutation operations. To enable this feature on your instance, contact ThoughtSpot Support. + +For more information, see xref:graphql-playground.adoc[GraphQL Playground]. +==== +.Runtime Parameter overrides +[%collapsible] +==== +Embedded application users can now create Worksheet and Answer Parameters to optimize data queries. You can also adjust values and apply overrides at runtime on a Liveboard or Answer either via REST API or by appending Parameters to the query URL in the UI. + +For more information, see xref:runtime-parameters.adoc[Runtime Parameter overrides]. +==== +.Link customization +[%collapsible] +==== +You can now customize the navigation links in your app using the *Generic link* option in the *Develop* > *Customization* > *Link settings* page. + +For more information, see xref:customize-links.adoc#_customize_link_format[Customize links]. +==== +.Cross filters on Liveboard visualizations [eaTag eaBackground]#Early Access# +[%collapsible] +==== +ThoughtSpot now supports brushing and linking of visualizations on a Liveboard using cross filters. Cross filters allow you to present a coordinated view of a Liveboard by applying filters across all visualizations based on the current selection. + +[NOTE] +The Cross filters feature is turned off by default. To enable this feature on your instance, contact your ThoughtSpot administrator. + +To hide or disable the cross filter feature on an embedded instance, use the `Action.CrossFilter` and `Action.RemoveCrossFilter` parameters in the SDK. For more information, see xref:embed-actions.adoc[Show or hide menu items] and xref:embed-action-ref.adoc#liveboardv2-viz-actions[Action reference]. +[discrete] +=== Contextual menu behavior + +By default, the contextual menu in ThoughtSpot application pages is set as right-click pop-up menu. Starting from 9.2.0.cl, you can set the contextual menu to trigger on left-click. + +To trigger the contextual menu on left-click or right-click on an embedded app, you can use the `contextMenuTrigger` property in the Visual Embed SDK. In the following example, the contextual menu is configured to trigger on left-click. + +---- +contextMenuTrigger: "left-click" +---- + +---- +contextMenuTrigger: ContextMenuTriggerOptions.LEFT_CLICK +---- + +When set as right-click menu (default behavior):: +The contextual menu opens on right-click. If you want to monitor right-click actions and listen to the right-click events on a chart or table, use `EmbedEvent.VizPointRightClick` event. For more information, see xref:events-ref.adoc#_vizpointrightclick[VizPointRightClick]. + +When set as left-click menu:: +The contextual opens on left-click. If your app is already using `EmbedEvent.VizPointClick` to listen to left-click events on a visualization, the `VizPointClick` event will be triggered whenever a user clicks on an action in the contextual menu. If you are using `EmbedEvent.VizPointClick` to trigger actions such as updating runtime filters on a Liveboard visualization, the click events from left-click contextual menu may impact your app’s current workflow. + ++ +We recommend using a development environment to test your customizations before rolling them out on production servers. For more information, contact ThoughtSpot Support. +==== +.Note tiles on Liveboards [eaTag eaBackground]#Early Access# +[%collapsible] +==== +In the new Liveboard experience mode, you can now add Note tiles with custom text, images, and links. This feature is turned off by default and can be enabled by ThoughtSpot administrators. + +For more information, see xref:enable-liveboardv2.adoc#noteTiles[Note tiles]. +==== +.Visual Embed SDK +[%collapsible] +==== +For information about the new features and enhancements introduced in Visual Embed SDK versions 1.20.0 and 1.21.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== +.REST API +[%collapsible] +==== +For information about REST API enhancements, see xref:rest-apiv1-changelog.adoc[REST API v1 changelog] and xref:rest-apiv2-changelog.adoc[REST API v2.0 changelog]. +==== + +== Version 9.0.0.cl + +.New Liveboard experience +[%collapsible] +==== +The xref:enable-liveboardv2.adoc[new Liveboard experience] is now Generally Available (GA) on embedded instances and is enabled by default. +==== + +.New CSS variables for custom styling +[%collapsible] +==== +The CSS customization feature supports new variables to customize the look and feel of the following UI elements: + +* Search bar and navigation panel +* Search suggestion panel +* Dialogs + +For more information, see xref:css-customization.adoc[Customize CSS]. +==== +.REST API v2.0 endpoints and Playground +[%collapsible] +==== +Starting with 9.0.0.cl, the REST API v2 [beta betaBackground]^Beta^ API endpoints are deprecated and removed from the REST API v2 Playground. A set of new endpoints are now generally available (GA) on all ThoughtSpot instances. + +The new REST API v2.0 endpoints introduce several improvements to the request and response structure and let you perform more tasks in a single API call. For example, you can create a new user, map the user to groups and Orgs, set home Liveboards for the user, and assign privileges in a single API request. + +[div announcementBlock] +-- +* All REST API v2 [beta betaBackground]^Beta^ endpoints are deprecated, but remain functional until further notice. The REST API SDK that was available with REST API v2 [beta betaBackground]^Beta^ version is no longer supported. + +ThoughtSpot does not recommend using REST API v2 [beta betaBackground]^Beta^ endpoints for production use cases. For more information, see xref:deprecated-features.adoc#_deprecation_of_rest_v2_api[Deprecation announcements]. +* The new REST API v2.0 endpoints are not an extension of the REST API v2 [beta betaBackground]^Beta^ endpoints. The resource categories, base path, endpoint URIs, and the structure of API requests and responses are different from those of the REST API v2 [beta betaBackground]^Beta^ version. +* Some API operations such as the CRUD operations for data connections and passing runtime filters on Liveboard visualizations are not available in the initial release. For more information, see xref:rest-api-v1v2-comparison.adoc[REST API v1 and v2.0 comparison] and xref:rest-api-v2-reference.adoc[REST API v2.0 reference]. +* For Org CRUD operations in production environments, ThoughtSpot recommends using xref:org-manage-api.adoc[REST API v1 endpoints]. +-- +==== + +.Early Access features +[%collapsible] +==== +Starting from 9.0.0.cl, ThoughtSpot allows its administrators to turn on Early Access features from the Admin portal. Early Access features are qualified by ThoughSpot for customer use but are not enabled by default on ThoughtSpot instances until the features are GA. + +The 9.0.0.cl release introduces the following Early Access features: + +* Custom maps ++ +Allows uploading map files (TopoJSON) to configure custom regions and visualize data on these regions. For more information, see link:https://docs.thoughtspot.com/cloud/latest/geomaps-custom[Upload custom geo maps, window=_blank]. + +* Mandatory filters ++ +Allows setting certain filters as mandatory on a Liveboard. For more information, see link:https://docs.thoughtspot.com/cloud/latest/liveboard-filters-mandatory[Mandatory Liveboard filter, window=_blank]. + +* Chart configuration experience ++ +Allows making multiple edits to a chart configuration and applying all changes at once. For more information, see link:https://docs.thoughtspot.com/cloud/latest/chart-x-axis[Reorder labels on the axis or legend, window=_blank]. + +* Chart data labels ++ +Allows displaying data labels in a lighter color on charts with a dark background. For more information, see link:https://docs.thoughtspot.com/cloud/latest/chart-data-labels[Show data labels, window=_blank]. +==== + +.Visual Embed SDK version 1.19.0 +[%collapsible] +==== +For information about the new features and enhancements introduced in Visual Embed SDK version 1.19.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.REST API +[%collapsible] +==== +For information about REST API v1 enhancements, see xref:rest-apiv1-changelog.adoc[REST API v1 changelog]. +==== + +== Version 8.10.0.cl + +.Ability to embed only the Search bar in an app [beta betaBackground]^Beta^ +[%collapsible] +==== +You can now embed the ThoughtSpot search bar component in your app. For example, if you are using Google Sheets for data analysis, you can embed the ThoughtSpot search bar and let your users search data from a specific data source. The embedded Search bar allows passing search tokens and modifying search options. You can also retrieve the search results as raw data and let your host application render it in the format you want. + +For more information, see xref:embed-searchbar.adoc[Embed ThoughtSpot search bar]. +==== + +.Advanced style customization with custom CSS +[%collapsible] +==== +The CSS customization feature supports new variables to customize the look and feel of the following UI elements: + +* Search data button in the navigation panel +* Font type and text style of search tokens +* Data panel on the Search and saved Answer pages +* Filter chips on Liveboard, visualizations, and Answer pages +* Menu components +* X-axis and Y-axis titles and labels on charts + +For more information, see xref:css-customization.adoc[Customize CSS]. +==== + +.CSP allowlist for font, image and stylesheet sources +[%collapsible] +==== +You can now enable CSP overrides for font, stylesheet, and image sources in ThoughtSpot UI. If you want to load fonts, stylesheets, images, or favicons from an external source, add the source URLs to the CSP allowlist on the *Security Settings* page. + +For more information, see xref:security-settings.adoc#_add_trusted_domains_for_font_css_and_image_import[Security Settings]. +==== + +.Multi-tenancy with Orgs +[%collapsible] +==== +You can now set up your ThoughtSpot Cloud instance as a multi-tenant cluster and partition it into logical and isolated workspaces called *Orgs*. Each Org can have its own users, groups, and metadata, and stay independent of and invisible to other Orgs configured on the same application instance. + +For more information, see xref:orgs.adoc[Multi-tenancy with Orgs]. +==== + +.Visual Embed SDK version 1.18.0 +[%collapsible] +==== +For information about the new features and enhancements introduced in Visual Embed SDK version 1.18.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.REST API +[%collapsible] +==== +For information about REST API v1 enhancements, see xref:rest-apiv1-changelog.adoc[REST API changelog]. +==== + +== Version 8.9.0.cl + +.Improvements to authentication methods and AuthType enums in the SDK +[%collapsible] +==== +The following changes are introduced in the Visual Embed SDK to improve the authentication framework and options for embedded application users: + +* New auth type enum for embedded SSO authentication ++ +The `AuthType.EmbeddedSSO` enum allows you to enable SSO login on embedded instances. This authentication method allows you to use your current SAML IdP or OpenID Connect configuration and redirect users to the IdP for authentication within the embedded iFrame. + +* Changes to the existing `AuthType` enums: + +** `AuthType.SAML` is renamed as `AuthType.SAMLRedirect` + +** `AuthType.OIDC` is renamed as `AuthType.OIDCRedirect` + +** `AuthType.AuthServer` is renamed to `AuthType.TrustedAuthToken` + + +For more information, see xref:embed-authentication.adoc[Authentication]. +==== + +.Just-in-time user creation and dynamic privilege assignment +[%collapsible] +==== +Starting from 8.9.0.cl, the xref:session-api.adoc#session-authToken[/tspublic/v1/session/auth/token] endpoint supports just-in-time provisioning of users. If the user specified in the API request does not exist in the ThoughtSpot system, you can set the `autocreate` property to `true` to add the user to ThoughtSpot and assign the user to `groups`. +==== +.Advanced style customization [beta betaBackground]^Beta^ +[%collapsible] +==== +ThoughtSpot now allows you to override style specifications of the embedded UI pages and elements with custom CSS. Custom CSS provides granular control over the design elements and lets you modify the properties of these elements +to match the look and feel of your host application. + +To help users visualize and preview the CSS overrides, the *Visual Embed* playground will include the *Apply custom styles* checkbox, which allows you to explore the variables available for customization. + +For more information, see xref:style-customization.adoc[Customize styles and layout] and xref:css-customization.adoc[Customize CSS using SDK]. + +==== +.Visual Embed SDK version 1.17.0 +[%collapsible] +==== +For information about the new features and enhancements introduced in Visual Embed SDK version 1.17.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== +.REST API +[%collapsible] +==== +For information about REST API v1 enhancements, see xref:rest-apiv1-changelog.adoc[REST API changelog]. +==== + +== Version 8.8.0.cl +.Custom tile size for visualizations on a Liveboard (New Liveboard experience only) +[%collapsible] +==== +ThoughtSpot users can now customize the tile size of a visualization on a Liveboard. In the earlier versions, ThoughtSpot allowed resizing visualizations using predefined layout options available in the *More* menu image:./images/icon-more-10px.png[the more options menu]. With custom tile size, users can now change the size of a visualization just by clicking and dragging the tile to the desired size. + +This feature is in beta and disabled by default on all Thoughtspot instances. To enable this feature on your instance, contact ThoughtSpot Support. +==== +.Visual Embed SDK version 1.16.0 +[%collapsible] +==== +For information about the new features and enhancements introduced in Visual Embed SDK version 1.16.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== +.REST API v1 +[%collapsible] +==== +For information about REST API v1 enhancements, see xref:rest-apiv1-changelog.adoc[REST API changelog]. +==== +.Bug fixes and improvements +[%collapsible] +==== +Bug fixes and new improvements in embedded user experience. + +For more information, see xref:fixed-issues.adoc[Fixed issues]. +==== + +== Version 8.7.0.cl + +.Liveboard tabs +[%collapsible] +==== +The new Liveboard experience[beta betaBackground]^Beta^ now supports organizing visualizations in tabs. Users with edit access to a Liveboard can add, edit, and move visualizations to tabs on a Liveboard. On embedded ThoughtSpot instances, developers can set a specific tab as an active tab using the Visual Embed SDK. + +This feature is available only on deployments that have the new Liveboard experience enabled. For more information, see xref:enable-liveboardv2.adoc#_customize_liveboard_tabs[Customize Liveboard tabs]. + +[IMPORTANT] +The new Liveboard experience is in BETA on embedded ThoughtSpot instances. This feature is turned off by default on embedded ThoughtSpot instances. +==== +.Visual Embed SDK version 1.15.0 +[%collapsible] +==== +For information about the new features and enhancements in the Visual Embed SDK version 1.15.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.REST API v1 +[%collapsible] +==== +For information about REST API v1 enhancements, see xref:rest-apiv1-changelog.adoc[REST API changelog]. +==== + +.REST API v2 [beta betaBackground]^Beta^ +[%collapsible] +==== +The REST API v2 [beta betaBackground]^Beta^ feature will be deprecated in 8.10.0.cl and replaced with the new v2.0 API endpoints. For more information, see xref:deprecated-features.adoc[Deprecation announcements]. +==== + +== Version 8.6.0.cl + +.Liveboard new experience [beta betaBackground]^Beta^ +[%collapsible] +==== +The new Liveboard experience is now available on embedded ThoughtSpot instances. In addition to the existing Liveboard features, the new experience introduces several notable changes to the *Liveboard* page: + +Liveboard editing:: +To edit a Liveboard, users must switch to the edit mode by clicking the *Edit* button on the Liveboard page. +The edit mode allows you to edit the Liveboard title and description text, apply filters, copy the Liveboard, modify the layout of the visualization tiles, delete a visualization, and so on. + +Liveboard filters:: +* The Liveboard filter configuration options are available on a single modal. +* When a user creates a copy of a Liveboard, the filters applied to its visualizations are also copied. + +Other features and enhancements:: +* The *Add filters* action is placed in the primary menu bar and can be viewed only when a Liveboard is in edit mode. Only users with edit access to the Liveboard can apply filters. +* The *Undo*, *Redo*, and *Reset* actions for visualizations. +* The *Liveboard Info* action label in the More image:./images/icon-more-10px.png[the more options menu] menu is renamed to *Show Liveboard details*. +* The *Schedule* action is placed in the More image:./images/icon-more-10px.png[the more options menu] menu. +* Improved visualization Explore experience. + +Deprecated features:: +The following features are *_not_* available with the new Liveboard experience: +* The *Copy embed link* and *Copy link* menu actions in the More image:./images/icon-more-10px.png[the more options menu] menu of a Liveboard +* The edit title icon on visualization tiles +* The *Share* button on visualizations + +For more information about the new Liveboard experience, see link:https://docs.thoughtspot.com/cloud/latest/liveboard-experience-new[New Liveboard experience, window=_blank]. + +[discrete] +==== New Liveboard experience rollout on embedded instances + +The new Liveboard experience is currently available in BETA on embedded ThoughtSpot instances. The new liveboard experience will be rolled out on embedded instances in phases: + +In ThoughtSpot Cloud 8.6.0.cl:: +The new Liveboard experience is turned off by default on embedded ThoughtSpot instances. If you are using the Visual Embed SDK to embed ThoughtSpot, you can xref:enable-liveboardv2.adoc[set the `liveboardV2` parameter] in the SDK package to `true` and enable the new experience globally for all users on your instance. + ++ +ThoughtSpot users with administrator privileges can also link:https://docs.thoughtspot.com/cloud/latest/liveboard-experience-new[turn on the new Liveboard experience, window=_blank] at the cluster level. + +In later releases:: +The new Liveboard Experience will be turned on by default for all embed application users. To switch to the classic experience, you can set the `liveboardV2` parameter to `false` in the SDK, or change the Liveboard experience preference in the `Admin` tab of the ThoughtSpot UI. + +[NOTE] +The Liveboard experience setting in the SDK takes precedence over the cluster-level settings in the *Admin* tab. + +[discrete] +==== Actions and Events in the SDK +If you have enabled the new Liveboard experience on your instance, you can use the `Action` and `Event` enumeration members available in the SDK package to customize an embedded object and improve interactivity. + +For example, to disable the *Delete* action for a visualization object on the Liveboard, you can use the `Action.Remove` enum. Similarly, you can trigger events such as `VizPointClick` on visualizations in an embedded Liveboard. + +==== + +.Visual Embed SDK version 1.14.0 +[%collapsible] +==== +For information about the new features and enhancements in the Visual Embed SDK version 1.14.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.REST API +[%collapsible] +==== +For information about REST API enhancements, see xref:rest-apiv1-changelog.adoc[REST API changelog]. +==== + +== Version 8.5.0.cl + +.Search Assist support for embedded instances +[%collapsible] +==== +Your application users can now access sample search walkthrough lessons created using Search Assist on embedded ThoughtSpot instances. If the Search Assist feature is enabled in the SDK, and the Search Assist lessons are created on the Worksheet, users can view sample search questions and follow the actions in the walkthrough to get answers. + +For more information, see xref:search-assist-tse.adoc[Enable Search Assist, window=_blank]. +==== + +.Visual Embed SDK 1.13.0 +[%collapsible] +==== +For information about the new features and enhancements in the Visual Embed SDK version 1.13.0, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.ThoughtSpot UI +[%collapsible] +==== +The new Data workspace is Generally Available (GA) in 8.5.0.cl on ThoughtSpot instances. For more information about the new Data tab, SpotApps, and other related features, see link:https://docs.thoughtspot.com/cloud/latest/notes[ThoughtSpot product documentation]. + +[IMPORTANT] +While some customizable actions from the Visual Embed SDK will be honored from within an embedded instance of the new Data workspace page, full support of this page in embedded ThoughtSpot instances is planned for a future release. If you are actively embedding and customizing the `Data` tab for your application and wish to retain the legacy `Data` tab, contact ThoughtSpot Support. + +==== + +== Version 8.4.0.cl + +.Link customization +[%collapsible] +==== +This release allows query parameters in the Liveboard, saved Answer, and visualization URLs that are customized for an embedded ThoughtSpot instance. For example, you can customize the *Unsubscribe* link sent in email notifications for KPI charts by adding `{ts-query-params}` to the visualization URL, and thus allow users to unsubscribe from KPI threshold alerts at any time. + +For more information, see xref:customize-links.adoc[Customize links]. +==== + +.Visual Embed SDK 1.12.0 + +[%collapsible] +==== +The Visual Embed SDK version 1.12.0 introduces new events. For more information, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.REST API v2 [beta betaBackground]^Beta^ +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|| +|[tag greenBackground]#NEW ENDPOINTS# a| This release introduces the following new REST API v2 [beta betaBackground]^Beta^ endpoints: + + +* Data + +** `*GET* /tspublic/rest/v2/data/answer/querysql` + +** `*GET* /tspublic/rest/v2/data/liveboard/querysql` +* Admin +** `*PUT* /tspublic/rest/v2/admin/assignauthor` +|[tag redBackground]#BREAKING CHANGES# a| * The method names for the following endpoints will be changed in the SDK. + +** `/tspublic/rest/v2/user/addgroup` + +** `/tspublic/rest/v2/user/removegroup` + +* The `/tspublic/rest/v2/admin/changeowner` endpoint will be renamed as `/tspublic/rest/v2/admin/changeauthor`. +|==== +==== + +== Version 8.3.0.cl + +.Visual Embed SDK 1.11.0 +[%collapsible] +==== +The Visual Embed SDK version 1.11.0 introduces several new events for embedded components. For more information, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.REST API v2 [beta betaBackground]^Beta^ +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|| +|[tag greenBackground]#NEW ENDPOINTS# a| The following REST API v2 [beta betaBackground]^Beta^ endpoints are now available: + +* Connection endpoints + +** `GET /tspublic/rest/v2/connection/database` + +** `POST /tspublic/rest/v2/connection/table` + +** `POST /tspublic/rest/v2/connection/tablecoloumn` + +* Report endpoint + +** `POST /tspublic/rest/v2/report/liveboard` + +* Security endpoints + +** `POST /tspublic/rest/v2/security/share/tsobject` + +** `POST /tspublic/rest/v2/security/share/visualization` + +** `GET /tspublic/rest/v2/security/permission/tsobject` + +** `GET /tspublic/rest/v2/security/permission/principal` + +** `POST /tspublic/rest/v2/security/permission/tsobject/search` + +** `POST /tspublic/rest/v2/security/permission/principal/search` + +* Custom action endpoints + +** `GET /tspublic/rest/v2/customaction` + +** `POST /tspublic/rest/v2/customaction/create` + +** `PUT /tspublic/rest/v2/customaction/update` + +** `DELETE /tspublic/rest/v2/customaction/delete` + +** `POST /tspublic/rest/v2/customaction/search` + +** `GET /tspublic/rest/v2/customaction/association` + +** `DELETE /tspublic/rest/v2/customactions/association/delete` + +|[tag orangeBackground]#MODIFIED# a| +* The `x-requested-by` header is not mandatory for API requests to the REST API v2 [beta betaBackground]^Beta^ endpoints. +* The `createdBy` attribute in the `/tspublic/rest/v2/metadata/header/search` API is renamed to `author`. +* The attributes with the `boolean` data type in the API endpoints are changed to `string` data type. If a boolean attribute was set as `true` in your existing setup, the value will be changed to `"true"`. +|[tag redBackground]#BREAKING CHANGES# a| + +* Note the change in HTTP request method for the following REST API v2 [beta betaBackground]^Beta^ endpoints: + +** `**PUT** /tspublic/rest/v2/metadata/tag/assign` + +** `**PUT** /tspublic/rest/v2/metadata/tag/unassign` + +** `**PUT** /tspublic/rest/v2/metadata/favorite/assign` + +** `**PUT** /tspublic/rest/v2/metadata/favorite/unassign` + +** `**PUT** /tspublic/rest/v2/metadata/homeliveboard/assign` + +** `**PUT** /tspublic/rest/v2/metadata/homeliveboard/unassign` + +* In the REST API SDK [beta betaBackground]^Beta^, the classes corresponding to enumerations used for string fields such as the `type` field in metadata API, are renamed. If you are using the REST API SDK in your environments, make sure the class names are updated. +|[tag redBackground]#REMOVED# a| The `ownedBy` attribute is removed from the `/tspublic/rest/v2/metadata/header/search` API endpoint. +|==== +==== + +== Version 8.2.0.cl + +//// +=== Custom actions +[width="100%" cols="1,4"] +|==== +|| +|[tag greenBackground]#NEW FEATURE# a| +++
App actions for Slack integration
+++ + +ThoughtSpot introduces app actions[beta betaBackground]^Beta^ to support seamless integration with third-party business apps such as Slack. Your application users can now connect ThoughtSpot with their Slack workspaces and deliver insights directly to Slack channels. + +Users with developer or admin privileges can create an app action for Slack[beta betaBackground]^Beta^ in the Developer portal and add it as a menu action on visualizations and saved answers. On clicking this action, ThoughtSpot users can initiate the Slack integration workflow and send data to their Slack channels without leaving the ThoughtSpot UI. + +For more information, see xref:app-actions.adoc[App actions] and xref:push-data-to-slack.adoc[Push data to a Slack workspace]. +|==== +//// + +.Visual Embed SDK 1.10.x +[%collapsible] +==== +The Visual Embed SDK version 1.10.x introduces new attributes and bug fixes. For more information, see xref:api-changelog.adoc[Visual Embed changelog]. +==== + +.REST API v1 +[%collapsible] +==== +New endpoints for data connection queries. For more information, see xref:rest-apiv1-changelog.adoc[REST API v1 changelog]. +==== + +.REST API v2 [beta betaBackground]^Beta^ + +[%collapsible] +==== +Starting from 8.2.0.cl release, the xref:rest-api-v2.adoc[REST API Playground and SDK] [beta betaBackground]^Beta^ feature is enabled by default on ThoughtSpot instances. + +The 8.2.0.cl release also introduces the following features: + +Endpoint URL path:: +The REST API v2 [beta betaBackground]^Beta^ endpoint URL path is changed from `/api/rest/v2` to `/tspublic/rest/v2/`. For example, the `GET /api/rest/v2/connection` endpoint is now available as `GET /tspublic/rest/v2/connection`. + +Trusted authentication:: +If trusted authentication is enabled on your instance, you can now obtain a login token to authenticate to ThoughtSpot and authorize your API requests. + +For more information, see xref:authentication.adoc#trustedAuthToken[REST API v2 authentication]. + +SDK for .NET clients:: +ThoughtSpot provides the .NET SDK to allow developers to interact with REST APIs from .NET applications. You can download the SDK from NuGet Package Manager and install it using the NuGet GUI. For more information, see xref:rest-api-sdk-libraries.adoc[REST API SDK and client libraries]. + +New API endpoints:: + +* `GET /tspublic/rest/v2/admin/configuration` +* `GET /tspublic/rest/v2/admin/configuration/overrides` +* `PUT /tspublic/rest/v2/admin/configuration/update` +* `PUT /tspublic/rest/v2/admin/resetpassword` +* `PUT /tspublic/rest/v2/admin/syncprincipal` +* `PUT /tspublic/rest/v2/admin/changeowner` +* `PUT /tspublic/rest/v2/user/changepassword` +* `POST /tspublic/rest/v2/data/search` +* `POST /tspublic/rest/v2/data/answer` +* `POST /tspublic/rest/v2/data/liveboard` +* `POST /tspublic/rest/v2/report/answer` +* `GET /tspublic/rest/v2/logs/events` + +For more information, see xref:rest-api-v2-reference-beta.adoc[REST API v2 Reference]. + +==== + +== Version 8.1.0.cl + +.Visual Embed SDK version 1.9.x +[%collapsible] +==== +The Visual Embed SDK version 1.9.x introduces new action enumerations, events, and attributes. For more information, see xref:api-changelog.adoc[Visual Embed Changelog]. +==== + +.REST API v2 [beta betaBackground]^Beta^ +[%collapsible] +==== +The following REST API v2 endpoints are now available on instances on which the REST API v2 Playground and SDK feature is enabled. + +* `GET /api/rest/v2/connection` +* `POST /api/rest/v2/connection/create` +* `PUT /api/rest/v2/connection/update` +* `DELETE /api/rest/v2/connection/delete` +* `PUT /api/rest/v2/connection/addtable` +* `PUT /api/rest/v2/connection/removetable` +* `POST /api/rest/v2/connection/search` +* `DELETE /api/rest/v2/metadata/delete` +* `GET /api/rest/v2/metadata/header` + +The REST API v2 Playground and SDK is a limited availability feature and is in beta. + +For more information, see xref:rest-api-v2.adoc[REST API v2] and xref:rest-api-v2-reference.adoc[REST API v2 Reference]. +==== + + +== Version 8.0.0.cl + +.Visual Embed SDK version 1.8.x +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|| +|[tag redBackground]#BREAKING CHANGE# | +++
Auto login
+++ + +The `autoLogin` attribute is now set as `false` by default. This attribute is used in the `init` method to automatically re-login a user when a user session expires. +|[tag greenBackground]#NEW FEATURE# | +++
Authentication
+++ + +The `init` method now returns an `authPromise` that resolves when the authentication is completed. +|==== + +==== + + +.Embed application +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a| +++
OpenID Connect authentication
+++ + +ThoughtSpot now supports OpenID Connect (OIDC) authentication framework on embedded instances. Your application users can now authenticate to an authorization server at your OpenID provider and access embedded ThoughtSpot content using their SSO credentials. + +For more information, see xref:configure-oidc.adoc[OpenID Connect authentication]. + +|[tag redBackground]#REMOVED# a| +++
Follow button
+++ + +If you have embedded the full ThoughtSpot application, you will notice that the *Follow* button on the Liveboards page is removed. You can now schedule email notifications using the **Schedule** feature and follow Liveboard updates. + +For more information, see link:https://cloud-docs.thoughtspot.com/end-user/pinboards/follow-pinboard.html[Follow Liveboards, window=_blank]. +|==== +==== + + +.Visual Embed SDK 1.7.0 + +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== + +|[tag greenBackground]#NEW FEATURE# |+++
OIDC AuthType
+++ + +The SDK supports the `OIDC` `authType` in `init` calls. If you want your application users to authenticate to an OpenID provider and use their SSO credentials to access the embedded ThoughtSpot content, you can enable the `OIDC` authentication type in the SDK. + +For more information, see xref:embed-authentication#oidc-auth.adoc[Authentication and security attributes]. +|[tag greenBackground]#NEW FEATURE# a|+++
Embed events
+++ + +The SDK includes the following new event: + +* `RouteChange` + +For more information, see xref:events-ref.adoc[Events reference]. + +|==== +==== + +.REST API Playground and SDK [beta betaBackground]^Beta^ + +[%collapsible] +==== + +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a| +++
REST API Playground and SDK
+++ + +ThoughtSpot introduces the v2 [beta betaBackground]^Beta^ version of REST API endpoints and an interactive Playground to explore the API request and response workflows. + +The API Playground offers several distinct features, such as an interactive code panel, a catalog of resource-oriented endpoint URLs, language-specific SDK and client libraries, code samples, and API reference documentation. + +You can use any standards-compliant HTTP client or use the Playground to make an API call. If you want to construct your queries and process API responses programmatically, you can download the SDK and client libraries in the programming language of your choice and integrate them with your applications. + +The REST API Playground and SDK is a limited availability feature and is in beta. To preview this feature, visit link:https://try-everywhere.thoughtspot.cloud/v2/#/everywhere/api/rest/playgroundV2[ThoughtSpot Live Playground, window=_blank]. To enable this feature on your ThoughtSpot instance, contact ThoughtSpot Support. + +For more information, see xref:rest-api-v2.adoc[REST API v2]. +|==== +==== + + +== Version ts8.nov.cl + +.Developer portal +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|[tag orangeBackground]#CHANGE NOTICE# a| +++
Pinboards are now Liveboards!
+++ + +Effective from the ThoughtSpot 8 November Cloud release, ThoughtSpot pinboards are rebranded as Liveboards and optimized for live analytics in cloud deployments. Along with granular insights, Liveboards offer interactive data analytics experience with enhanced capabilities. + +As part of rebranding, we have made some terminology changes in the ThoughtSpot UI and Developer portal. We are in the process of rolling out terminology changes across all ThoughtSpot interfaces, platforms, and information artifacts. During this period, your environment may show some instances of `pinboard` based on the rebranding rollout stage. In some cases, we may even continue to use the legacy terminology for backward compatibility, and to ensure that your existing integrations work seamlessly. For more information, see xref:terminology-update.adoc[Terminology changes]. +|==== +==== + + +.Custom actions +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a| +++
Custom action association to user groups
+++ + +ThoughtSpot now allows you to restrict a custom action's availability to specific user groups. Developers can associate a custom action to one or several user groups in the Developer portal and allow only authorized users to view and access the custom action on a Worksheet, Answer, or visualization. + +For more information, see xref:customize-actions-menu.adoc#access-control[Custom actions] and xref:custom-actions-url.adoc[Configure a custom URL action]. +|==== +==== + +.User access +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# |ThoughtSpot now supports restricting embed user access to the non-embedded ThoughtSpot application instance. By default, all embedded ThoughtSpot users can navigate to and log in to the non-embedded ThoughtSpot application instance. +If you want to allow only users with administrator or developer privileges to access the non-embedded ThoughtSpot application instance, contact ThoughtSpot Support. +|==== +==== + + +.Visual Embed SDK version 1.6.x +[%collapsible] +==== + +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a|+++
Visible actions
+++ + +You can now configure a set of ThoughtSpot UI actions as visible actions and display these actions in the embedded UI. If your embedded instance requires only a few actions, you can use the `visibleActions` API to show only these actions in the embedded ThoughtSpot UI. + +For more information, see xref:embed-actions.adoc[Show or hide UI actions]. + +|[tag orangeBackground]#MODIFIED# | +++
Terminology changes
+++ + +The SDK library and object parameter names are modified to rebrand pinboards as Liveboards. For a complete list of changes, see xref:terminology-update.adoc#sdk-changes[Terminology changes]. + +|[tag greenBackground]#NEW FEATURE# a|+++
Embed events
+++ + +The SDK supports the following new events: + +* `DialogOpen` +* `DialogClose` + +For more information, see xref:events-ref.adoc[Events reference]. + +|==== +==== + +.REST API +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a|`POST /tspublic/v1/session/login/token` + +This API allows you to send the login token and user information in the request body. For more information, see the xref:session-api.adoc#session-loginToken[REST API reference page]. + +|[tag orangeBackground]#MODIFIED# a| The `/tspublic/v1/connection/create` and `/tspublic/v1/connection/update` endpoints now allow configuring and modifying a connection without importing tables. + +For more information, see xref:connection-apis.adoc[Data connection APIs]. +|[tag orangeBackground]#MODIFIED#|You can now filter metadata objects by author GUIDs using the `authorguid` attribute in the `/tspublic/v1/metadata/list` endpoint. + +For more information, see xref:metadata-api.adoc#metadata-list[Get a list of metadata objects]. +|==== + +==== + +.ThoughtSpot application UI +[%collapsible] +==== + +To make it easier for users to find new insights, the **Search data** functionality is moved from the search bar toggle on the **Home** page to the **Search data** button in the main navigation bar. + +Note that if you are embedding the full application without the navigation bar, your application users may not be able to access the **Search data** button. If you must include the Search bar toggle on the **Home** page, contact ThoughtSpot Support to restore this feature on your cluster. + +image:./images/search-toggle.png[Search toggle, width=auto] + +image:./images/search-data-btn.png[Search data button, width=auto] + +==== + +== Version ts7.oct.cl + +.Custom actions +[%collapsible] +==== + +[width="100%" cols="1,4"] +|==== +|[tag orangeBackground]#MODIFIED# a|+++
Custom actions feature availability
+++ + +Starting from ThoughtSpot 7 Cloud October release, you _do not_ require a separate ThoughtSpot Everywhere Edition license to create or manage custom actions. The *Custom action* feature is unlocked on all clusters that have a valid ThoughtSpot Enterprise Cloud service subscription. ThoughtSpot Cloud service users with Developer or Admin privileges can access the *Custom actions* feature in the *Develop* tab. + +|[tag redBackground]#REMOVED# a|+++
The Only allow in context menu checkbox +++ + +The *Only allow in context menu* checkbox in the custom action creation dialog is removed from the UI. This checkbox was available in previous releases to allow developers to set a custom action to appear only in the contextual menu on pinboard visualizations, charts, or tables. + +If you have created custom actions with the *Only allow in context menu* setting enabled on your instance, note these custom action workflow changes: + +* If you have a *Global* custom action with the *Only allow in context menu* setting enabled, the configuration setting _is not_ preserved and the action is placed in the **More** image:./images/icon-more-10px.png[the more options menu] menu instead of the contextual menu. ++ +You can xref:custom-actions-edit.adoc[modify the position of this action] by using the *Edit* option in the *Custom actions* panel on a visualization or search results page. + +* If you have a *Local* custom action with the *Only allow in context menu* setting enabled and the action is already assigned to a Worksheet, visualization, chart, or table, the configuration setting _is_ preserved and the custom action shows up in the contextual menu. + +* If you have a *Local* custom action with the *Only allow in context menu* setting enabled, but it is not assigned to a Worksheet, visualization, chart, or table, the action will not be available as a menu item or button. You must add the action to a visualization, chart, or table, and configure its position as required. For more information, see xref:custom-actions-viz.adoc[Add a custom action to a visualization] and xref:custom-actions-Worksheet.adoc[Add custom actions to a Worksheet]. + +|==== +==== + +.Visual Embed SDK version 1.5.0 + +[%collapsible] +==== + +The ThoughtSpot 7 Cloud October release introduces the Visual Embed SDK version 1.5.0, which includes the following new features and enhancements. + +[width="100%" cols="1,4"] +|==== +|| +|[tag greenBackground]#NEW FEATURE# | +++
Render embedded objects in queue
+++ + +The SDK now supports rendering embedded objects in a queue. If you have multiple embedded objects, you can enable the `queueMultiRenders` parameter to queue your embedded objects and render them one after another. This feature helps in decreasing the load on the web browsers and improving your application loading experience. By default, this attribute is set to `false`. + +|[tag greenBackground]#NEW FEATURE# a|+++
Liveboard embed
+++ + +The `pinboardEmbed` package includes the `defaultHeight` attribute that sets a minimum height for embedded objects on a pinboard page and the corresponding visualization pages that a user can navigate to. + +For more information, see xref:embed-search.adoc[Embed a pinboard]. + +|[tag greenBackground]#NEW FEATURE# a|+++
Embed events
+++ + +The SDK EmbedEvent library includes the following new events: + +* `VizPointDoubleClick` +* `Drilldown` +* `SetVisibleVizs` + +For more information, see xref:events-ref.adoc#embed-events[Events reference]. + +|==== +==== + +.REST APIs +[%collapsible] +==== +The ThoughtSpot 7 Cloud October release includes the following new REST API endpoints. For more information about these APIs, see xref:rest-api-reference.adoc[REST API Reference]. + +* `POST /tspublic/v1/group/{groupid}/users` +* `GET /tspublic/v1/group/{groupid}/users` +* `DELETE /tspublic/v1/group/{groupid}/users` +* `PUT /tspublic/v1/user/email` +* `POST /tspublic/v1/user/{userid}/groups` +* `GET /tspublic/v1/user/{userid}/groups` +* `PUT /tspublic/v1/user/{userid}/groups` +* `DELETE /tspublic/v1/user/{userid}/groups` +==== + + +== Version ts7.sep.cl + +.Licensing +[%collapsible] +==== + +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a| +++
+++New ThoughtSpot Everywhere Edition license+++
+++ + +ThoughtSpot introduces the ThoughtSpot Everywhere Edition license that grants access to ThoughtSpot Everywhere features, such as the Developer portal, Playground, customization workflows, Visual Embed SDK, and REST APIs. If you have a ThoughtSpot Enterprise Cloud Service subscription and you want to avail the benefits of ThoughtSpot Everywhere, you can now request for a license upgrade. + +The new licensing model introduces several notable changes in the ThoughtSpot Developer portal: + +* On clusters that _do not_ have the ThoughtSpot Everywhere Edition license, the ThoughtSpot Developer Portal displays a locked icon next to the customization menu actions. When you click the locked icon, the UI prompts you to sign up for a free trial or upgrade your license. +* The ThoughtSpot Enterprise Cloud service subscribers can either start a 30-day free trial or initiate a license upgrade from the UI. +* Free trial users can initiate a license upgrade request by clicking **Upgrade Now** at any time during the evaluation period, or when the trial expires. +* If you click *Upgrade* or **Upgrade Now**, ThoughtSpot opens the Live Chat Support widget. You can start a conversation with the Sales personnel to initiate the license upgrade. + +For more information about the licensing model and upgrade process, see xref:get-started-tse.adoc[Get started with ThoughtSpot Everywhere]. +|==== + +==== + +.Developer portal enhancements +[%collapsible] +==== +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a| +++
+++Developer Playground enhancements+++
+++ + +* The *Full app* Playground page includes the *Hide profile and help* checkbox to provide a preview of the `disableHelpAndProfile` function that can hide the Help and Profile icons in the ThoughtSpot navigation bar. + +* The *Full Height* checkbox in *Pinboard* Playground provides a preview of the `fullHeight` attribute that can dynamically resize the embedded pinboard frame according to the height of the pinboard. + +For more information, see xref:developer-playground.adoc[Developer Playground]. +|==== + +==== + +.Visual Embed SDK version 1.4.0 + +[%collapsible] +==== +The ThoughtSpot 7 Cloud September release introduces the Visual Embed SDK version 1.4.0, which includes the following new features and enhancements. + +[width="100%" cols="1,4"] +|==== +|| +|[tag greenBackground]#NEW FEATURE# a|+++
+++Prefetch API+++
+++ + +The `prefetch` API fetches static resources from a given URL before your application loads. Web browsers can then cache the prefetched resources locally and serve them from a user's local disk. You can use this API to load the embedded objects faster and improve your application response time. + +For more information, see xref:prefetch-and-cache.adoc[Prefetch static resources]. + +|[tag greenBackground]#NEW FEATURE# a|+++
+++In-app page navigation+++
+++ + +The `navigateToPage` method in the SDK lets you provide quick and direct access to a specific pinboard, saved Answer, or an application page. You can add a custom menu action or button in your application UI that calls the `navigateToPage` method and leads your users to the page specified in the `path` parameter. + +For more information, see xref:page-navigation.adoc[Add a custom action for in-app navigation]. + +|[tag greenBackground]#NEW FEATURE# a|+++
+++Full application embedding+++
+++ + +The `appEmbed` SDK package includes the following new attributes: + +* The `disableProfileAndHelp` attribute to show or hide the `Help (?)` and the user profile menu in the navigation bar of your embedded app. + +* The `hideObjects` attribute to hide specific objects from a user's page view. + +For more information, see xref:full-embed.adoc[Embed full application]. + +|[tag greenBackground]#NEW FEATURE# |+++
+++Search embed +++
+++ + +The `searchEmbed` package includes the `forceTable` attribute that sets tabular view as the default format for presenting search data. You can use set this attribute to `true` to force search results to appear in the table view. + +For more information, see xref:embed-search.adoc[Embed ThoughtSpot search]. + +|[tag redBackground]#REMOVED# | + +The `searchQuery` parameter is no longer supported and is removed from the `searchEmbed` SDK package. +|[tag greenBackground]#NEW FEATURE# a|+++
+++Embed events +++
+++ +The SDK EmbedEvent library includes the following events: + +* `QueryChanged` +* `AuthExpire` + +For more information, see xref:embed-events.adoc[Subscribe to Events]. +|==== + +==== + +.REST APIs + +[%collapsible] +==== + +The ThoughtSpot 7 Cloud September release includes the following new endpoints and modifications to the REST APIs. For more information, see xref:rest-api-reference.adoc[REST API Reference]. + +.New APIs + +* `POST /tspublic/v1/connection/create` +* `POST /tspublic/v1/connection/update` +* `POST /tspublic/v1/connection/export` +* `POST /tspublic/v1/connection/delete` +* `POST /tspublic/v1/metadata/unassigntag` +* `GET /tspublic/v1/metadata/list` +* `GET /tspublic/v1/security/metadata/permissions` +* `GET /tspublic/v1/security/metadata/{id}/permissions` +* `GET /tspublic/v1/security/effectivepermissionbulk` +* `GET /tspublic/v1/session/info` +* `POST /tspublic/v1/user/activate` +* `POST /tspublic/v1/user/inactivate` +* `POST /tspublic/v1/user/session/invalidate` +* `POST /tspublic/v1/user/resetpassword` +* `PUT /tspublic/v1/group/{groupid}/users` +* `POST /tspublic/v1/group/{groupid}/groups` +* `PUT /tspublic/v1/group/{groupid}/groups` +* `GET /tspublic/v1/group/{groupid}/groups` +* `POST /tspublic/v1/group/addmemberships` +* `POST /tspublic/v1/group/removememberships` +* `DELETE /tspublic/v1/group/{groupid}/groups` + + +.Modified APIs + +* `POST /tspublic/v1/metadata/assigntag` + +==== + +== Version ts7.aug.cl + +.Custom actions +[%collapsible] +==== + +[width="100%" cols="1,4"] +|==== +|| +|[tag greenBackground]#NEW FEATURE# a| +++
Custom actions for worksheets
+++ + +The Worksheet pages now include a `Custom actions` tab that shows the custom actions created in the Developer portal. ThoughtSpot users can add these actions to a Worksheet and place them as primary actions or menu items in the new visualizations built from that Worksheet. + +This feature is available to all ThoughtSpot users who have edit privileges to a Worksheet. + +For more information, see xref:custom-actions-worksheet.adoc[Add custom actions to a Worksheet]. + +|[tag greenBackground]#NEW FEATURE# a| +++
Query parameters for URL-based custom actions
+++ + +The Developer portal now allows you to add arbitrary key-value pairs as query parameters for a URL action. If a URL endpoint requires specific information, such as the database details or data object attributes, you can add a key-value pair of these attributes when creating a custom action. When the custom action workflow is triggered, these attributes are passed as query parameters in `GET` requests to get the data payload from ThoughtSpot. + +For more information, see xref:custom-actions-url.adoc[Configure a custom URL action]. +|==== + +==== + +.Visual Embed SDK version 1.3.1 + +[%collapsible] +==== +The ThoughtSpot 7 Cloud August release supports Visual Embed SDK version 1.3.1, which includes the following features and enhancements. + +[width="100%" cols="1,4"] +|==== +|| +|[tag greenBackground]#NEW FEATURE# a| +++
searchOptions
+++ + +The `searchEmbed` SDK package introduces the `searchOptions` parameter for setting search tokens. The `searchOptions` parameter includes the following attributes: + +* `searchTokenString` ++ +A TML query string to define search tokens. + +* `executeSearch` ++ +When set to `true`, it executes search and shows the search results. + +For more information, see xref:embed-search.adoc#search-query[Embed ThoughtSpot search]. + +|[tag redBackground]#DEPRECATED# a| +++
searchQuery
+++ + +The `searchQuery` parameter in the `searchEmbed` SDK package is deprecated in the Visual Embed SDK version 1.3.1. Instead, you can use the `searchOptions` parameter to define the search token string. + +For more information about `searchOptions`, see xref:embed-search.adoc#search-query[Embed ThoughtSpot search]. + +|[tag greenBackground]#NEW FEATURE# a| +++
autoLogin
+++ + +The SDK now supports logging in users automatically after a user session has expired. + +For more information, see xref:embed-authentication.adoc#embed-session-sec[Embed user authentication]. + +|[tag greenBackground]#NEW FEATURE# a| +++
shouldEncodeUrlQueryParams
+++ + +You can now convert query parameters in the ThoughtSpot generated URLs to base64-encoded format. You can enable this attribute to secure your cluster from cross-site scripting attacks. +|[tag redBackground]#BREAKING CHANGE# a| +++
Data structure changes in custom action response payloads
+++ + +* The data structure passed in the custom action response for search now shows as `payload.data.embedAnswerData` instead of `payload.data.columnsAndData`. + +* The Answer payload for custom actions includes the following metadata: + +** `reportBookmetadata` ++ +Includes visualization metadata attributes such as description, object header metadata, author details, timestamp of the Answer creation, and modification. + +** user data ++ +Includes user information such as username, GUID of the user, and email address. + +To view a sample response payload, see xref:callback-response-payload.adoc#search-data-payload[Custom action response payload]. + +|[tag greenBackground]#NEW FEATURE# a| +++
preventPinboardFilterRemoval
+++ + +The `pinboardEmbed` SDK package now includes the `preventPinboardFilterRemoval` attribute. You can use this attribute to disable the filter removal action and thus prevent users from removing the filter chips added on a pinboard page. + +For more information, see xref:embed-pinboard.adoc[Embed a pinboard] and xref:embed-a-viz.adoc[Embed a visualization]. +|[tag greenBackground]#NEW FEATURE# a| +++
suppressNoCookieAccessAlert
+++ + +You can now set custom alerts for `noCookieAccess` events. By default, the SDK triggers a `noCookieAccess` event and generates an alert when a user's browser blocks third-party cookies. The `suppressNoCookieAccessAlert` allows you to disable this alert. + +|[tag greenBackground]#NEW FEATURE# a| +++
Support for fetching callback custom action payload in batches
+++ + +The Visual Embed SDK now supports processing data in batches for callback custom action responses. +The callback custom action event in the SDK package supports defining `batchSize` and `offset` values to paginate the Answer payload and send the records in batches. + +For more information, see xref:push-data-to-external-app.adoc#large-dataset[Callback custom action workflow]. +|==== + +==== + +.REST APIs +[%collapsible] +==== + +The ThoughtSpot 7 Cloud August release introduces several new APIs to xref:user-api.adoc[manage users], xref:group-api.adoc[user groups], xref:admin-api.adoc[cluster configuration], xref:dependency-apis.adoc[object dependencies], and so on. + +For a complete list of APIs, see xref:rest-api-reference.adoc[REST API Reference]. + +==== + + +== Version ts7.jun.cl + +.Custom actions +[%collapsible] +==== + +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a|+++
Global and local custom actions
+++ + +The ThoughtSpot developer portal now supports configuring a custom action as a __global__ or __local__ action. This feature allows you to determine and control the placement of custom actions in the ThoughtSpot UI. Developers can now choose to create a custom action that will appear on all visualizations, or a specific custom action that can be added to a visualization by a ThoughtSpot user. The custom actions panel in the visualization page allows ThoughtSpot users to view the available custom actions and add an action to any visualization. + +For example, if you want an action that triggers a callback into your parent app, which would then post its data to Slack, you might want to add a custom action globally to all visualizations. Similarly, if you want to send the data obtained from a specific visualization to a URL, you can associate a custom action locally to that visualization. + +For more information, see xref:customize-actions-menu.adoc[Custom actions] and xref:custom-actions-viz.adoc[Add a custom action to a specific visualization]. + +|[tag greenBackground]#NEW FEATURE# a|+++
Authentication schemes for custom actions
+++ + +You can now apply an authentication scheme for a custom action that triggers a data payload to a specific URL target. If an action requires your users to authenticate to send data to a URL, you can specify the authentication method and authorization attributes when creating a custom action in the Developer portal. +ThoughtSpot will use this information to send the required attributes in the `Authorization` headers to the URL endpoint configured in the custom action. + +|[tag greenBackground]#NEW FEATURE# a| ++++
Custom action position settings
+++ + +ThoughtSpot users with edit privileges can now define or modify the position of a custom action on visualization pages. When a developer creates a custom action in the Developer portal, ThoughtSpot adds a menu item to the **More** image:./images/icon-more-10px.png[the more options menu] menu by default. ThoughtSpot users can change this to a context menu action or a primary action at any time. + +If your application instance requires an action that sends only a single row of data from charts or tables, developers can configure a custom action and restrict it to only the contextual menu. If this setting is enabled on a custom action, ThoughtSpot users cannot modify this action on a visualization page. + +For more information, see xref:custom-actions-viz.adoc[Add a custom action to a specific visualization]. +|==== + +==== + +.Custom link format for embedded instances +[%collapsible] +==== + +ThoughtSpot generates links to access objects, such as pinboards, visualizations, and answers, when a user shares an object with another user or follows a pinboard to receive periodic notifications. If you have embedded ThoughtSpot in your application, you might want to generate these links in the format that preserves your host application context. + +For embedded instances, ThoughtSpot now allows you to customize the format of these links in the Developer portal. The *Link Settings* page in the Developer portal allows you to customize the link format for various resource URLs and the *unsubscribe* link sent in email notifications. + +For more information, see xref:customize-links.adoc[Customize links]. +==== + +.REST APIs +[%collapsible] +==== + +The ThoughtSpot 7 Cloud June release includes several new and modified APIs: + +.New APIs + +* `POST /tspublic/v1/security/share` ++ +Use this API to share ThoughtSpot objects with another user or user group. For more information, see xref:security-api.adoc#share-object[Share objects with another user]. + +* `POST /tspublic/v1/security/shareviz` ++ +Use this API to share a specific ThoughtSpot visualization with another user or user group. For more information, see xref:security-api.adoc#shareviz[Share a visualization with another user or user group]. + +* `GET /tspublic/v1/session/login/token` ++ +Use this API to get a login token for a ThoughtSpot user when trusted authentication is enabled. For more information, see xref:session-api.adoc#session-loginToken[Authenticate and log in a user]. + +* `POST /tspublic/v1/metadata/assigntag` ++ +Use this API to programmatically assign a tag to a ThoughtSpot object such as a pinboard, Answer, table, or Worksheet. For more information, see xref:metadata-api.adoc#assign-tag[Assign tags to metadata objects]. + +* `POST /tspublic/v1/metadata/details` ++ +Use this API to query metadata details for a specific data object such as a pinboard, Answer, or a Worksheet. For more information, see xref:metadata-api.adoc#metadata-details[Get metadata details]. + +* `POST /tspublic/v1/metadata/markunmarkfavoritefor` ++ +Use this API to add pinboards and answers to a user's favorites list. For more information, see xref:metadata-api.adoc#set-favorite[Set objects as favorites]. + +* `DELETE /tspublic/v1/metadata/markunmarkfavoritefor` ++ +Use this API to remove an object from a user's favorites list. For more information, see xref:metadata-api.adoc#del-object-fav[Remove objects from favorites]. + +* `POST /tspublic/v1/session/homepinboard` ++ +Use this API to set a pinboard as the home pinboard for a user account. For more information, see xref:session-api.adoc#set-home-pinboard[Set a pinboard as a home pinboard]. + +* `GET /tspublic/v1/session/homepinboard` ++ +Use this API to get the GUID of the pinboard set as a home pinboard. For more information, see xref:session-api.adoc#get-home-pinboard[Get details of the home pinboard]. + +* `DELETE /tspublic/v1/session/homepinboard` ++ +Use this API to remove the home pinboard. For more information, see xref:session-api.adoc#del-home-pinboard[Remove a home pinboard]. + + +.Other API enhancements + +The `POST /tspublic/v1/user/updatepreference` API now includes the optional `username` parameter to allow API users to specify the `username` of the ThoughtSpot user whose profile is being modified. +For more information, see xref:user-api.adoc#updatepreference-api[Update a user profile]. + +==== + + +== Version ts7.may.cl + +.Custom actions in the context menu +[%collapsible] +==== +You can now add a custom action to the contextual menu to send data or initiate an action from an embedded visualization. The *Customization* > *Actions* page in the *Develop* tab allows you to add a custom action to the contextual menu for visualizations in the *Answers* or *Pinboards* page. + +[NOTE] +This feature is available only if the link:https://cloud-docs.thoughtspot.com/admin/ts-cloud/new-answer-experience[New Answer experience, window=_blank] is enabled on your ThoughtSpot instance. + +For more information, see xref:customize-actions-menu.adoc[Add custom actions]. +==== + +.Visual Embed SDK version 1.2.0 +[%collapsible] +==== + +[width="100%" cols="1,4"] +|==== +|[tag greenBackground]#NEW FEATURE# a|+++
SAML authentication
+++ + +The Visual Embed SDK packages now include the `noRedirect` attribute as an optional parameter for the `SSO` `AuthType`. If you want to display the SAML authentication workflow in a pop-up window, instead of refreshing the application web page to direct users to the SAML login page, you can set the `noRedirect` attribute to `true`. + +For more information, see the instructions for embedding xref:full-embed.adoc[ThoughtSpot pages], xref:embed-search.adoc[search], xref:embed-pinboard.adoc[pinboard], and xref:embed-a-viz.adoc[visualizations]. + +|[tag greenBackground]#NEW FEATURE# a|+++
Visual Embed SDK notification when third-party cookies are disabled
+++ + +When a user accesses the embedded application from a web browser that has third-party cookies disabled, the Visual Embed SDK emits the `NoCookieAccess` event to notify the developer. Cookies are disabled by default in Safari. Users can enable third-party cookies in Safari’s Preferences setting page or use another web browser. +To know how to enable this setting by default on Safari for a ThoughtSpot embedded instance, contact ThoughtSpot Support. + +|[tag greenBackground]#NEW FEATURE# a|+++
Pinboard actions
+++ +The *More* menu image:./images/icon-more-10px.png[the more options menu] in the embedded Pinboard page now shows the following actions for pinboard and visualizations. + +Pinboard:: +* Save +* Make a copy +* Add filters +* Configure filters +* Present +* Download as PDF +* Pinboard info +* Manage schedules + + +[NOTE] +Users with edit permissions can view and access the *Save*, *Add filters*, *Configure filters*, and *Manage schedules* actions. +|[tag greenBackground]#NEW FEATURE# a|+++
Visualization actions
+++ + +Visualizations on a pinboard: + +* Pin +* Download +* Edit +* Present +* Download as CSV +* Download as XLSX +* Download as PDF + +[NOTE] +Users with edit permissions can view and access the *Edit* action. The *Download as CSV*, *Download as XSLX*, and *Download as PDF* actions are available for table visualizations. The *Download* action is available for chart visualizations. + +|==== + +==== + +.Performance optimization +[%collapsible] +==== +This release introduces the following performance improvements for ThoughtSpot embedded applications: + +* Faster loading of embedded objects and application pages. +* Faster loading of preview results in the Playground. +==== +.REST APIs +[%collapsible] +==== +The ThoughtSpot 7 Cloud May release introduces the following REST APIs: + +* `*POST* /tspublic/v1/user/updatepreference` ++ +You can use this API to programmatically update a ThoughtSpot user's profile settings such as the email address, locale preference, notification settings, and the preference for revisiting the onboarding experience. For more information, see xref:user-api.adoc#updatepreference-api[User API]. + +* `*GET* /tspublic/v1/metadata/listas` ++ +You can use this API to get a list of object headers for a ThoughtSpot user or user group. For more information, see xref:metadata-api.adoc#headers-metadata-users[Metadata API]. +==== diff --git a/docs/src/asciidocs/writerGuide.adoc b/docs/src/asciidocs/writerGuide.adoc deleted file mode 100644 index 9635985a5..000000000 --- a/docs/src/asciidocs/writerGuide.adoc +++ /dev/null @@ -1,2291 +0,0 @@ -// View this document online at https://asciidoctor.org/docs/asciidoc-writers-guide/ -= AsciiDoc Writer's Guide -Dan Allen ; Sarah White -:description: This guide describes the basic structure of an AsciiDoc document, how to create your first AsciiDoc document, how to add other structural elements such as lists, block quotes and source code, and how to convert an AsciiDoc document to HTML, DocBook and PDF. -:keywords: AsciiDoc, Asciidoctor, syntax, reference, learn, how to, writers, authors -:page-description: {description} -:page-keywords: {keywords} -:page-layout: docs -ifndef::env-site[] -:toc: left -:icons: font -:idprefix: -:idseparator: - -:sectanchors: -:source-highlighter: highlightjs -endif::[] -:experimental: -:mdash: — -:language: asciidoc -:source-language: {language} -:table-caption!: -:example-caption!: -:figure-caption!: -:imagesdir: ../images -// Refs -:url-docs-asciidoc: https://docs.asciidoctor.org/asciidoc/latest/ -:url-quickref: {url-docs-asciidoc}syntax-quick-reference/ -:asciidoctor-ref: https://asciidoctor.org/ -:asciidoctor-gem-ref: https://rubygems.org/gems/asciidoctor -:uri-install: https://asciidoctor.org/docs/install-toolchain/ -:fopub-doc-ref: https://github.com/asciidoctor/asciidoctor-fopub/blob/master/README.adoc -:docs-ref: https://asciidoctor.org/docs -:gist-ref: https://gist.github.com -:publican-ref: https://fedorahosted.org/publican - -This guide provides a gentle introduction to AsciiDoc, a _plain text_ documentation *syntax* and *processor*. -This introduction is intended for anyone who wants to reduce the effort required to write and publish content, whether for technical documentation, articles, web pages or good ol'-fashioned prose. - -TIP: If you want to know what AsciiDoc is all about, find the answer in {url-docs-asciidoc}#about-asciidoc[About AsciiDoc]. -If you're looking for a concise survey of the AsciiDoc syntax, consult the {url-quickref}[AsciiDoc Syntax Quick Reference]. - -In this guide, you'll learn: - -- The basic structure of an AsciiDoc document -- How to create your first AsciiDoc document -- How to add other structural elements such as lists, block quotes and source code -- How to convert an AsciiDoc document to HTML, DocBook and PDF - -In addition to covering the AsciiDoc basics, this guide also suggests a set of conventions to help you create more consistent documents and maximize your writing productivity. - -Let's dive in to AsciiDoc! - -== Writing in AsciiDoc - -The goal of this section is to teach you how to compose your first AsciiDoc document. -Hopefully, when you look back, you'll agree it just makes sense. - -Your adventure with AsciiDoc begins in your favorite text editor. - -=== It's just text, mate. - -Since AsciiDoc syntax is just _plain text_, you can write an AsciiDoc document using _any_ text editor. -You don't need complex word processing programs like Microsoft Word, OpenOffice Writer or Google Docs. -In fact, you _shouldn't_ use these programs because they add cruft to your document (that you can't see) and makes conversion tedious. - -TIP: While it's true any text editor will do, I recommend selecting an editor that supports syntax highlighting for AsciiDoc. -The *[red]##c##[green]##o##[purple]##l##[fuchsia]##o##[blue]##r##* brings contrast to the text, making it easier to read. -The highlighting also confirms when you've entered the correct syntax for an inline or block element. - -The most popular application for editing plain text on macOS is *TextMate*. -A similar choice on Linux is *GEdit*. -On Windows, stay away from Notepad and Wordpad because they produce plain text which is not cross-platform friendly. -Opt instead for a competent text editor like *Notepad++*. -If you're a programmer (or a writer with an inner geek), you'll likely prefer *Vim*, *Emacs*, or *Sublime Text*, all of which are available cross-platform. -The key feature all these editors share is syntax highlighting for AsciiDoc. - -Open up your favorite text editor and get ready to write some AsciiDoc! - -=== Content is king! - -The bulk of the content in a document is paragraph text. -This is why Asciidoctor doesn't require any special markup or attributes to specify paragraph content. -You can just start typing. - -In Asciidoctor, adjacent or consecutive lines of text form a paragraph element. -To start a new paragraph after another element, such as a section title or table, hit the kbd:[RETURN] key twice to insert a blank line, and then continue typing your content. - -.Two paragraphs in an AsciiDoc document -[source] ----- -This journey begins one late Monday afternoon in Antwerp. -Our team desperately needs coffee, but none of us dare open the office door. - -To leave means code dismemberment and certain death. ----- - -.The two paragraphs rendered using the default (html5) converter and stylesheet (asciidoctor.css) -==== -This journey begins one late Monday afternoon in Antwerp. -Our team desperately needs coffee, but none of us dare open the office door. - -To leave means code dismemberment and certain death. -==== - -Just like that, *you're writing in AsciiDoc!* -As you can see, it's just like writing an e-mail. - -Save the file with a file extension of `.adoc`. - -TIP: If you want to find out how to convert the document to HTML, DocBook or PDF, skip ahead to the section on <>. - -==== Wrapped text and hard line breaks - -Since adjacent lines of text are combined into a single paragraph when Asciidoctor converts a document, that means you can wrap paragraph text or put each sentence or phrase on a separate line. -The line breaks won't appear in the output. - -However, if you want the line breaks in a paragraph to be preserved, you can either use a space followed by a plus sign (`{plus}`) or set the `hardbreaks` option on the paragraph. -This results in a visible line break (e.g., `
`) following each line. - -[source] -.Line breaks preserved using a space followed by the plus sign ({plus}) ----- -Rubies are red, + -Topazes are blue. ----- - -==== -Rubies are red, + -Topazes are blue. -==== - -[source] -.Line breaks preserved using the hardbreaks option ----- -[%hardbreaks] -Ruby is red. -Java is black. ----- - -==== -[%hardbreaks] -Ruby is red. -Java is black. -==== - -To preserve line breaks throughout your whole document, add the `hardbreaks` attribute to the document's header. - -.Line breaks preserved throughout the document using the hardbreaks attribute -[source] ----- -= Line Break Doc Title -:hardbreaks: - -Rubies are red, -Topazes are blue. ----- - -=== Admonitions - -There are certain statements you may want to draw attention to by taking them out of the content's flow and labeling them with a priority. -These are called admonitions. -It's rendered style is determined by the assigned label (i.e., value). -Asciidoctor provides five admonition style labels: - -* `NOTE` -* `TIP` -* `IMPORTANT` -* `CAUTION` -* `WARNING` - -.Caution vs. Warning -[#caution-vs-warning] -**** -When choosing the admonition type, you may find yourself getting confused between "caution" and "warning" as these words are often used interchangeably. -Here's a simple rule to help you differentiate the two: - -* Use *CAUTION* to advise the reader to _act_ carefully (i.e., exercise care). -* Use *WARNING* to inform the reader of danger, harm, or consequences that exist. - -To find a deeper analysis, see https://www.differencebetween.com/difference-between-caution-and-vs-warning/. -**** - -When you want to call attention to a single paragraph, start the first line of the paragraph with the label you want to use. -The label must be uppercase and followed by a colon (`:`). - -.Admonition paragraph syntax -[source] ----- -WARNING: Wolpertingers are known to nest in server racks. <1> <2> -Enter at your own risk. ----- -<1> The label must be uppercase and immediately followed by a colon (`:`). -<2> Separate the first line of the paragraph from the label by a single space. - -.Result: Admonition paragraph -==== -WARNING: Wolpertingers are known to nest in server racks. -Enter at your own risk. -==== - -An admonition paragraph is rendered in a callout box with the admonition label--or its corresponding icon--in the gutter. -Icons are enabled by setting the `icons` attribute on the document. - -NOTE: Admonitions can also encapsulate any block content, which we'll cover later. - -=== Mild punctuation, strong impact - -Just as we emphasize certain words and phrases when we speak, we can emphasize them in text by surrounding them with punctuation. -AsciiDoc refers to this markup as _quoted text_. - -==== Quoted text - -For instance, in an e-mail, you might "`speak`" a word louder by enclosing it in asterisks. - -[source] -I can't believe it, we *won*! - -As you would expect, the asterisks make the text *won* bold. -You can almost sense the emotion. -This is one example of quoted (i.e., formatted) text. - -NOTE: The term "`quote`" is used liberally here to apply to any symbols that surround text in order to apply emphasis or special meaning. - -Here are the forms of quoted text that AsciiDoc recognizes: - -.Bold, italic, and monospace formatting syntax -[source] ----- -bold *constrained* & **un**constrained - -italic _constrained_ & __un__constrained - -bold italic *_constrained_* & **__un__**constrained - -monospace `constrained` & ``un``constrained - -monospace bold `*constrained*` & ``**un**``constrained - -monospace italic `_constrained_` & ``__un__``constrained - -monospace bold italic `*_constrained_*` & ``**__un__**``constrained ----- - -When you want to quote text (e.g., place emphasis) somewhere other than at the boundaries of a word, you need to double up the punctuation. - -.Result: Bold, italic, and monospace text -==== -bold *constrained* & **un**constrained - -italic _constrained_ & __un__constrained - -bold italic *_constrained_* & **__un__**constrained - -monospace `constrained` & ``un``constrained - -monospace bold `*constrained*` & ``**un**``constrained - -monospace italic `_constrained_` & ``__un__``constrained - -monospace bold italic `*_constrained_*` & ``**__un__**``constrained -==== - -Any quoted text can be prefixed with an attribute list. -The first positional attribute is treated as a role. -The role can be used to apply custom styling to the text. -For instance: - -[source] -Type the word [.userinput]#asciidoc# into the search bar. - -When converting to HTML, the word "`asciidoc`" is wrapped in `` tags and the role is used as the element's CSS class: - -[source,xml] -asciidoc - -You can apply styles to the text using CSS. - -You may not always want these substitutions to take place. -In those cases, you'll need to use markup to escape the text. - -==== Preventing substitution - -If you are getting quoted text behavior where you don't want it, you can use a backslash or a passthrough macro to prevent it. - -Asciidoctor provides several approaches for preventing substitutions. - -.Backslash escaping -To prevent punctuation from being interpreted as formatting markup, precede it with a backslash (`\`). -If the formatting punctuation begins with two characters (e.g., `+__+`), you need to precede it with two backslashes (`+\\+`). -This is also how you can prevent character and attribute references from substitution. -When your document is processed, the backslash is removed so it doesn't display in your output. - -[source] ----- -\*Stars* will appear as *Stars*, not as bold text. - -\§ will appear as an entity, not the § symbol. - -\\__func__ will appear as __func__, not as emphasized text. - -\{two-semicolons} will appear {two-semicolons}, not resolved as ;;. ----- - -Asciidoctor supports several forms of the passthrough macro. - -inline pass macro:: An inline macro named `pass` that can be used to passthrough content. -Supports an optional set of substitutions. -+ -[source] ----- -pass:[content like #{variable} passed directly to the output] followed by normal content. - -content with only select substitutions applied: pass:c,a[__<{email}>__] ----- - -single and double plus:: A special syntax for preventing text from being formatted. -Only escapes special characters for compliance with the output format and doesn't support explicit substitutions. - -triple plus:: A special syntax for designating passthrough content. -Does not apply any substitutions (equivalent to the inline pass macro) and doesn't support explicit substitutions. - -double dollar (deprecated):: A deprecated special syntax for designating passthrough content. -Like the triple plus, does not apply any substitutions and doesn't support explicit substitutions. - -CAUTION: Asciidoctor does not implement the block pass macro. -Instead, you should use a <>. - -==== Inline pass macro and explicit substitutions - -To exclude a phrase from substitutions and disable escaping of special characters, enclose it in the inline pass macro. -For example, here's one way to format text as underline when generating HTML from AsciiDoc: - -[source] ----- -The text pass:[underline me] is underlined. ----- - -==== -The text pass:[underline me] is underlined. -==== - -If you want to enable ad-hoc `quotes` substitution, then assign the `macros` value to `subs` and use the inline pass macro. - ------- -[subs=+macros] <1> ----- -I better not contain *bold* or _italic_ text. -pass:quotes[But I should contain *bold* text.] <2> ----- ------- -<1> `macros` is assigned to `subs`, which allows any macros within the block to be processed. -<2> The pass macro is assigned the `quotes` value. Text within the square brackets will be formatted. - -The inline pass macro does introduce additional markup into the source code that could make it invalid in raw form. -However, the output it produces will be valid when viewed in a viewer (HTML, PDF, etc.). - -==== -[subs=+macros] ----- -I better not contain *bold* or _italic_ text. -pass:quotes[But I should contain *bold* text.] ----- -==== - -The inline pass macro also accepts shorthand values for specifying substitutions. - -* `c` = special characters -* `q` = quotes -* `a` = attributes -* `r` = replacements -* `m` = macros -* `p` = post replacements - -For example, the quotes text substitution value is assigned in the inline passthrough macro below: - -[source] ----- -The text pass:q[underline *me*] is underlined and the word "`me`" is bold. ----- - -==== -The text pass:q[underline *me*] is underlined and the word "`me`" is bold. -==== - -==== Triple plus passthrough - -The triple-plus passthrough works much the same way as the pass macro. -To exclude content from substitutions, enclose it in triple pluses (pass:[+++]). - - +++content passed directly to the output+++ followed by normal content. - -The triple-plus macro is often used to output custom HTML or XML. - -[source] ----- -The text +++underline me+++ is underlined. ----- - -==== -The text +++underline me+++ is underlined. -==== - -.Single plus enclosure - -To exclude a phrase from substitutions, enclose it in plus signs (`+`). - -[source] ----- -This +*literal*+ will appear as *literal*. ----- - -==== Replacements - -AsciiDoc also recognizes textual representations of symbols, arrows and dashes. - -[cols="2,^1l,^1l,^1,2"] -.Textual symbol replacements -|=== -|Name |Syntax |Unicode Replacement |Rendered |Notes - -|Copyright -|(C) -|© -|(C) -| - -|Registered -|(R) -|® -|(R) -| - -|Trademark -|(TM) -|™ -|(TM) -| - -|Em dash -|-- -|— -|{empty}--{empty} -|Only replaced if between two word characters, between a word character and a line boundary, or flanked by spaces. - -When flanked by space characters (e.g., `+a -- b+`), the normal spaces are replaced by thin spaces (\ ). - -|Ellipsis -|... -|… -|... -| - -|Single right arrow -|-> -|→ -|-> -| - -|Double right arrow -|=> -|⇒ -|=> -| - -|Single left arrow -|<- -|← -|<- -| - -|Double left arrow -|<= -|⇐ -|<= -| - -|Typographic apostrophe -|Sam's -|Sam’s -|Sam's -|The typewriter apostrophe is replaced with the typographic (aka curly) apostrophe. -|=== - -This mild punctuation does not take away from the readability of the text. -In fact, you could argue that it makes the text easier to read. -What's important is that these are conventions with which you are likely already familiar. - -Punctuation is used in AsciiDoc to create another very common type of element in documents, _lists!_ - -=== Lists, lists, lists - -There are three types of lists supported in AsciiDoc: - -. Unordered -. Ordered -. Description - -Unordered and ordered lists are structurally very similar. -They consist of items that are prefixed by different types of markers (i.e., bullet). -In contrast, description lists--also called variable, labeled, or term-definition lists--are collections of terms that each have their own supporting content. -Unlike unordered and ordered lists, description lists are rarely nested, though they often contain the former. - -Let's explore each type of list, then mix them together. -We'll also look at how to put complex content inside a list item. - -==== Lists of things - -If you were to create a list in an e-mail, how would you do it? -Chances are, you'd mark list items using the same characters that Asciidoctor uses to find list items. - -In the example below, each list item is marked using an asterisk (`{asterisk}`), the AsciiDoc syntax specifying an unordered list item. - -[source] ----- -* Edgar Allan Poe -* Sheri S. Tepper -* Bill Bryson ----- - -A list item's first line of text must be offset from the marker (`{asterisk}`) by at least one space. -If you prefer, you can indent list items. -Blank lines are required before and after a list. -Additionally, blank lines are permitted, but not required, between list items. - -.Rendered unordered list -==== -* Edgar Allan Poe -* Sheri S. Tepper -* Bill Bryson -==== - -You can add a title to a list by prefixing the title with a period (`.`). - -[source] ----- -.Kizmet's Favorite Authors -* Edgar Allan Poe -* Sheri S. Tepper -* Bill Bryson ----- - -.Rendered unordered list with a title -==== -.Kizmet's Favorite Authors -* Edgar Allan Poe -* Sheri S. Tepper -* Bill Bryson -==== - -Was your instinct to use a hyphen (`-`) instead of an asterisk to mark list items? -Guess what? -That works too! - -[source] ----- -- Edgar Allan Poe -- Sheri S. Tepper -- Bill Bryson ----- - -You should reserve the hyphen for lists that only have a single level because the hyphen marker (`-`) doesn't work for nested lists. -Now that we've mentioned nested lists, let's go to the next section and learn how to create lists with multiple levels. - -[#separating-lists] -.Separating Lists -**** -If you have adjacent lists, they have the tendency to want to fuse together. -To force lists apart, insert a line comment (`//`) surrounded by blank lines between the two lists. -Here's an example, where the `-` text in the line comment indicates the line serves as an "`end of list`" marker: - -[source] ----- -* Apples -* Oranges - -//- - -* Walnuts -* Almonds ----- -**** - -To nest an item, just add another asterisk (`{asterisk}`) to the marker, and another for each subsequent level. - -[source] ----- -.Possible DefOps manual locations -* West wood maze -** Maze heart -*** Reflection pool -** Secret exit -* Untracked file in git repository ----- - -.Rendered nested, unordered list -==== -.Possible DefOps manual locations -* West wood maze -** Maze heart -*** Reflection pool -** Secret exit -* Untracked file in git repository -==== - -In Asciidoctor 1.5.7 and earlier you could only have up to six (6) levels of nesting (assuming one level uses the hyphen marker). - -Since Asciidoctor 1.5.8, you can nest unordered lists to any depth. -Keep in mind, however, that some interfaces will begin flattening lists after a certain depth. -GitHub starts flattening list after 10 levels of nesting. - -[source] ----- -* level 1 -** level 2 -*** level 3 -**** level 4 -***** level 5 -* level 1 ----- - -==== -* level 1 -** level 2 -*** level 3 -**** level 4 -***** level 5 -* level 1 -==== - -While it would seem as though the number of asterisks represents the nesting level, that's not how depth is determined. -A new level is created for each unique marker encountered. -However, it's much more intuitive to follow the convention that the number of asterisks equals the level of nesting. -After all, we're shooting for plain text markup that is readable _as is_. - -==== Ordering the things - -Sometimes, we need to number the items in a list. -Instinct might tell you to prefix each item with a number, like in this next list: - -[source] ----- -1. Protons -2. Electrons -3. Neutrons ----- - -The above works, but -since the numbering is obvious, the AsciiDoc processor will insert the numbers for you if you omit them: - -[source] ----- -. Protons -. Electrons -. Neutrons ----- - -==== -. Protons -. Electrons -. Neutrons -==== - -If you decide to use number for your ordered list, you have to keep them sequential. -This differs from other lightweight markup languages. -It's one way to adjust the numbering offset of a list. -For instance, you can type: - -[source] ----- -4. Step four -5. Step five -6. Step six ----- - -However, in general the best practice is to use the `start` attribute to configure this sort of thing: - -[source] ----- -[start=4] -. Step four -. Step five -. Step six ----- - -To present the items in reverse order, add the `reversed` option: - -[source] ----- -[%reversed] -.Parts of an atom -. Protons -. Electrons -. Neutrons ----- - -==== -[%reversed] -.Parts of an atom -. Protons -. Electrons -. Neutrons -==== - -You can give a list a title by prefixing the line with a dot immediately followed by the text (without leaving any space after the dot). - -Here's an example of a list with a title: - -[source] ----- -.Parts of an atom -. Protons -. Electrons -. Neutrons ----- - -==== -.Parts of an atom -. Protons -. Electrons -. Neutrons -==== - -You create a nested item by using one or more dots in front of each the item. - -[source] ----- -. Step 1 -. Step 2 -.. Step 2a -.. Step 2b -. Step 3 ----- - -AsciiDoc selects a different number scheme for each level of nesting. -Here's how the previous list renders: - -.A nested ordered list -==== -. Step 1 -. Step 2 -.. Step 2a -.. Step 2b -. Step 3 -==== - -[TIP] -==== -Like with the asterisks in an unordered list, the number of dots in an ordered list doesn't represent the nesting level. -However, it's much more intuitive to follow this convention: - -[quote] -# of dots = level of nesting - -Again, we are shooting for plain text markup that is readable _as is_. -==== - -Asciidoctor works hard to infer the relationships between the items that are most intuitive to us humans. -Here's an example of nesting an unordered list inside of an ordered list: - -[source] ----- -. Linux -* Fedora -* Ubuntu -* Slackware -. BSD -* FreeBSD -* NetBSD ----- - -==== -. Linux -* Fedora -* Ubuntu -* Slackware -. BSD -* FreeBSD -* NetBSD -==== - -You can spread the items out and indent the nested lists if that makes it more readable for you: - -[source] ----- -. Linux - - * Fedora - * Ubuntu - * Slackware - -. BSD - - * FreeBSD - * NetBSD ----- - -The following table shows the numbering scheme used by default for each nesting level. - -.Ordered list numbering scheme by level -[cols="^2,3,3,4"] -|=== -|Level |Numbering Scheme |Examples |CSS class (HTML converter) - -|1 -|Arabic -|1. 2. 3. -|arabic - -|2 -|Lower Alpha -|a. b. c. -|loweralpha - -|3 -|Lower Roman -|i. ii. iii. -|lowerroman - -|4 -|Upper Alpha -|A. B. C. -|upperalpha - -|5 -|Upper Roman -|I. II. III. -|upperroman -|=== - -You can override the number scheme for any level by setting its style (the first positional entry in a block attribute list). -You can also set the starting number using the `start` attribute: - -[source] ----- -[lowerroman, start=5] -. Five -. Six -[loweralpha] -.. a -.. b -.. c -. Seven ----- - -==== Description lists - -A description list (often abbreviate as dlist) is useful when you need to include a description or supporting text for one or more terms. -Each item in a description list consists of: - -* one or more terms -* a separator following each term (typically a double colon, `::`) -* at least one space or endline -* the supporting content (either text, attached blocks, or both) - -Here's an example of a description list that identifies parts of a computer: - -[source] ----- -CPU:: The brain of the computer. -Hard drive:: Permanent storage for operating system and/or user files. -RAM:: Temporarily stores information the CPU uses during operation. -Keyboard:: Used to enter text or control items on the screen. -Mouse:: Used to point to and select items on your computer screen. -Monitor:: Displays information in visual form using text and graphics. ----- - -By default, the content of each item is displayed below the description when rendered. -Here's a preview of how this list is rendered: - -.A basic description list -==== -CPU:: The brain of the computer. -Hard drive:: Permanent storage for operating system and/or user files. -RAM:: Temporarily stores information the CPU uses during operation. -Keyboard:: Used to enter text or control items on the screen. -Mouse:: Used to point to and select items on your computer screen. -Monitor:: Displays information in visual form using text and graphics. -==== - -If you want the description and content to appear on the same line, add the horizontal style to the list. - -[source] ----- -[horizontal] -CPU:: The brain of the computer. -Hard drive:: Permanent storage for operating system and/or user files. -RAM:: Temporarily stores information the CPU uses during operation. ----- - -==== -[horizontal] -CPU:: The brain of the computer. -Hard drive:: Permanent storage for operating system and/or user files. -RAM:: Temporarily stores information the CPU uses during operation. -==== - -The content of a description list can be any AsciiDoc element. -For instance, we could rewrite the grocery list from above so that each aisle is a description rather than a parent outline list item. - -[source] ----- -Dairy:: -* Milk -* Eggs -Bakery:: -* Bread -Produce:: -* Bananas ----- - -==== -Dairy:: -* Milk -* Eggs -Bakery:: -* Bread -Produce:: -* Bananas -==== - -Description lists are quite lenient about whitespace, so you can spread the items out and even indent the content if that makes it more readable for you: - -[source] ----- -Dairy:: - - * Milk - * Eggs - -Bakery:: - - * Bread - -Produce:: - - * Bananas ----- - -==== Hybrid lists - -[#three-hybrid] -Finally, you can mix and match the three list types within a single hybrid list. -Asciidoctor works hard to infer the relationships between the items that are most intuitive to us humans. - -Here's a list that mixes description, ordered, and unordered list items: - -[source] ----- -Operating Systems:: - Linux::: - . Fedora - * Desktop - . Ubuntu - * Desktop - * Server - BSD::: - . FreeBSD - . NetBSD - -Cloud Providers:: - PaaS::: - . OpenShift - . CloudBees - IaaS::: - . Amazon EC2 - . Rackspace ----- - -Here's how the list is rendered: - -.A hybrid list -==== -Operating Systems:: - Linux::: - . Fedora - * Desktop - . Ubuntu - * Desktop - * Server - BSD::: - . FreeBSD - . NetBSD - -Cloud Providers:: - PaaS::: - . OpenShift - . CloudBees - IaaS::: - . Amazon EC2 - . Rackspace -==== - -You can include more complex content in a list item as well. - -=== Links and images - -AsciiDoc makes it easy to include links, images and other types of media in a document. - -==== External links - -There's nothing you have to do to make a link to a URL. -Just include the URL in the document and AsciiDoc will turn it into a link. - -Asciidoctor recognizes the following common schemes without the help of any markup. - -[#schemes] -* http -* https -* ftp -* irc -* mailto -* \email@email.com - -You can think of these like implicit macro names (the bare email address being a special case). -Since the URL in the example below begins with a protocol (in this case _https_ followed by a colon), Asciidoctor will automatically turn it into a hyperlink when it is processed. - -[source] ----- -The homepage for the Asciidoctor Project is https://asciidoctor.org. <1> ----- -<1> The trailing period will not get caught up in the link. - -To prevent automatic linking of an URL, prepend it with a backslash (`\`). - -[source] ----- -Once launched, the site will be available at \https://example.org. ----- - -If you prefer URLs to be shown with the scheme hidden, set the `hide-uri-scheme` attribute in the document's header. - -[source] ----- -:hide-uri-scheme: - -https://asciidoctor.org ----- - -When the hide-uri-scheme attribute is set, the above URL will render as follows: - -[source,xml] ----- -asciidoctor.org ----- - -Note the absence of _https_ inside the `` element. - -To attach a URL to text, enclose the text in square brackets at the end of the URL, thus making it an URL macro: - -[source] ----- -Chat with other Fedora users in the irc://irc.freenode.org/#fedora[Fedora IRC channel]. ----- - -When a URL does not start with one of the <>, or the URL is not surrounded by word boundaries, you must use the `link` macro. -The `link` macro is a stronger version of a URI macro, which you can think of like an unconstrained macro. -The URL is preceded by `link:` and followed by square brackets. -The square brackets may include optional link text. -The URL is used for the text of the link if link text is not specified. -Prior to 1.5.7, if the `linkattrs` document attribute is set, the text in square brackets is parsed as attributes, which allows a window name or role to be specified. -Since 1.5.7, attributes are parsed automatically if an equal sign is found after a comma (e.g., `[link text,window=_blank]`). - -.Anatomy of a link macro -[source] ----- -link:url[optional link text, optional target attribute, optional role attribute] ----- - -Let's consider a case where we need to use the link macro (instead of just a URI macro) to expand a link when it's not adjacent to a word boundary (i.e., unconstrained). - -[source] ----- -search/link:https://ecosia.org[Ecosia] ----- - -==== -search/link:https://ecosia.org[Ecosia] -==== - -If we didn't use the `link:` prefix in this case, the URL macro would not be detected by the parser. - -==== Target window and role attributes for links - -[#link-macro-attributes] -Prior to 1.5.7, Asciidoctor _does not_ parse attributes in the link macro by default. -If you want attributes in the link macro to be parsed, you must set the `linkattrs` document attribute in the header. -Since 1.5.7, this parsing is automatic (and the attribute is not required) if an equal sign is found after a comma. -When attribute parsing is enabled, you can then specify the name of the target window using the `window` attribute. - -[source] ----- -= Asciidoctor Document Title - -Let's view the raw HTML of the link:view-source:asciidoctor.org[Asciidoctor homepage,window=_blank]. ----- - -==== -Let's view the raw HTML of the link:view-source:asciidoctor.org[Asciidoctor homepage,window=_blank]. -==== - -Since `_blank` is the most common window name, we've introduced shorthand for it. -Just end the link text with a caret (`+^+`): - -[source] ----- -Let's view the raw HTML of the link:view-source:asciidoctor.org[Asciidoctor homepage^]. ----- - -CAUTION: If you use the caret syntax more than once in a single paragraph, you may need to escape the first occurrence with a backslash. - -When attribute parsing is enabled, you can add a role (i.e., CSS class) to the link. - -[source] ----- -Chat with other Asciidoctor users on the https://discuss.asciidoctor.org/[*mailing list*^,role=green]. ----- - -==== -Chat with other Asciidoctor users on the https://discuss.asciidoctor.org/[*mailing list*^,role=green]. -==== - -TIP: Links with attributes (including the subject and body segments on mailto links) are a feature unique to Asciidoctor. -When they're enabled, you must surround the link text in double quotes if it contains a comma. - -==== Links to relative files - -If you want to link to an external file relative to the current document, use the `link` macro in front of the file name. - -[source] ----- -link:protocol.json[Open the JSON file] ----- - -If your file is an HTML file, you can link directly to a section in the document, append a hash (`#`) followed by the section's ID to the end of the file name. - -[source] ----- -link:external.html#livereload[LiveReload] ----- - -For links to relative AsciiDoc documents cross references should be used. - -[reftext="Internal Cross References"] -==== Cross references - -A link to another location within an AsciiDoc document or between AsciiDoc documents is called a _cross reference_ (also referred to as an _xref_). - -In Asciidoctor, the inline xref macro is used to create cross references (also called in-text or page citations) to content elements (sections, blocks, or phrases) that have an ID (regardless of whether that ID is explicit or auto-generated). - -You create a cross reference by enclosing the ID of the target block or section (or the path of another document with an optional anchor) in double angled brackets. - -.Cross reference using the ID of the target section -[source] ----- -The section <> describes how to insert images into your document. ----- - -.Rendered cross reference using the ID of the target section -==== -The section <> describes how to insert images into your document. -==== - -You can also link to a block or section using the title by referencing its title, referred to as a [.term]_natural cross reference_. -The title must contain at least one space character or contain at least one uppercase letter. -(If you are using Ruby < 2.4, that uppercase letter is restricted to the basic Latin charset). - -.Cross reference using a section's title -[source] ----- -Refer to <>. ----- - -.Rendered cross reference using a section's title -==== -Refer to <>. -==== - -Converters usually use the reftext of the target as the default text of the link. -When the document is parsed, attribute references in the reftext are substituted immediately. -When the reftext is displayed, additional reftext substitutions are applied to the text (specialchars, quotes, and replacements). - -You can override the reftext of the target by specifying alternative text at the location of the cross reference. -After the ID, add a comma and then enter the custom text you want the cross reference to display. - -.Cross reference with custom xreflabel text -[source] ----- -Learn how to <>. ----- - -.Rendered cross reference using custom xreflabel text -==== -Learn how to <>. -==== - -You can also use the inline xref macro as an alternative to the double angled bracket form. - -.Inline xref macro -[source] ----- -Learn how to xref:link-macro-attributes[use attributes within the link macro]. ----- - -Cross references can also be used to create a link to a file relative to the current document. -For links to another AsciiDoc document, this is the preferred way. - -The trailing hash (`#`) means that you refer to the top of the document. - -.Cross reference to the top of a relative AsciiDoc document -[source] ----- -Refer to <> for more information. ----- - -.Converted HTML for cross reference to relative AsciiDoc document -[source,html] ----- -Refer to Document B for more information. ----- - -To link directly to a section in the document, append the section's ID after the hash (`#`). - -.Cross reference to a specific section of a relative AsciiDoc document -[source] ----- -Refer to <> for more information. ----- - -.Converted HTML for cross reference to section of a relative AsciiDoc document -[source,html] ----- -Refer to Section B for more information. ----- - -In both cases, this syntax will also work if you are inside the document you are referring to. -This is useful if you are sharing the same link across multiple documents. - -In the link that is created from the inter-document cross reference, the source file extension is replaced with the value of the `outfilesuffix` attribute. -To customize the file extension used in the target of the link, simply change the value of this attribute. - -Image references are similar to links since they are also references to URLs or files. -The difference, of course, is that they display the image in the document. - -==== Images - -To include an image on its own line (i.e., a _block image_), use the `image::` prefix in front of the file name and square brackets after it: - -[source] -image::sunset.jpg[] - -If you want to specify alt text, include it inside the square brackets: - -[source] -image::sunset.jpg[Sunset] - -You can also give the image an id, a title (i.e., caption), set its dimensions (i.e., width and height) and make it a link: - -[source] ----- -[#img-sunset] -.A mountain sunset -[link=https://www.flickr.com/photos/javh/5448336655] -image::sunset.jpg[Sunset,300,200] ----- - -The title of a block image is displayed underneath the image when rendered. -Here's a preview: - -.A hyperlinked image with caption -==== -[#img-sunset] -.A mountain sunset -[link=https://www.flickr.com/photos/javh/5448336655] -image::sunset.jpg[Sunset,300,200] -==== - -IMPORTANT: Images are resolved relative to the value of the `imagesdir` document attribute, which defaults to an empty value. -The `imagesdir` attribute can be an absolute path, relative path or base URL. -If the image target is a URL or an absolute path, the `imagesdir` prefix is _not_ added. - -TIP: You should use the `imagesdir` attribute to avoid hard coding the shared path to your images in every image macro. - -If you want to include an image inline, use the `image:` prefix instead (notice there is only one colon): - -[source] -Press the image:save.png[Save, title="Save"] button. - -For inline images, the optional title is displayed as a tooltip. - -If paragraphs and lists are the meat of the document, then titles and sections are its bones. -Let's explore how to give structure to our document. - -=== Titles, titles, titles - -AsciiDoc supports three types of titles: - -. Document title -. Section title -. Block title - -All titles are optional in AsciiDoc. -This section will define each title type and explain how and when to use them. - -==== Document title - -Just as every e-mail has a subject, every document (typically) has a title. -The title goes at the top of an AsciiDoc document. - -TIP: A document title is an _optional_ feature of an AsciiDoc document. - -To create a document title, begin the first line of the document with one equal sign followed by at least one space (``= ``), then the text of the title. -This syntax is the simplest (and thus recommended) way to declare a document title. - -Here's an example of a document title followed by an abbreviated paragraph: - -[source] ----- -= Lightweight Markup Languages - -According to Wikipedia... ----- - -The document title is part of the document header. -So, what else can go in the header? -Good question. - -===== The document header - -Notice the blank line between the title line and the first line of content in the previous example. -This blank line separates the document header from the document body (in this case a paragraph). -The document title is part of the document header. -In all, the document header contains the title, author, revision information and document-wide attributes. - -CAUTION: If the title line is not offset by a blank line, it gets interpreted as a section title, which we'll discuss later. - -Your document now has a title, but what about an author? -Just as every e-mail has a sender, every document must surely have an author. -Let's see how to add additional information to the header, including an author. - -There are two optional lines of text you can add immediately below the document title for defining common document attributes: - -Line 1:: Author name and an optional e-mail address -Line 2:: An optional revision, a date and an optional remark - -Let's add these lines to our document: - -[source] ----- -= Lightweight Markup Languages -Doc Writer -v1.0, 2012-01-01 - -According to Wikipedia... ----- - -The header now contains a document title, an author, a revision number, and a date. -This information will typically be displayed as a formatted header at the top of the output document. - -NOTE: The header, including the document title, is _not required_. -If absent, the AsciiDoc processor will happily convert whatever content is present. -The header is only used when generating a full document. -It's excluded from the output of an embedded document. - -The document header can also be used to define attributes. - -==== Document attributes - -Attributes are one of the features that sets AsciiDoc apart from other lightweight markup languages. -You can use attributes to toggle features or to store reusable or replacement content. - -Most often, attributes are defined in the document header. -There are scenarios where they can be defined inline, but we'll focus on the more common usage. - -An attribute entry consists of a name surrounded by colons at the beginning of the line followed by at least one space, then the content. -The content is optional. - -Here's an example of an attribute that holds the version of an application: - -[source] ----- -= User Guide -Doc Writer -2012-01-01 -:appversion: 1.0.0 ----- - -IMPORTANT: There should be no blank lines between the first attribute entry and the rest of the header. - -Now you can refer to this attribute anywhere in the document (where attribute substitution is performed) by surrounding the name in curly braces: - -[source] -The current version of the application is {appversion}. - -Attributes are also commonly used to store URLs, which can get quite lengthy. -Here's an example: - -[source] ----- -:fedpkg: https://apps.fedoraproject.org/packages/rubygem-asciidoctor ----- - -Here's the attribute in use: - -[source] -Information about the Asciidoctor package for Fedora can found at {fedpkg}. - -Document attributes can also be used to toggle settings or set configuration variables that control the output generated by the AsciiDoc processor. - -For example, to include a table of contents in your document, you can define the `toc` attribute: - -[source] ----- -:toc: ----- - -To undefine an attribute, place a `!` at the end of the name: - -[source] ----- -:linkcss!: ----- - -You can also set the base path to images (default: _empty_), icons (default: `./images/icons`), stylesheets (default: `./stylesheets`) and JavaScript files (default: `./javascripts`): - -[source] ----- -:imagesdir: ./images -:iconsdir: ./icons -:stylesdir: ./styles -:scriptsdir: ./js ----- - -TIP: Attribute values can also be set and overridden when invoking the AsciiDoc processor. -We'll explore that feature later. - -When you find yourself typing the same text repeatedly, or text that often needs to be updated, consider assigning it to a document attribute and use that instead. - -As your document grows, you'll want to break the content into sections, like in this guide. -That's accomplished using section titles. - -==== Section titles - -Sections partition the document into a content hierarchy. -In AsciiDoc, sections are defined using section titles. - -A section title uses the same syntax as a document title, except the line may begin with two to six equal signs instead of just a single equal sign. -The number of equal signs represents the nesting level (using a 0-based index). - -Here are all the section levels permitted in an AsciiDoc document (for an article doctype, the default), shown below the document title: - -[source] ----- -= Document Title (Level 0) - -== Level 1 Section - -=== Level 2 Section - -==== Level 3 Section - -===== Level 4 Section - -====== Level 5 Section - -== Another Level 1 Section ----- - -NOTE: When the document is converted to HTML 5 (using the built-in `html5` backend), each section title becomes a heading element where the heading level matches the number of equal signs. -For example, a level 1 section (2 equal signs) maps to an `

` element. - -Section levels cannot be chosen arbitrarily. -There are two rules you must follow: - -. A document can only have multiple level 0 sections if the `doctype` is set to `book`.footnote:[The default doctype is `article`, which only allows one level 0 section (i.e., the document title).] -. Section levels cannot be skipped when nesting sections - -For example, the following syntax is illegal: - -[source] ----- -= Document Title - -= Illegal Level 0 Section (violates rule #1) - -== First Section - -==== Illegal Nested Section (violates rule #2) ----- - -Content above the first section (after the document title) is part of the preamble. -Once the first section is reached, content is associated with the section that precedes it: - -[source] ----- -== First Section - -Content of first section - -=== Nested Section - -Content of nested section - -== Second Section - -Content of second section ----- - -TIP: In addition to the equals marker used for defining single-line section titles, Asciidoctor recognizes the hash symbol (`#`) from Markdown. -That means the outline of a Markdown document will convert just fine as an AsciiDoc document. - -To have the processor auto-number the sections, define the `sectnums` attribute in the document header: - -[source] ----- -:sectnums: ----- - -You can also use this attribute entry above any section title in the document to toggle the auto-numbering setting. -When you want to turn off the numbering, add an exclamation point to the end of the attribute name: - -[source] ----- -:sectnums!: - -== Unnumbered Section ----- - -===== Preamble - -Content between the document title and the first section is called the preamble. -If a document title is not present, this content is not wrapped in a preamble section. - -[source] ----- -= Document Title - -preamble - -another preamble paragraph - -== First Section ----- - -TIP: When using the default Asciidoctor stylesheet, this preamble is rendered in the style of a lead (i.e., larger font). - -You can also assign titles to individual elements. - -==== Block titles - -You can assign a title to any paragraph, list or delimited block element. -The title is used as the element's caption. -In most cases, the title is displayed immediately above the content. -If the content is a figure or image, the title is displayed below the content. - -A block title is defined on a line above the element. -The line must begin with a dot (`.`) and be followed immediately by the title text with no spaces in between. - -Here's an example of a list with a title: - -[source] ----- -.TODO list -- Learn the AsciiDoc syntax -- Install AsciiDoc -- Write my document in AsciiDoc ----- - -Speaking of block titles, let's dig into blocks and discover which types of blocks AsciiDoc supports. - -== Building blocks in AsciiDoc - -AsciiDoc provides a nice set of components for including non-paragraph text--such as block quotes, source code listings, sidebars and tables--in your document. -These components are referred to as _delimited blocks_ because they are surrounded by delimiter lines. - -=== Delimited blocks - -You've already seen many examples of the listing block (i.e., code block), which is surrounded by lines with four or more hyphens. - -[source] -.... ----- -This is an example of a _listing block_. -The content inside is displayed as
 text.
-----
-....
-
-Within the boundaries of a delimited block, you can enter any content or blank lines.
-The block doesn't end until the ending delimiter is found.
-The delimiters around the block determine the type of block, how the content is processed and converted and what elements are used to wrap the content in the output.
-
-Here's how the block above appears when converted to HTML and viewed in a browser:
-
-....
-This is an example of a _listing block_.
-The content inside is displayed as 
 text.
-....
-
-Here's the HTML source that is generated:
-
-[source,html]
-----
-
-
-
This is an example of a _listing block_.
-The content inside is displayed as <pre> text.
-
-
----- - -You should notice a few things about how the content is processed: - -* the HTML tag `
` is escaped
-* the endlines are preserved
-* the phrase "`listing block`" is not italicized, despite having underscores around it.
-
-Each type of block is processed according to its purpose.
-Literal blocks don't receive the full set of substitutions normally applied to a paragraph.
-Since a listing block is typically used for source code, substitutions are not desirable.
-
-The following table identifies the delimited blocks that AsciiDoc provides by default, their purpose and what substitutions are performed on its content.
-
-[cols="1,1l,1,1"]
-|===
-|Name (Style) |Line delimiter |Purpose |Substitutions
-
-|comment
-|////
-|Private notes that are not displayed in the output
-|none
-
-|example
-|====
-|Designates example content or defines an admonition block
-|normal
-
-|literal
-|....
-|Output text to be displayed exactly as entered
-|verbatim
-
-|listing, source
-|----
-|Source code or keyboard input to be displayed as entered
-|verbatim
-
-|open
-|--
-|Anonymous block that can act as any other block (except _pass_ or _table_)
-|varies
-
-|pass
-|++++
-|Raw text to be passed through unprocessed
-|none
-
-|quote, verse
-|____
-|A quotation or verse with optional attribution
-|normal
-
-|sidebar
-|****
-|Aside text displayed outside the flow of the document
-|normal
-
-|table
-|\|===
-|Used to display tabular content or advanced layouts
-|varies
-|===
-
-IMPORTANT: AsciiDoc allows delimited lines to be longer than 4 characters.
-*Don't do it.*
-Maintaining long delimiter lines is a _colossal_ waste of time, not to mention arbitrary and error prone.
-Use the minimum line length required to create a delimited block and _move on_ to drafting the content.
-The reader will never see the long delimiters anyway since they are not carried over to the output.
-
-This table shows the substitutions performed by each substitution group referenced in the previous table.
-
-|===
-|Group / Substitution |Normal |Verbatim |None
-
-h|Special chars
-|Yes
-|Yes
-|No
-
-h|Callouts
-|No
-|Yes
-|No
-
-h|Quotes
-|Yes
-|No
-|No
-
-h|Attributes
-|Yes
-|No
-|No
-
-h|Replacements
-|Yes
-|No
-|No
-
-h|Macros
-|Yes
-|No
-|No
-
-h|Post replacements
-|Yes
-|No
-|No
-|===
-
-In order to apply normal substitutions to an attribute value, surround it with single quotes.
-There are two exceptions to this behavior: At the moment normal substitutions are not applied to
-the `options` and `title` attribute values.
-
-You can control how blocks are displayed using block metadata.
-
-=== Block metadata
-
-Metadata can be assigned to any block.
-There are several types of metadata:
-
-* Title
-* Id (i.e., anchor)
-* Style (first unnamed block attribute)
-* Named block attributes
-
-Here's an example of a quote block that includes all types of metadata:
-
-[source]
-----
-.Gettysburg Address
-[[gettysburg]]
-[quote, Abraham Lincoln, Address delivered at the dedication of the Cemetery at Gettysburg]
-____
-Four score and seven years ago our fathers brought forth
-on this continent a new nation...
-
-Now we are engaged in a great civil war, testing whether
-that nation, or any nation so conceived and so dedicated,
-can long endure. ...
-____
-----
-
-Here's the metadata extracted from this block:
-
-Title:: Gettysburg Address
-Id:: gettysburg
-Style:: quote
-Named block attributes::
-  attribution::: Abraham Lincoln
-  citetitle::: Address delivered at the dedication of the Cemetery at Gettysburg
-
-TIP: A block can have multiple block attribute lines.
-The attributes will be aggregated.
-If there is a name conflict, the last attribute defined wins.
-
-Some metadata is used as supplementary content, such as the title, whereas other metadata, such as the style, controls how the block is converted.
-
-=== Masquerading blocks
-
-Some blocks can masquerade as other blocks, a feature which is controlled by the block style.
-The block style is the first positional attribute in the block attribute list.
-
-==== Admonition blocks
-
-For instance, an example block can act as an admonition block:
-
-[source]
-----
-[NOTE]
-====
-This is an example of an admonition block.
-
-Unlike an admonition paragraph, it may contain any AsciiDoc content.
-The style can be any one of the admonition labels:
-
-* NOTE
-* TIP
-* WARNING
-* CAUTION
-* IMPORTANT
-====
-----
-
-==== Listing and source code blocks
-
-At the start of this tutorial, remember how painful we said it is to insert source code into a document using a traditional word processor.
-They just aren't designed for that use case.
-*AsciiDoc is!*
-
-In fact, inserting source code in an AsciiDoc is incredibly easy.
-Just shove the raw code into a listing block.
-
-[source]
-....
-----
-require 'asciidoctor'
-
-puts Asciidoctor.convert_file 'mysample.adoc', to_file: false
-----
-....
-
-To enable syntax highlighting in the output, set the style on the block to `source` and specify the source language in the second attribute position.
-
-[source]
-....
-[source,ruby]
-----
-require 'asciidoctor'
-
-puts Asciidoctor.convert_file 'mysample.adoc', to_file: false
-----
-....
-
-You can even use source code that's in a separate file.
-Just use the AsciiDoc include directive:
-
-[source]
-....
-[source,ruby]
-----
-\include::example.rb[]
-----
-....
-
-To really show how well-suited AsciiDoc is for technical documentation, it also supports callouts in source code.
-Code callouts are used to explain lines of source code.
-The explanations are specified below the listing and keyed by number.
-Here's an example:
-
-[source]
-....
-[source,ruby]
-----
-require 'asciidoctor'  # \<1>
-
-Asciidoctor.convert_file 'mysample.adoc'  # \<2>
-----
-<1> Imports the library
-<2> Reads, parses, and converts the file
-....
-
-Here's how the callouts appear when rendered:
-
-[#eg-callouts]
-.Source code with callouts
-====
-[source,ruby]
-----
-require 'asciidoctor'  # <1>
-
-puts Asciidoctor.convert_file 'mysample.adoc'  # <2>
-----
-<1> Imports the library
-<2> Reads, parses, and converts the file
-====
-
-==== Open blocks
-
-The most versatile block of all is the open block.
-An open block can act as any other block, with the exception of _pass_ and _table_.
-Here's an example of an open block acting as a sidebar:
-
-[source]
-----
-[sidebar]
-.Related information
---
-This is aside text.
-
-It is used to present information related to the main content.
---
-----
-
-[#pass-blocks]
-==== Passthrough blocks
-
-The "`anything goes`" mechanism in AsciiDoc is the passthrough block.
-As the name implies, this block passes the content of the block directly through to the output document.
-When you've encountered a complex requirement that you cannot meet using the AsciiDoc syntax, a passthrough block can come in very handy.
-
-For example, let's say you want to embed a GitHub gist into your document.
-You can define the following passthrough block:
-
-[source]
-----
-++++
-
-++++
-----
-
-////
-[source]
-----
-++++
-
-++++
-----
-////
-
-CAUTION: Using a passthrough block couples your content to a specific output format, such as HTML.
-If you're going to use a passthrough block, we recommend using {user-ref}#conditional-preprocessor-directives[conditional preprocessor directives] to associate the format-specific content with each backend you intend to support.
-
-//The block style can be used in the absense of block delimiters to promote a paragraph to a block element.
-
-=== Delimiters optional
-
-If the content is contiguous (not interrupted by blank lines), you can forgo the use of the block delimiters and instead use the block style above a paragraph to repurpose it as one of the delimited block types.
-
-This format is often used for single-line listings:
-
-[source]
-----
-[listing]
-sudo dnf install asciidoc
-----
-
-or single-line quotes:
-
-[source]
-----
-[quote]
-Never do today what you can put off 'til tomorrow.
-----
-
-While most blocks are linear, tables give you the ability to layout content horizontally as well.
-
-=== A new perspective on tables
-
-Tables are one of the most refined areas of the AsciiDoc syntax.
-They are easy to create, easy to read in raw form and also remarkably sophisticated.
-I recommend that you use tables sparingly because they interrupt the conversation with your readers.
-When they are the most suitable way to present the information, know that you've got a powerful tool in your hands.
-
-You can think of a table as a delimited block that contains one or more bulleted lists.
-The list marker is a vertical bar (`|`).
-Each list represents one row in the table and must share the same number of items (taking into account any column or row spans).
-
-Here's a simple example of a table with two columns and three rows:
-
-[source]
-----
-[cols=2*]
-|===
-|Firefox
-|Web Browser
-
-|Ruby
-|Programming Language
-
-|TorqueBox
-|Application Server
-|===
-----
-
-The first non-blank line inside the block delimiter (`|===`) determines the number of columns.
-Since we are putting each column title on a separate line, we have to use the `cols` block attribute to explicitly state that this table has two columns.
-The `*` is the repeat operator.
-It means to repeat the column specification for the remainder of columns.
-In this case, it means to repeat no special formatting (since none is present) across 2 columns.
-
-We can make the first row of the table the header by setting the `header` option on the table.
-
-[source]
-----
-[cols=2*,options=header]
-|===
-|Name
-|Group
-
-|Firefox
-|Web Browser
-
-|Ruby
-|Programming Language
-
-...
-|===
-----
-
-You can also define the `header` option using the following shorthand:
-
-```
-[%header,cols=2*]
-```
-
-Alternatively, we could define the header row on a single line offset from the body rows by a blank line, so neither the `cols` nor the `options` attributes are required.
-
-[source]
-----
-|===
-|Name |Group
-
-|Firefox
-|Web Browser
-
-...
-|===
-----
-
-The content of each item (i.e., cell) can span multiple lines, as is the case with other lists in AsciiDoc.
-Unlike other lists, the content of each cell may contain blank lines without the need for a list continuation to hold them together.
-A new cell begins when another non-escaped vertical bar (`|`) is encountered.
-
-[source]
-----
-|===
-|Name |Group |Description
-
-|Firefox
-|Web Browser
-|Mozilla Firefox is an open-source web browser.
-It's designed for standards compliance,
-performance, portability.
-
-|Ruby
-|Programming Language
-|A programmer's best friend.
-
-...
-|===
-----
-
-You can set the relative widths of each column using _column specifiers_{mdash}a comma-separated list of relative values defined in the `cols` block attribute.
-The number of entries in the list determines the number of columns.
-
-[source]
-----
-[cols="2,3,5"]
-|===
-|Name |Group |Description
-
-|Firefox
-|Web Browser
-|Mozilla Firefox is an open-source web browser.
-It's designed for standards compliance,
-performance and portability.
-
-|Ruby
-|Programming Language
-|A programmer's best friend.
-
-...
-|===
-----
-
-If you want to include blocks or lists inside the contents of a column, you can put an `a` (for AsciiDoc) at the end of the column's relative value.
-
-[source]
-----
-[cols="2,3,5a"]
-|===
-|Name |Group |Description
-
-|Firefox
-|Web Browser
-|Mozilla Firefox is an open-source web browser.
-It's designed for:
-
-* standards compliance,
-* performance and
-* portability.
-
-|Ruby
-|Programming Language
-|A programmer's best friend.
-
-...
-|===
-----
-
-Alternatively, you can apply the AsciiDoc style to an individual cell by prefixing the vertical bar with an `a`:
-
-[source]
-----
-a|Mozilla Firefox is an open-source web browser.
-It's designed for:
-
-* standards compliance,
-* performance and
-* portability.
-----
-
-There's a whole collection of column and cell specifiers you can use to format the contents of the table, including styling and alignment.
-
-AsciiDoc tables can also be created directly from CSV data.
-Just set the `format` block attribute to `csv` and insert CSV data inside the block delimiters, either directly:
-
-[source]
-----
-[%header,format=csv]
-|===
-Artist,Track,Genre
-Baauer,Harlem Shake,Hip Hop
-The Lumineers,Ho Hey,Folk Rock
-|===
-----
-
-or using an `include::[]` directive:
-
-[source]
-----
-[%header,format=csv]
-|===
-\include::tracks.csv[]
-|===
-----
-
-Asciidoctor 0.1.3 also recognizes shorthand notation for setting CSV and DSV table formats.
-The first position of the table block delimiter (i.e., `|===`) can be replaced by a data delimiter to set the table format accordingly.
-
-Instead of specifying the `csv` format using an attribute, you can simply replace the leading pipe (`|`) with a comma (`,`).
-
-//[source]
-----
-,===
-a,b,c
-,===
-----
-
-In the same way, the `dsv` format can be specified by replacing the leading pipe (`|`) with a colon (`:`).
-
-//[source]
-----
-:===
-a:b:c
-:===
-----
-
-That's a pretty powerful option.
-
-== What else can AsciiDoc do?
-
-We've covered many of the features of the AsciiDoc syntax, but it still has much more depth.
-AsciiDoc is simple enough for a README, yet can scale to meet the requirements of a publisher.
-
-Here are some of the features that the AsciiDoc syntax supports:
-
-* footnotes
-* indexes
-* appendix, preface, dedication, partintro
-* multi-line attributes
-* preprocessor directive (conditional markup)
-* mathematical formulas
-* musical notation
-* diagrams
-* block filters
-* themes
-* custom blocks, macros and output formats
-
-Consult the {user-ref}[Asciidoctor User Manual] to continue exploring the syntax and processor capabilities.
-
-That's enough syntax for now.
-You've created your first AsciiDoc document.
-Now it's time to convert the document into a presentable format.
-This will give you a real appreciation for the power that AsciiDoc puts in your hands.
-
-== Converting your document
-
-While AsciiDoc syntax is designed to be readable in raw form, the intended audience for that format are writers and editors.
-Readers aren't going to appreciate the raw text nearly as much.
-Aesthetics matter.
-You'll want to apply nice typography with font sizes that adhere to the "`golden ratio`", colors, icons and images to give it the respect it deserves.
-That's where the Asciidoctor processor comes in (*after* you have done the writing).
-
-The Asciidoctor processor parses the document and translates it into a backend format, such as HTML, ePub, DocBook or PDF.
-Asciidoctor ships with a set of default templates in the tin, but you can customize the templates or create your own to get exactly the output you want.
-
-Before you can use the Asciidoctor processor, you have to install the {asciidoctor-gem-ref}[Asciidoctor Ruby Gem].
-Review the {uri-install}[Asciidoctor Installation Guide] if you need help to install the gem.
-
-=== Converting a document to HTML 5
-
-Asciidoctor provides both a command line tool and a Ruby API for converting AsciiDoc documents to HTML 5, Docbook 5.0 and custom output formats.
-
-To use Asciidoctor to generate an HTML document, type `asciidoctor` followed by your document's name on the command line.
-
- $ asciidoctor mysample.adoc
-
-In Asciidoctor, the *html5* backend is the default, so there's no need to specify a backend explicitly to generate an HTML 5 document.
-
-Asciidoctor also provides a Ruby API, so you can generate an HTML document directly from a Ruby application:
-
-[source,ruby]
-----
-require 'asciidoctor'
-
-Asciidoctor.convert_file 'mysample.adoc'
-----
-
-Alternatively, you can capture the HTML output into a variable instead of writing it to a file:
-
-[source,ruby]
-----
-html = Asciidoctor.convert_file 'mysample.adoc', to_file: false, header_footer: true
-puts html
-----
-
-To generate DocBook, just specify the backend option:
-
-[source,ruby]
-----
-Asciidoctor.convert_file 'mysample.adoc', backend: 'docbook'
-----
-
-One of the strengths of Asciidoctor is that it can output to a variety of formats, not just HTML.
-
-=== Converting a document to DocBook
-
-Despite the fact that writing in DocBook is inhumane, it's useful as a portable document format.
-Since AsciiDoc syntax was designed with DocBook output in mind, the conversion is very good.
-There's a corresponding DocBook element for each markup in the AsciiDoc syntax.
-
-Asciidoctor provides a Docbook 5.0 backend out of the box.
-To convert the document to Docbook 5.0, call the processor with the backend flag set to `docbook5`:
-
- $ asciidoctor -b docbook5 mysample.adoc
-
-A new XML document, named `mysample.xml`, will now be present in the current directory:
-
- $ ls -1
- mysample.adoc
- mysample.html
- mysample.xml
-
-If you're on Linux, you can view the DocBook file using Yelp:
-
- $ yelp mysample.xml
-
-DocBook is only an intermediary format in the Asciidoctor toolchain.
-You'll either feed it into a system that processes DocBook (like {publican-ref}[publican]), or you can convert it to PDF using the {fopub-doc-ref}[asciidoctor-fopub tool].
-
-=== Output galore
-
-There's really no end to the customization you can do to the output the Asciidoctor processor generates.
-We've just scratched the surface here.
-
-Check out the {user-ref}[Asciidoctor User Manual] and the {docs-ref}[Asciidoctor Docs Page] to learn more.
-
-=== Where else is AsciiDoc supported?
-
-The easiest way to experiment with AsciiDoc is online.
-AsciiDoc document in a GitHub repository or a {gist-ref}[gist] is automatically converted to HTML and rendered in the web interface.
-
-If you have a project on GitHub, you can write the README or any other documentation in AsciiDoc and the GitHub interface will show the HTML output for visitors to view.
-
-// image?
-
-Gists, in particular, are a great way to experiment with AsciiDoc.
-Just create a new gist, name the file with the extension `.adoc` and enter AsciiDoc markup.
-You can save the document as public or secret.
-If you want to try AsciiDoc without installing any software, a gist is a great way to get started.
-
-// image?
-
-While there's plenty more of the AsciiDoc syntax and toolchain to explore, you know more than enough about it to write a range of documentation, from a simple README to a comprehensive user guide.
-
-== Wrap-up
-
-Writing in AsciiDoc should be no more complex than writing an e-mail.
-All you need to compose a document in AsciiDoc is open a text editor and type regular paragraphs.
-Only when you need additional semantics or formatting do you need to introduce markup.
-Let your instinct guide you when you need to remember what punctuation to use.
-The AsciiDoc syntax is based on time-tested plain-text conventions from the last several decades of computing.
-Hopefully you agree that the markup does not detract from the readability of the text in raw form, as that's a key goal of lightweight markup languages like AsciiDoc.
-
-As humans, communication is what connects us through the ages and allows us to pass on knowledge.
-AsciiDoc enables you to focus on communicating rather than distracting you with other stuff that just gets in the way.
-Copy the text of an e-mail into a document and see how easy it to repurpose it as documentation.
-Almost immediately, you'll find your writing zen and enjoy the rewarding experience of producing.
-
-[glossary]
-== Glossary
-
-[glossary]
-admonition paragraph:: a callout paragraph that has a label or icon indicating its priority
-admonition block:: a callout block containing complex content that has a label or icon indicating its priority
-backend:: a set of templates for converting AsciiDoc source to different output format
-cross reference:: a link from one location in the document to another location marked by an anchor
-list continuation:: a plus sign (`+`) on a line by itself that connects adjacent lines of text to a list item
-quoted text:: text which is enclosed in special punctuation to give it emphasis or special meaning
\ No newline at end of file
diff --git a/docs/src/assets/fonts/Plain-Light.otf b/docs/src/assets/fonts/Plain-Light.otf
new file mode 100644
index 000000000..a1a1eacee
Binary files /dev/null and b/docs/src/assets/fonts/Plain-Light.otf differ
diff --git a/docs/src/assets/fonts/Plain-Medium.otf b/docs/src/assets/fonts/Plain-Medium.otf
new file mode 100644
index 000000000..9b2c358e3
Binary files /dev/null and b/docs/src/assets/fonts/Plain-Medium.otf differ
diff --git a/docs/src/assets/icons/favicon.png b/docs/src/assets/icons/favicon.png
new file mode 100644
index 000000000..29452eae0
Binary files /dev/null and b/docs/src/assets/icons/favicon.png differ
diff --git a/docs/src/assets/icons/favicon.svg b/docs/src/assets/icons/favicon.svg
new file mode 100644
index 000000000..6e40eb14a
--- /dev/null
+++ b/docs/src/assets/icons/favicon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/docs/src/assets/styles/admonition.scss b/docs/src/assets/styles/admonition.scss
new file mode 100644
index 000000000..2bd30df93
--- /dev/null
+++ b/docs/src/assets/styles/admonition.scss
@@ -0,0 +1,89 @@
+@import './variables.scss';
+
+.documentWrapper .admonitionblock {
+    margin: 1.4rem 0 0;
+    line-height: $admonition-content-line-height;
+
+    p {
+        font-size: calc((#{$admonition-font-factor-p} / #{$rem-base}) * 1rem);
+    }
+
+    td.content {
+        font-size: calc((#{$admonition-font-factor-p} / #{$rem-base}) * 1rem);
+        padding: 1rem 1rem 0.75rem;
+        background: var(--admonition-background);
+        width: 100%;
+        word-wrap: anywhere;
+        border: 1px solid $disabledcolor;
+        border-radius: 5px;
+        box-shadow: var(--box-shadow);
+
+        & > :not(.title):first-child {
+            margin-top: 0;
+        }
+
+        & > .title + * {
+            margin-top: 0;
+        }
+    }
+
+    pre {
+        font-size: calc((#{$admonition-font-factor-pre} / #{$rem-base}) * 1rem);
+    }
+
+    .icon {
+        position: absolute;
+        top: 0;
+        left: 0;
+        padding: 0 0.5rem;
+        height: 1.25rem;
+        font-weight: $admonition-label-font-weight;
+        text-transform: uppercase;
+        border-radius: 0.45rem;
+        transform: translate(-0.5rem, -50%);
+        font-size: $admonition-title-font-size;
+        line-height: $admonition-title-line-height;
+
+        i {
+            display: inline-flex;
+            align-items: center;
+            height: 100%;
+
+            &::after {
+                content: attr(title);
+            }
+        }
+    }
+
+    &.caution .icon {
+        background-color: $caution-color;
+        color: $caution-on-color;
+    }
+
+    &.important .icon {
+        background-color: $important-color;
+        color: $important-on-color;
+    }
+
+    &.note .icon {
+        background-color: $note-color;
+        color: $note-on-color;
+    }
+
+    &.tip .icon {
+        background-color: $tip-color;
+        color: $tip-on-color;
+    }
+
+    &.warning .icon {
+        background-color: $warning-color;
+        color: $warning-on-color;
+    }
+    
+
+    & > table {
+        table-layout: fixed;
+        position: relative;
+        width: 100%;
+    }
+}
diff --git a/docs/src/assets/styles/grid.scss b/docs/src/assets/styles/grid.scss
new file mode 100644
index 000000000..5b879ffe5
--- /dev/null
+++ b/docs/src/assets/styles/grid.scss
@@ -0,0 +1,826 @@
+/*!
+ * Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.4/customize/)
+ */
+/*!
+ * Bootstrap v3.4.1 (https://getbootstrap.com/)
+ * Copyright 2011-2019 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+
+.container {
+    padding-right: 15px;
+    padding-left: 15px;
+    margin-right: auto;
+    margin-left: auto;
+}
+@media (min-width: 768px) {
+    .container {
+        width: 750px;
+    }
+}
+@media (min-width: 992px) {
+    .container {
+        width: 970px;
+    }
+}
+@media (min-width: 1200px) {
+    .container {
+        width: 1170px;
+    }
+}
+.container-fluid {
+    padding-right: 15px;
+    padding-left: 15px;
+    margin-right: auto;
+    margin-left: auto;
+}
+.row {
+    margin-right: -15px;
+    margin-left: -15px;
+}
+.row-no-gutters {
+    margin-right: 0;
+    margin-left: 0;
+}
+.row-no-gutters [class*='col-'] {
+    padding-right: 0;
+    padding-left: 0;
+}
+.col-xs-1,
+.col-sm-1,
+.col-md-1,
+.col-lg-1,
+.col-xs-2,
+.col-sm-2,
+.col-md-2,
+.col-lg-2,
+.col-xs-3,
+.col-sm-3,
+.col-md-3,
+.col-lg-3,
+.col-xs-4,
+.col-sm-4,
+.col-md-4,
+.col-lg-4,
+.col-xs-5,
+.col-sm-5,
+.col-md-5,
+.col-lg-5,
+.col-xs-6,
+.col-sm-6,
+.col-md-6,
+.col-lg-6,
+.col-xs-7,
+.col-sm-7,
+.col-md-7,
+.col-lg-7,
+.col-xs-8,
+.col-sm-8,
+.col-md-8,
+.col-lg-8,
+.col-xs-9,
+.col-sm-9,
+.col-md-9,
+.col-lg-9,
+.col-xs-10,
+.col-sm-10,
+.col-md-10,
+.col-lg-10,
+.col-xs-11,
+.col-sm-11,
+.col-md-11,
+.col-lg-11,
+.col-xs-12,
+.col-sm-12,
+.col-md-12,
+.col-lg-12 {
+    position: relative;
+    min-height: 1px;
+    padding-right: 15px;
+    padding-left: 15px;
+}
+.col-xs-1,
+.col-xs-2,
+.col-xs-3,
+.col-xs-4,
+.col-xs-5,
+.col-xs-6,
+.col-xs-7,
+.col-xs-8,
+.col-xs-9,
+.col-xs-10,
+.col-xs-11,
+.col-xs-12 {
+    float: left;
+}
+.col-xs-12 {
+    width: 100%;
+}
+.col-xs-11 {
+    width: 91.66666667%;
+}
+.col-xs-10 {
+    width: 83.33333333%;
+}
+.col-xs-9 {
+    width: 75%;
+}
+.col-xs-8 {
+    width: 66.66666667%;
+}
+.col-xs-7 {
+    width: 58.33333333%;
+}
+.col-xs-6 {
+    width: 50%;
+}
+.col-xs-5 {
+    width: 41.66666667%;
+}
+.col-xs-4 {
+    width: 33.33333333%;
+}
+.col-xs-3 {
+    width: 25%;
+}
+.col-xs-2 {
+    width: 16.66666667%;
+}
+.col-xs-1 {
+    width: 8.33333333%;
+}
+.col-xs-pull-12 {
+    right: 100%;
+}
+.col-xs-pull-11 {
+    right: 91.66666667%;
+}
+.col-xs-pull-10 {
+    right: 83.33333333%;
+}
+.col-xs-pull-9 {
+    right: 75%;
+}
+.col-xs-pull-8 {
+    right: 66.66666667%;
+}
+.col-xs-pull-7 {
+    right: 58.33333333%;
+}
+.col-xs-pull-6 {
+    right: 50%;
+}
+.col-xs-pull-5 {
+    right: 41.66666667%;
+}
+.col-xs-pull-4 {
+    right: 33.33333333%;
+}
+.col-xs-pull-3 {
+    right: 25%;
+}
+.col-xs-pull-2 {
+    right: 16.66666667%;
+}
+.col-xs-pull-1 {
+    right: 8.33333333%;
+}
+.col-xs-pull-0 {
+    right: auto;
+}
+.col-xs-push-12 {
+    left: 100%;
+}
+.col-xs-push-11 {
+    left: 91.66666667%;
+}
+.col-xs-push-10 {
+    left: 83.33333333%;
+}
+.col-xs-push-9 {
+    left: 75%;
+}
+.col-xs-push-8 {
+    left: 66.66666667%;
+}
+.col-xs-push-7 {
+    left: 58.33333333%;
+}
+.col-xs-push-6 {
+    left: 50%;
+}
+.col-xs-push-5 {
+    left: 41.66666667%;
+}
+.col-xs-push-4 {
+    left: 33.33333333%;
+}
+.col-xs-push-3 {
+    left: 25%;
+}
+.col-xs-push-2 {
+    left: 16.66666667%;
+}
+.col-xs-push-1 {
+    left: 8.33333333%;
+}
+.col-xs-push-0 {
+    left: auto;
+}
+.col-xs-offset-12 {
+    margin-left: 100%;
+}
+.col-xs-offset-11 {
+    margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+    margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+    margin-left: 75%;
+}
+.col-xs-offset-8 {
+    margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+    margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+    margin-left: 50%;
+}
+.col-xs-offset-5 {
+    margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+    margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+    margin-left: 25%;
+}
+.col-xs-offset-2 {
+    margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+    margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+    margin-left: 0%;
+}
+@media (min-width: 768px) {
+    .col-sm-1,
+    .col-sm-2,
+    .col-sm-3,
+    .col-sm-4,
+    .col-sm-5,
+    .col-sm-6,
+    .col-sm-7,
+    .col-sm-8,
+    .col-sm-9,
+    .col-sm-10,
+    .col-sm-11,
+    .col-sm-12 {
+        float: left;
+    }
+    .col-sm-12 {
+        width: 100%;
+    }
+    .col-sm-11 {
+        width: 91.66666667%;
+    }
+    .col-sm-10 {
+        width: 83.33333333%;
+    }
+    .col-sm-9 {
+        width: 75%;
+    }
+    .col-sm-8 {
+        width: 66.66666667%;
+    }
+    .col-sm-7 {
+        width: 58.33333333%;
+    }
+    .col-sm-6 {
+        width: 50%;
+    }
+    .col-sm-5 {
+        width: 41.66666667%;
+    }
+    .col-sm-4 {
+        width: 33.33333333%;
+    }
+    .col-sm-3 {
+        width: 25%;
+    }
+    .col-sm-2 {
+        width: 16.66666667%;
+    }
+    .col-sm-1 {
+        width: 8.33333333%;
+    }
+    .col-sm-pull-12 {
+        right: 100%;
+    }
+    .col-sm-pull-11 {
+        right: 91.66666667%;
+    }
+    .col-sm-pull-10 {
+        right: 83.33333333%;
+    }
+    .col-sm-pull-9 {
+        right: 75%;
+    }
+    .col-sm-pull-8 {
+        right: 66.66666667%;
+    }
+    .col-sm-pull-7 {
+        right: 58.33333333%;
+    }
+    .col-sm-pull-6 {
+        right: 50%;
+    }
+    .col-sm-pull-5 {
+        right: 41.66666667%;
+    }
+    .col-sm-pull-4 {
+        right: 33.33333333%;
+    }
+    .col-sm-pull-3 {
+        right: 25%;
+    }
+    .col-sm-pull-2 {
+        right: 16.66666667%;
+    }
+    .col-sm-pull-1 {
+        right: 8.33333333%;
+    }
+    .col-sm-pull-0 {
+        right: auto;
+    }
+    .col-sm-push-12 {
+        left: 100%;
+    }
+    .col-sm-push-11 {
+        left: 91.66666667%;
+    }
+    .col-sm-push-10 {
+        left: 83.33333333%;
+    }
+    .col-sm-push-9 {
+        left: 75%;
+    }
+    .col-sm-push-8 {
+        left: 66.66666667%;
+    }
+    .col-sm-push-7 {
+        left: 58.33333333%;
+    }
+    .col-sm-push-6 {
+        left: 50%;
+    }
+    .col-sm-push-5 {
+        left: 41.66666667%;
+    }
+    .col-sm-push-4 {
+        left: 33.33333333%;
+    }
+    .col-sm-push-3 {
+        left: 25%;
+    }
+    .col-sm-push-2 {
+        left: 16.66666667%;
+    }
+    .col-sm-push-1 {
+        left: 8.33333333%;
+    }
+    .col-sm-push-0 {
+        left: auto;
+    }
+    .col-sm-offset-12 {
+        margin-left: 100%;
+    }
+    .col-sm-offset-11 {
+        margin-left: 91.66666667%;
+    }
+    .col-sm-offset-10 {
+        margin-left: 83.33333333%;
+    }
+    .col-sm-offset-9 {
+        margin-left: 75%;
+    }
+    .col-sm-offset-8 {
+        margin-left: 66.66666667%;
+    }
+    .col-sm-offset-7 {
+        margin-left: 58.33333333%;
+    }
+    .col-sm-offset-6 {
+        margin-left: 50%;
+    }
+    .col-sm-offset-5 {
+        margin-left: 41.66666667%;
+    }
+    .col-sm-offset-4 {
+        margin-left: 33.33333333%;
+    }
+    .col-sm-offset-3 {
+        margin-left: 25%;
+    }
+    .col-sm-offset-2 {
+        margin-left: 16.66666667%;
+    }
+    .col-sm-offset-1 {
+        margin-left: 8.33333333%;
+    }
+    .col-sm-offset-0 {
+        margin-left: 0%;
+    }
+}
+@media (min-width: 992px) {
+    .col-md-1,
+    .col-md-2,
+    .col-md-3,
+    .col-md-4,
+    .col-md-5,
+    .col-md-6,
+    .col-md-7,
+    .col-md-8,
+    .col-md-9,
+    .col-md-10,
+    .col-md-11,
+    .col-md-12 {
+        float: left;
+    }
+    .col-md-12 {
+        width: 100%;
+    }
+    .col-md-11 {
+        width: 91.66666667%;
+    }
+    .col-md-10 {
+        width: 83.33333333%;
+    }
+    .col-md-9 {
+        width: 75%;
+    }
+    .col-md-8 {
+        width: 66.66666667%;
+    }
+    .col-md-7 {
+        width: 58.33333333%;
+    }
+    .col-md-6 {
+        width: 50%;
+    }
+    .col-md-5 {
+        width: 41.66666667%;
+    }
+    .col-md-4 {
+        width: 33.33333333%;
+    }
+    .col-md-3 {
+        width: 25%;
+    }
+    .col-md-2 {
+        width: 16.66666667%;
+    }
+    .col-md-1 {
+        width: 8.33333333%;
+    }
+    .col-md-pull-12 {
+        right: 100%;
+    }
+    .col-md-pull-11 {
+        right: 91.66666667%;
+    }
+    .col-md-pull-10 {
+        right: 83.33333333%;
+    }
+    .col-md-pull-9 {
+        right: 75%;
+    }
+    .col-md-pull-8 {
+        right: 66.66666667%;
+    }
+    .col-md-pull-7 {
+        right: 58.33333333%;
+    }
+    .col-md-pull-6 {
+        right: 50%;
+    }
+    .col-md-pull-5 {
+        right: 41.66666667%;
+    }
+    .col-md-pull-4 {
+        right: 33.33333333%;
+    }
+    .col-md-pull-3 {
+        right: 25%;
+    }
+    .col-md-pull-2 {
+        right: 16.66666667%;
+    }
+    .col-md-pull-1 {
+        right: 8.33333333%;
+    }
+    .col-md-pull-0 {
+        right: auto;
+    }
+    .col-md-push-12 {
+        left: 100%;
+    }
+    .col-md-push-11 {
+        left: 91.66666667%;
+    }
+    .col-md-push-10 {
+        left: 83.33333333%;
+    }
+    .col-md-push-9 {
+        left: 75%;
+    }
+    .col-md-push-8 {
+        left: 66.66666667%;
+    }
+    .col-md-push-7 {
+        left: 58.33333333%;
+    }
+    .col-md-push-6 {
+        left: 50%;
+    }
+    .col-md-push-5 {
+        left: 41.66666667%;
+    }
+    .col-md-push-4 {
+        left: 33.33333333%;
+    }
+    .col-md-push-3 {
+        left: 25%;
+    }
+    .col-md-push-2 {
+        left: 16.66666667%;
+    }
+    .col-md-push-1 {
+        left: 8.33333333%;
+    }
+    .col-md-push-0 {
+        left: auto;
+    }
+    .col-md-offset-12 {
+        margin-left: 100%;
+    }
+    .col-md-offset-11 {
+        margin-left: 91.66666667%;
+    }
+    .col-md-offset-10 {
+        margin-left: 83.33333333%;
+    }
+    .col-md-offset-9 {
+        margin-left: 75%;
+    }
+    .col-md-offset-8 {
+        margin-left: 66.66666667%;
+    }
+    .col-md-offset-7 {
+        margin-left: 58.33333333%;
+    }
+    .col-md-offset-6 {
+        margin-left: 50%;
+    }
+    .col-md-offset-5 {
+        margin-left: 41.66666667%;
+    }
+    .col-md-offset-4 {
+        margin-left: 33.33333333%;
+    }
+    .col-md-offset-3 {
+        margin-left: 25%;
+    }
+    .col-md-offset-2 {
+        margin-left: 16.66666667%;
+    }
+    .col-md-offset-1 {
+        margin-left: 8.33333333%;
+    }
+    .col-md-offset-0 {
+        margin-left: 0%;
+    }
+}
+@media (min-width: 1200px) {
+    .col-lg-1,
+    .col-lg-2,
+    .col-lg-3,
+    .col-lg-4,
+    .col-lg-5,
+    .col-lg-6,
+    .col-lg-7,
+    .col-lg-8,
+    .col-lg-9,
+    .col-lg-10,
+    .col-lg-11,
+    .col-lg-12 {
+        float: left;
+    }
+    .col-lg-12 {
+        width: 100%;
+    }
+    .col-lg-11 {
+        width: 91.66666667%;
+    }
+    .col-lg-10 {
+        width: 83.33333333%;
+    }
+    .col-lg-9 {
+        width: 75%;
+    }
+    .col-lg-8 {
+        width: 66.66666667%;
+    }
+    .col-lg-7 {
+        width: 58.33333333%;
+    }
+    .col-lg-6 {
+        width: 50%;
+    }
+    .col-lg-5 {
+        width: 41.66666667%;
+    }
+    .col-lg-4 {
+        width: 33.33333333%;
+    }
+    .col-lg-3 {
+        width: 25%;
+    }
+    .col-lg-2 {
+        width: 16.66666667%;
+    }
+    .col-lg-1 {
+        width: 8.33333333%;
+    }
+    .col-lg-pull-12 {
+        right: 100%;
+    }
+    .col-lg-pull-11 {
+        right: 91.66666667%;
+    }
+    .col-lg-pull-10 {
+        right: 83.33333333%;
+    }
+    .col-lg-pull-9 {
+        right: 75%;
+    }
+    .col-lg-pull-8 {
+        right: 66.66666667%;
+    }
+    .col-lg-pull-7 {
+        right: 58.33333333%;
+    }
+    .col-lg-pull-6 {
+        right: 50%;
+    }
+    .col-lg-pull-5 {
+        right: 41.66666667%;
+    }
+    .col-lg-pull-4 {
+        right: 33.33333333%;
+    }
+    .col-lg-pull-3 {
+        right: 25%;
+    }
+    .col-lg-pull-2 {
+        right: 16.66666667%;
+    }
+    .col-lg-pull-1 {
+        right: 8.33333333%;
+    }
+    .col-lg-pull-0 {
+        right: auto;
+    }
+    .col-lg-push-12 {
+        left: 100%;
+    }
+    .col-lg-push-11 {
+        left: 91.66666667%;
+    }
+    .col-lg-push-10 {
+        left: 83.33333333%;
+    }
+    .col-lg-push-9 {
+        left: 75%;
+    }
+    .col-lg-push-8 {
+        left: 66.66666667%;
+    }
+    .col-lg-push-7 {
+        left: 58.33333333%;
+    }
+    .col-lg-push-6 {
+        left: 50%;
+    }
+    .col-lg-push-5 {
+        left: 41.66666667%;
+    }
+    .col-lg-push-4 {
+        left: 33.33333333%;
+    }
+    .col-lg-push-3 {
+        left: 25%;
+    }
+    .col-lg-push-2 {
+        left: 16.66666667%;
+    }
+    .col-lg-push-1 {
+        left: 8.33333333%;
+    }
+    .col-lg-push-0 {
+        left: auto;
+    }
+    .col-lg-offset-12 {
+        margin-left: 100%;
+    }
+    .col-lg-offset-11 {
+        margin-left: 91.66666667%;
+    }
+    .col-lg-offset-10 {
+        margin-left: 83.33333333%;
+    }
+    .col-lg-offset-9 {
+        margin-left: 75%;
+    }
+    .col-lg-offset-8 {
+        margin-left: 66.66666667%;
+    }
+    .col-lg-offset-7 {
+        margin-left: 58.33333333%;
+    }
+    .col-lg-offset-6 {
+        margin-left: 50%;
+    }
+    .col-lg-offset-5 {
+        margin-left: 41.66666667%;
+    }
+    .col-lg-offset-4 {
+        margin-left: 33.33333333%;
+    }
+    .col-lg-offset-3 {
+        margin-left: 25%;
+    }
+    .col-lg-offset-2 {
+        margin-left: 16.66666667%;
+    }
+    .col-lg-offset-1 {
+        margin-left: 8.33333333%;
+    }
+    .col-lg-offset-0 {
+        margin-left: 0%;
+    }
+}
+.clearfix:before,
+.clearfix:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after {
+    display: table;
+    content: ' ';
+}
+.clearfix:after,
+.container:after,
+.container-fluid:after,
+.row:after {
+    clear: both;
+}
+.center-block {
+    display: block;
+    margin-right: auto;
+    margin-left: auto;
+}
+.pull-right {
+    float: right !important;
+}
+.pull-left {
+    float: left !important;
+}
+.hide {
+    display: none !important;
+}
+.show {
+    display: block !important;
+}
+.invisible {
+    visibility: hidden;
+}
+.text-hide {
+    font: 0/0 a;
+    color: transparent;
+    text-shadow: none;
+    background-color: transparent;
+    border: 0;
+}
+.hidden {
+    display: none !important;
+}
+.affix {
+    position: fixed;
+}
diff --git a/docs/src/assets/styles/highlight.scss b/docs/src/assets/styles/highlight.scss
new file mode 100644
index 000000000..8a1bc83ea
--- /dev/null
+++ b/docs/src/assets/styles/highlight.scss
@@ -0,0 +1,90 @@
+@import './variables.scss';
+
+/*! Adapted from the GitHub style by Vasily Polovnyov  */
+.hljs-comment,
+.hljs-quote {
+    color: $highlight-grey;
+    font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-subst {
+    color: var(--color-jet-70);
+    font-weight: $font-weight-bold;
+}
+
+.hljs-number, 
+.hljs-literal,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag 
+.hljs-attr {
+    color: var(--highlight-green);
+}
+
+.hljs-string,
+.hljs-doctag {
+    color: var(--highlight-purple);
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-selector-id {
+    color: var(--highlight-darkred);
+    font-weight: $font-weight-bold;
+}
+
+.hljs-subst {
+    font-weight: normal;
+}
+
+.hljs-type,
+.hljs-class .hljs-title {
+    color: var(--highlight-blue);
+    font-weight: $font-weight-bold;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-attribute {
+    color: var(--highlight-darkblue);
+    font-weight: normal;
+}
+
+.hljs-regexp,
+.hljs-link {
+    color: $highlight-lightgreen;
+}
+
+.hljs-symbol,
+.hljs-bullet {
+    color: var(--highlight-violet);
+}
+
+.hljs-built_in,
+.hljs-builtin-name {
+    color: var(--highlight-lightblue);
+}
+
+.hljs-meta {
+    color: $highlight-lightgrey;
+    font-weight: $font-weight-bold;
+}
+
+.hljs-deletion {
+    background: $highlight-peach;
+}
+
+.hljs-addition {
+    background: $highlight-fadedgreen;
+}
+
+.hljs-emphasis {
+    font-style: italic;
+    font-size: $font-size-small;
+}
+
+.hljs-strong {
+    font-weight: $font-weight-bold;
+}
diff --git a/docs/src/assets/styles/index.scss b/docs/src/assets/styles/index.scss
new file mode 100644
index 000000000..c29b9db81
--- /dev/null
+++ b/docs/src/assets/styles/index.scss
@@ -0,0 +1,590 @@
+@import './variables.scss';
+@import './padding.scss';
+@import './margin.scss';
+
+@font-face {
+    font-family: 'Optimo-Plain';
+    src: url('../fonts/Plain-Medium.otf') format('opentype');
+    font-weight: $font-weight-bold;
+    font-style: normal;
+    font-display: swap;
+}
+
+@font-face {
+    font-family: 'Optimo-Plain';
+    src: url('../fonts/Plain-Light.otf') format('opentype');
+    font-weight: $font-weight-normal;
+    font-style: normal;
+    font-display: swap;
+}
+
+html {
+    scroll-behavior: smooth;
+}
+
+body {
+    margin: $gutter;
+    padding: $gutter;
+    font-family: 'Optimo-Plain';
+    font-size: $font-size-normal;
+}
+
+main {
+    display: flow-root;
+    background-color: var(--body-background-color);
+}
+
+main.withHeaderFooter {
+    padding-top: 51px;
+    display: flex;
+    min-height: 100vh;
+}
+
+* {
+    box-sizing: border-box;
+}
+
+a {
+    text-decoration: none;
+}
+
+.m-0 {
+    margin: $gutter;
+}
+
+.containerWrapper {
+    padding: 10px 25px;
+}
+
+
+.d-inline-block {
+    display: inline-block;
+}
+
+/*active class with background*/
+
+.activelink {
+    background: $hovercolor;
+    color: var(--secondary-color);
+}
+
+/*end active class with background*/
+
+/*active class without background*/
+/*to override document componet style used important*/
+.active {
+    color: var(--secondary-color) !important;
+}
+
+/*active class without background*/
+
+/*visited class*/
+
+.visited {
+    color: $disabledcolor;
+}
+
+/*end visited class*/
+
+.introWrapper {
+    display: flex;
+    margin-top: $document-margin-top;
+}
+
+button {
+    cursor: pointer;
+}
+
+.widthAuto {
+    width: auto;
+    img {
+        width: auto;
+        max-width: 100%;
+    }
+}
+
+.bordered img {
+  border: 1px solid var(--border-color);
+}
+
+.displayNone {
+    display: none;
+}
+
+.icon {
+    color: var(--icon-color);
+}
+
+/*Tags style start*/
+
+.video {
+   width: 800px;
+   height: 600px;
+}
+
+.tag {
+    border-radius: $tag-border-radius;
+    display: inline-block;
+    font-size: $tag-font-size !important;
+    font-weight: $tag-font-weight !important;
+    height: $tag-height;
+    line-height: $tag-line-height !important;
+    margin-right: $tag-margin-right;
+    text-align: center;
+    min-width: $tag-width;
+    padding: $tag-padding;
+    color: $tag-font-color;
+}
+
+.version {
+    display: inline-block;
+    font-size: $font-size-small;
+    font-weight: $font-weight-bold;
+    height: 25px;
+    line-height: $line-height-doc;
+    text-align: center;
+    min-width: $tag-width;
+    margin: 5px;
+    padding: $tag-padding;
+    color: var(--primary-color);
+    border: solid 1px;
+    border-color: $tip-color;
+}
+
+
+.eaTag {
+    border-radius: $beta-border-radius;
+    display: inline-block;
+    font-size: 13px;
+    font-weight: $font-weight-normal;
+    height: 22px;
+    line-height: $line-height-doc;
+    text-align: center;
+    min-width: $tag-width;
+    padding: $beta-padding;
+    color: $tag-font-color;
+    margin-right: 1px;
+}
+
+.beta {
+    border-radius: $beta-border-radius;
+    display: inline-block;
+    font-size: 13px;
+    font-weight: $font-weight-normal;
+    height: 22px;
+    line-height: $line-height-doc;
+    text-align: center;
+    min-width: $tag-width;
+    padding: $beta-padding;
+    color: $tag-font-color;
+    margin-right: 1px;
+}
+
+
+
+.blueBackground {
+    background-color: $note-color;
+}
+
+.purpleBackground {
+    background-color: $caution-color;
+}
+
+.redBackground {
+    background-color: $important-color;
+}
+
+.greenBackground {
+    background-color: $tip-color;
+}
+
+.greyBackground {
+    background-color: #C0C6CF;
+}
+
+.greyDarkBackground {
+    background-color: #A5ACB9;
+}
+
+.greyLightBackground {
+    background-color: #EAEDF2;
+}
+
+.orangeBackground {
+    background-color: $warning-color;
+}
+
+.yellowBackground {
+    background-color: $tag-color-yellow;
+}
+
+.noBackground {
+    background-color: $tag-color-white;
+}
+
+.lightBackground {
+    background-color: $tag-color-light;
+}
+
+.eaBackground  {
+    background-color: #8c62f5;
+}
+.betaBackground {
+    background-color: #06BF7F;
+}
+
+
+
+/*Tags style end*/
+
+/* Div box style start */
+
+.announcementBlock {
+    border: 0.5px solid $disabledcolor;
+    font-color: var(--announcement-font-color);
+    border-radius: 10px;
+    height: auto;
+    width: 100%;
+    padding: $padding-sm $padding-sm $padding-sm $padding-md;
+    background-color: var(--announcement-block-color);
+    }
+
+.boxDiv {
+    padding: 15px;
+    display: inline-block;
+    margin: 10px;
+    box-shadow: var(--box-shadow);
+    border-top: 0.5px solid $lightgrey;
+    border-radius: 10px;
+    &:hover {
+        box-shadow: var(--box-shadow-hover);
+    }
+}
+
+.container {
+    margin:0 0 30px 0;
+    padding: 5px;
+    width: auto;
+
+}
+
+.homeHeader {
+    display: inline-block;
+    padding: 5px;
+    width: 100%;
+    margin: 0;
+    vertical-align: top;
+}
+
+.homeHeaderText {
+      display: inline-block;
+      padding: 5px 5px 5px 20px;
+      width: 600px;
+      max-width: 33%;
+      margin: 0;
+      vertical-align: top;
+}
+
+.homeBullet {
+    border-radius: 25pt;
+    display: inline-block;
+    font-size: 14px;
+    font-weight: $font-weight-bold;
+    line-height: $tag-line-height !important;
+    margin-right: $tag-margin-right;
+    text-align: center;
+    min-width: auto;
+    padding: 0 8px 0 8px;
+    color: $darkblue;
+}
+
+.blockHome{
+    border-top: 0.5px solid var(--border-color);
+    border-bottom: 0.5px solid var(--border-color);
+    margin: 20px 10px 5px 10px;
+
+}
+
+.blockHomeContent{
+    padding: 15px;
+    display: inline-block;
+    margin: 10px;
+}
+
+.boxHalfWidth {
+    display: inline-block;
+    padding: 15px;
+    height: 225px;
+    max-height: 500px;
+    width: 475px;
+    max-width: 500px;
+    margin: 10px;
+    box-shadow: var(--box-shadow);
+    border-radius: 10px;
+    &:hover {
+        box-shadow: var(--box-shadow-hover);
+    }
+}
+
+.boxFullWidth {
+    width: 100%;
+    box-shadow: var(--box-shadow);
+    border: 1px solid var(--border-color);
+    margin: 10px;
+    padding: 15px;
+}
+
+.divider {
+    border-bottom: 0.5px solid var(--border-color);
+    display: block;
+    width: 100%;
+    margin: 5px auto;
+}
+
+
+.boxBody {
+    font-size: 13px;
+    font-weight: $font-weight-normal;
+    line-height: 18pt;
+    color: var(--primary-color);
+    padding: 5px;
+}
+
+.introList {
+    font-size: 13px;
+    font-weight: $font-weight-normal;
+    line-height: 18pt;
+    color: var(--primary-color);
+    padding: 5px 5px $padding-md 5px;
+    overflow: auto;
+}
+
+.boxAuto {
+    border: 0.5px solid $disabledcolor;
+	height: auto;
+	width: 100%;
+	padding: 0 0 0 2px;
+}
+
+.tableContainer {
+    border: 0.5px solid $disabledcolor;
+    padding: 0 0 0 5px;
+    overflow-x: auto;
+}
+
+.videoContainer {
+    border-radius: 10px;
+    overflow-x: auto;
+    width: 100%;
+    box-shadow: var(--box-shadow);
+    border: 1px solid var(--border-color);
+    margin: 10px;
+    padding: 15px;
+}
+
+summary.title  {
+    font-size: $font-size-summ-title;
+    margin-top: $margin-sm;
+    margin-left: 3px;
+    font-weight: $font-weight-normal;
+    line-height: $line-height-doc;
+    color: var(--primary-color);
+
+}
+
+
+.introTile {
+    padding: $padding-md;
+    display: inline-block;
+    margin: 1px;
+    width: 100%;
+    box-shadow: var(--box-shadow);
+    border-top: 0.5px solid $lightgrey;
+    height: 700px;
+    border-radius: 10px;
+    &:hover {
+        box-shadow: var(--box-shadow-hover);
+    }
+}
+
+.cardHead {
+    border-bottom: 1px solid var(--border-color);
+    text-align: center;
+    color: var(--primary-color);
+    font-size: $font-size-h5;
+    margin: auto;
+    padding: 10px;
+    font-weight: $font-weight-bold;
+
+}
+
+.cardBlockHeading {
+       margin-top: $margin-lg;
+       padding-bottom: $padding-sm;
+       border-bottom: 1px solid var(--border-color);
+       font-size: 26px;
+       font-weight: $font-weight-bold;
+       text-align: center;
+}
+
+
+a.anchor {
+    position: absolute;
+    text-decoration: none;
+    width: 1.75ex;
+    margin-left: -1.5ex;
+    visibility: hidden;
+    font-size: .8em;
+    font-weight: 400;
+    padding-top: 0.05em;
+}
+
+
+.introCard     {
+    padding: 15px;
+    display: inline-block;
+    position: relative;
+    height: 225px;
+    max-height: 500px;
+    width: 300px;
+    max-width:400px;
+    margin: 10px;
+    box-shadow: var(--box-shadow);
+    border-radius: 10px;
+    &:hover {
+        box-shadow: var(--box-shadow-hover);
+    }
+}
+
+
+
+/* Div box style end */
+
+/*Scrollbar styling start*/
+::-webkit-scrollbar {
+    width: 0.4em;
+}
+
+::-webkit-scrollbar {
+    height: 0.4em;
+}
+
+::-webkit-scrollbar-track {
+    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
+    border-radius: 10px;
+}
+
+::-webkit-scrollbar-thumb {
+    background-color: var(--scrollbar-color);
+    outline: none;
+    border-radius: 4px;
+}
+
+/* Scrollbar styling end*/
+@media screen and (min-width: 767px) and (max-width: 1024px) {
+    .documentBody {
+        width: calc(100% - 260px);
+    }
+
+    .homeBanner {
+        display: none;
+    }
+
+    .homeHeader {
+         width: 100%;
+         max-width: 100%;
+        }
+
+    .documentWrapper {
+        width: 100%;
+    }
+    .homeHeaderText {
+         width: 100%;
+         max-width: 100%;
+    }
+    .homeHeader {
+         width: 100%;
+    }
+    .introTile {
+         height: 100%;
+         margin: 10px;
+    }
+    .boxBody {
+        font-size: 12px;
+    }
+}
+
+@media screen and (max-width: $mobile-resolution-max) {
+    .introWrapper {
+        margin-top: $margin-top-mobile;
+        padding: 5px;
+    }
+
+    .homeBanner {
+       display: none;
+    }
+
+    .homeHeader {
+            width: 100%;
+            max-width: 100%;
+    }
+
+     .blockHome {
+         border: 0;
+     }
+
+     .documentWrapper {
+          documentView {
+                 padding-left: 5px;
+             }
+     }
+
+    .containerWrapper {
+        padding: 10px 10px 10px 12px;
+    }
+
+    .documentBody {
+        width: 100%;
+        padding-left: 0;
+    }
+
+    .homeHeaderText {
+        width: 100%;
+        max-width: 100%;
+        border-top: 0.5px solid var(--border-color);
+    }
+
+    .blockHome {
+             border: 0;
+    }
+
+   .introCard {
+        width: 100%;
+    }
+
+    .boxDiv {
+        width: 100%;
+    }
+
+    .boxHalfWidth {
+        width: 100%;
+    }
+
+    .introTile {
+        height: 100%;
+        margin: 5px;
+    }
+    .tableContainer {
+	overflow: scroll;
+}
+}
+
+@media screen and (max-width: $mobile-resolution-max) {
+    main.withHeaderFooter {
+        flex-direction: column;
+    }
+}
+
+.searchResultHighlightColor {
+    color: var(--secondary-color);
+}
diff --git a/docs/src/assets/styles/margin.scss b/docs/src/assets/styles/margin.scss
new file mode 100644
index 000000000..272f47289
--- /dev/null
+++ b/docs/src/assets/styles/margin.scss
@@ -0,0 +1,103 @@
+/* Margin classes start */
+
+.m-1 {
+    margin: 0.25rem;
+}
+
+.m-2 {
+    margin: 0.5rem;
+}
+
+.m-3 {
+    margin: 1rem;
+}
+
+.m-4 {
+    margin: 1.5rem;
+}
+
+.m-5 {
+    margin: 3rem;
+}
+
+.mt-1 {
+    margin-top: 0.25rem;
+}
+
+.mt-2 {
+    margin-top: 0.5rem;
+}
+
+.mt-3 {
+    margin-top: 1rem;
+}
+
+.mt-4 {
+    margin-top: 1.5rem;
+}
+
+.mt-5 {
+    margin-top: 3rem;
+}
+
+.mb-1 {
+    margin-bottom: 0.25rem;
+}
+
+.mb-2 {
+    margin-bottom: 0.5rem;
+}
+
+.mb-3 {
+    margin-bottom: 1rem;
+}
+
+.mb-4 {
+    margin-bottom: 1.5rem;
+}
+
+.mb-5 {
+    margin-bottom: 3rem;
+}
+
+.ml-1 {
+    margin-left: 0.25rem;
+}
+
+.ml-2 {
+    margin-left: 0.5rem;
+}
+
+.ml-3 {
+    margin-left: 1rem;
+}
+
+.ml-4 {
+    margin-left: 2.5rem;
+}
+
+.ml-5 {
+    margin-left: 3rem;
+}
+
+.mr-1 {
+    margin-right: 0.25rem;
+}
+
+.mr-2 {
+    margin-right: 0.5rem;
+}
+
+.mr-3 {
+    margin-right: 1rem;
+}
+
+.mr-4 {
+    margin-right: 1.5rem;
+}
+
+.mr-5 {
+    margin-right: 3rem;
+}
+
+/* Margin classes end */
diff --git a/docs/src/assets/styles/padding.scss b/docs/src/assets/styles/padding.scss
new file mode 100644
index 000000000..2c95eff38
--- /dev/null
+++ b/docs/src/assets/styles/padding.scss
@@ -0,0 +1,103 @@
+/* Padding classes start */
+
+.pd-1 {
+    padding: 0.25rem;
+}
+
+.pd-2 {
+    padding: 0.5rem;
+}
+
+.pd-3 {
+    padding: 1rem;
+}
+
+.pd-4 {
+    padding: 1.5rem;
+}
+
+.pd-5 {
+    padding: 3rem;
+}
+
+.pt-1 {
+    padding-top: 0.25rem;
+}
+
+.pt-2 {
+    padding-top: 0.5rem;
+}
+
+.pt-3 {
+    padding-top: 1rem;
+}
+
+.pt-4 {
+    padding-top: 1.5rem;
+}
+
+.pt-5 {
+    padding-top: 3rem;
+}
+
+.pb-1 {
+    padding-bottom: 0.25rem;
+}
+
+.pb-2 {
+    padding-bottom: 0.5rem;
+}
+
+.pb-3 {
+    padding-bottom: 1rem;
+}
+
+.pb-4 {
+    padding-bottom: 1.5rem;
+}
+
+.pb-5 {
+    padding-bottom: 3rem;
+}
+
+.pl-1 {
+    padding-left: 0.25rem;
+}
+
+.pl-2 {
+    padding-left: 0.5rem;
+}
+
+.pl-3 {
+    padding-left: 1rem;
+}
+
+.pl-4 {
+    padding-left: 1.5rem;
+}
+
+.pl-5 {
+    padding-left: 3rem;
+}
+
+.pr-1 {
+    padding-right: 0.25rem;
+}
+
+.pr-2 {
+    padding-right: 0.5rem;
+}
+
+.pr-3 {
+    padding-right: 1rem;
+}
+
+.pr-4 {
+    padding-right: 1.5rem;
+}
+
+.pr-5 {
+    padding-right: 3rem;
+}
+
+/* Padding classes end */
diff --git a/docs/src/assets/styles/variables.scss b/docs/src/assets/styles/variables.scss
new file mode 100644
index 000000000..65b9f1bef
--- /dev/null
+++ b/docs/src/assets/styles/variables.scss
@@ -0,0 +1,225 @@
+$gutter: 0;
+/*Colors*/
+$gray-80: #323946;
+$white: #fff;
+$darkblue: #2770ef;
+$secondarycolor: #2770ef;
+$lightgrey: #eaedf2;
+$darkgrey: #777e8b;
+$hovercolor: rgba(113, 161, 244, 0.12);
+$text-container-background: rgba(192, 198, 207, 0.12);
+$disabledcolor: #a5acb9;
+$result-container-max-height: 320px;
+$result-height: 64px;
+$highlight-grey: #6e7781;
+$highlight-darkgrey: #333;
+$highlight-green: #188038;
+$highlight-red: #d14;
+$highlight-darkred: #900;
+$highlight-blue: #0550ae;
+$highlight-lightgreen: #009926;
+$highlight-lightgrey: #999;
+$highlight-peach: #fdd;
+$highlight-fadedgreen: #dfd;
+$highlight-yellow:#e18114;
+
+$header-zIndex: 99;
+$header-logo-width: 273px;
+$header-link-margin: 45px;
+$font-weight-normal: 300;
+$font-weight-bold: 500;
+$line-height-normal: 31px;
+$line-height-button: 16px;
+$line-height-doc: 1.6rem;
+$line-height-result-title: 20px;
+$line-height-result-footer: 18px;
+$font-size-small: 12px;
+$font-size-home: 13px;
+$font-size-normal: 14px;
+$font-size-table: 14px;
+$font-size-doc: 14.5px;
+$font-size-code: 13.5px;
+$line-height-code: 1.4rem; 
+$font-size-large: 18px;
+$font-size-404: 1.25rem;
+$padding-md: 24px;
+$margin-lg: 35px;
+$margin-md: 24px;
+$margin-sm: 16px;
+$margin-xs: 5px;
+$padding-xs: 5px;
+$padding-sm: 10px;
+$padding-lg: 28px;
+$document-margin-top: 88px;
+$document-padding: 20px;
+$padding-nested-ul: 12px;
+$margin-links: 16px;
+$docmap-width-desktop: 250px;
+$docmap-width-tablet: 180px;
+$docmap-width-mobile: 100%;
+$tablet-resolution-min: 767px;
+$tablet-resolution-max: 1024px;
+$mobile-resolution-max: 600px;
+$box-shadow-search-box: 0px 0px 4px rgba(25, 35, 49, 0.08),
+    0px 12px 24px rgba(25, 35, 49, 0.12);
+$height-search-icon: 16px;
+$width-search-icon: 16px;
+$height-search-input: 32px;
+$margin-search-result: 16px;
+$padding-left-search-input: 36px;
+$font-family-code: Roboto,Consolas,Monaco,monospace;
+$font-family-doc: Optimo-Plain;
+$font-family-back-button: Optimo-Plain;
+$width-back-button: 32px;
+$height-back-button: 32px;
+$font-color-back-button: #777e8b;
+$margin-top-mobile: 58px;
+$menu-icon-width: 43px;
+$z-index-search: 1;
+$z-index-left-nav: 9;
+$arrow-icon-width: 12px;
+$title-margin: 10px;
+$sub-title-margin: 30px;
+$sub-title-margin-h5: 10px;
+$font-size-h1: 30px;
+$font-size-h2: 26px;
+$font-size-h3: 23px;
+$font-size-h4: 20px;
+$font-size-h5: 18px;
+$font-size-summ-title: 17px;
+$font-size-breadcrums: 13px;
+$font-size-breadcrums-mobile: 10px;
+$icon-width: 14px;
+$icon-height: 14px;
+$arrow-icon-width: 20px;
+$arrow-icon-height: 20px;
+
+/* Preview link variables */
+
+$preview-padding: 8px 16px;
+$preview-border-radius: 16px;
+$preview-margin-bottom: 8px;
+$preview-height: 32px;
+
+/* Toggle button variables */
+
+$switch-width: 80px;
+$switch-height: 34px;
+$slider-width: 26px;
+$slider-height: 26px;
+$slider-background: #ccc;
+
+/* Admonition variables */
+
+$caution-color: #a0439c;
+$important-color: #d32f2f;
+$note-color: #217ee7;
+$tip-color: #41af46;
+$warning-color: #e18114;
+$color-white: #fff;
+$color-smoke-30: #fafafa;
+$warning-on-color: $color-white;
+$caution-on-color: $color-white;
+$important-on-color: $color-white;
+$note-on-color: $color-white;
+$tip-on-color: $color-white;
+$panel-background: $color-smoke-30;
+/* fonts */
+$rem-base: 18;
+$body-font-size-desktop: 1.125em; /* 18px */
+$body-font-size-print: 0.9375em; /* 15px */
+$body-line-height: 1.15;
+$body-font-family: 'Roboto', sans-serif;
+$body-font-weight-bold: 500;
+$monospace-font-family: 'Roboto Mono', monospace;
+$monospace-font-weight-bold: 500;
+$admonition-label-font-weight: $body-font-weight-bold;
+$admonition-title-font-size: 12px;
+$admonition-title-line-height: 20px;
+$admonition-font-factor-p: 16;
+$admonition-content-line-height: 24px;
+$admonition-font-factor-pre: 15;
+
+
+/*Tag variables*/
+$beta-border-radius: 6px;
+$beta-padding: 0 5px;
+$tag-border-radius: 20px;
+$tag-font-size: 13px;
+$tag-font-weight: 400;
+$tag-height: 28px;
+$tag-line-height: 28px;
+$tag-margin-right: 5px;
+$tag-padding: 0 10px;
+$tag-width: auto;
+$tag-font-color: #fff;
+$tag-color-yellow: #ffbc00;
+$tag-color-white: var(--body-background-color);
+$tag-color-light: $lightgrey;
+
+:root {
+    --body-background-color: #fff;
+    --primary-color: #1d232f;
+    --sidebar-text-color: #323946;
+    --header-color: #000000;
+    --header-border-color: #000000;
+    --breadcrums-font-color: #5f6368;
+    --announcement-block-color: #f1f1f1;
+    --admonition-background: #fff;
+    --code-block-color: #f6f8fa;
+    --text-color-code-lang: #999;
+    --icon-color: #999;
+    --back-button-background: #eaedf2;
+    --block-background: #eaedf2;
+    --border-color: #c0c6cf;
+    --table-header-color: #fff;
+    --border-color-tr: #e6e6e6; 
+    --scrollbar-color: #a5acb9;
+    --color-jet-70: #d14;
+    --highlight-purple: #9334e6;
+    --highlight-green: #188038;
+    --highlight-lightgreen:#009926; 
+    --highlight-lightblue: #0086b3;
+    --highlight-darkblue: #000080;
+    --highlight-blue: #458;
+    --highlight-darkred: #900;
+    --highlight-violet: #990073;
+    --secondary-color: #2770ef;
+    --box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 12%), 0 0px 4px 0 rgba(0, 0, 0, 11%);
+    --box-shadow-hover: 0 16px 20px 0 rgba(0, 0, 0, 12%),
+        0 16px 20px 0 rgba(0, 0, 0, 12%);
+}
+
+#wrapper[data-theme='dark'] {
+    --body-background-color: #21252c;
+    --header-color: #323946;
+    --header-border-color: #777E8B;
+    --primary-color: #E8EAED;
+    --sidebar-text-color: #E8EAED;
+    --breadcrums-font-color: #a5acb9;
+    --announcement-block-color: #3c4356;
+    --admonition-background: #3c4356;
+    --code-block-color: #3c4356;
+    --text-color-code-lang: #fff;
+    --icon-color: #fff;
+    --table-header-color: #3c4356;
+    --back-button-background: #a4abb8;
+    --block-background: none;
+    --border-color: #3c4356;
+    --border-color-tr:#3c4356;
+    --scrollbar-color: #3c4356;
+    --color-jet-70: #e18114;
+    --highlight-purple: #40c4ff;
+    --highlight-green: aquamarine;
+    --highlight-lightgreen:#009926; 
+    --highlight-lightblue: #90caf9;
+    --highlight-darkblue: #9fa8da;
+    --highlight-blue: #c5cae9;
+    --highlight-darkred: #ef9a9a;
+    --highlight-violet: #f8bbd0;
+    --secondary-color: #8388fe;
+    --box-shadow: 0 2px 2px 0 rgba(255, 255, 255, 12%),
+        0 0px 6px 0 rgba(255, 255, 255, 11%);
+    --box-shadow-hover: 0 16px 20px 0 rgb(255 255 255 / 6%),
+        0 16px 20px 0 rgb(255 255 255 / 6%);
+}
diff --git a/docs/src/assets/svg/ts-logo-white-developer.svg b/docs/src/assets/svg/ts-logo-white-developer.svg
new file mode 100644
index 000000000..d769f1125
--- /dev/null
+++ b/docs/src/assets/svg/ts-logo-white-developer.svg
@@ -0,0 +1,8 @@
+
+  
+    
+      
+    
+  
+  
+
diff --git a/docs/src/assets/svg/ts-logo-white.svg b/docs/src/assets/svg/ts-logo-white.svg
new file mode 100644
index 000000000..345ab2678
--- /dev/null
+++ b/docs/src/assets/svg/ts-logo-white.svg
@@ -0,0 +1 @@
+
diff --git a/docs/src/components/BackButton/__snapshots__/index.test.tsx.snap b/docs/src/components/BackButton/__snapshots__/index.test.tsx.snap
new file mode 100644
index 000000000..25dcb31c6
--- /dev/null
+++ b/docs/src/components/BackButton/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,45 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`BackButton it should renders correctly 1`] = `
+
+ +

+ Test Title +

+
+`; diff --git a/docs/src/components/BackButton/index.scss b/docs/src/components/BackButton/index.scss new file mode 100644 index 000000000..ad4761a07 --- /dev/null +++ b/docs/src/components/BackButton/index.scss @@ -0,0 +1,32 @@ +@import '../../assets/styles/variables.scss'; + +.backButtonWrapper { + display: flex; + padding-left: 24px; + align-items: center; + + button { + width: $width-back-button; + height: $height-back-button; + display: block; + border-radius: 50%; + border: none; + outline: none; + margin-right: 10px; + background: var(--back-button-background); + } + + .leftIcon { + height: $arrow-icon-width; + width: $arrow-icon-height; + position: relative; + top: 2px; + } + + p { + color: $font-color-back-button; + font-size: $font-size-normal; + font-weight: $font-weight-normal; + font-family: $font-family-back-button; + } +} diff --git a/docs/src/components/BackButton/index.test.tsx b/docs/src/components/BackButton/index.test.tsx new file mode 100644 index 000000000..892eba565 --- /dev/null +++ b/docs/src/components/BackButton/index.test.tsx @@ -0,0 +1,25 @@ +import React from "react" +import renderer from "react-test-renderer" +import { render } from "@testing-library/react" + +import BackButton from "./index" + +describe("BackButton", () => { + const testTitle = 'Test Title'; + const testBackLink = `test backlink`; + + it("it should renders correctly", () => { + const tree = renderer + .create() + .toJSON() + expect(tree).toMatchSnapshot() + }) + + it(`renders title correctly`, () => { + const { getByTestId } = render() + + const title = getByTestId("backBtn") + + expect(title).toBeInTheDocument() + }) +}) \ No newline at end of file diff --git a/docs/src/components/BackButton/index.tsx b/docs/src/components/BackButton/index.tsx new file mode 100644 index 000000000..bc36b5fda --- /dev/null +++ b/docs/src/components/BackButton/index.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { IconContext } from '@react-icons/all-files'; +import { BsArrowLeft } from '@react-icons/all-files/bs/BsArrowLeft'; +import './index.scss'; + +const BackButton = (props: { title: string; backLink: string }) => ( +
+ +

{props.title}

+
+); + +export default BackButton; diff --git a/docs/src/components/Breadcrums/__snapshots__/index.test.tsx.snap b/docs/src/components/Breadcrums/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..740b9c066 --- /dev/null +++ b/docs/src/components/Breadcrums/__snapshots__/index.test.tsx.snap @@ -0,0 +1,32 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Breadcrums should render correctly and show breadcrumbs 1`] = ` +
+
+ +
+
+`; diff --git a/docs/src/components/Breadcrums/index.scss b/docs/src/components/Breadcrums/index.scss new file mode 100644 index 000000000..bbf1955db --- /dev/null +++ b/docs/src/components/Breadcrums/index.scss @@ -0,0 +1,48 @@ +@import '../../assets/styles/variables.scss'; + +.breadcrumsWrapper { + padding: $padding-sm $padding-md 0px; + .breadcrumb { + margin: 0; + list-style: none; + list-style-type: none; + padding-inline-start: 0px; + padding-inline-end: 0px; + li { + display: inline; + margin: 0; + font-weight: 300; + color: var(--breadcrums-font-color); + font-size: $font-size-breadcrums; + } + + li + li:before { + padding: 0px 5px; + content: '\003E'; + } + + li a { + text-decoration: none; + color: var(--breadcrums-font-color); + font-size: $font-size-breadcrums; + &:hover { + color: var(--secondary-color); + } + } + + } + +} + +@media screen and (max-width: $mobile-resolution-max) { + .breadcrumsWrapper{ + padding: 10px 5px 5px 20px; + font-size: $font-size-breadcrums-mobile; + line-height: 14pt; + } +} + + + + + diff --git a/docs/src/components/Breadcrums/index.test.tsx b/docs/src/components/Breadcrums/index.test.tsx new file mode 100644 index 000000000..d459996c1 --- /dev/null +++ b/docs/src/components/Breadcrums/index.test.tsx @@ -0,0 +1,298 @@ +import React from 'react'; +import { render } from "@testing-library/react"; + +import Breadcrums from "./index"; +import { getBreadcrumsPath } from '../../utils/doc-utils'; + +jest.mock('../../utils/doc-utils', () => ({ + getBreadcrumsPath: jest.fn().mockReturnValue([ + { + "name": "ThoughtSpot Everywhere", + "href": "?pageid=embed-analytics" + }, + { + "name": "ThoughtSpot Developer portal", + "href": null + } + ]), +})) + +describe('Breadcrums', () => { + const pageId = 'spotdev-portal'; + const breadcrumsData = [ + { + "name": "Home", + "href": "?pageid=introduction" + }, + { + "name": "What’s new", + "href": "?pageid=whats-new" + }, + { + "name": "ThoughtSpot Everywhere", + "href": "?pageid=embed-analytics", + "children": [ + { + "name": "Integration guidelines", + "href": "?pageid=integration-guidelines" + }, + { + "name": "ThoughtSpot Developer portal", + "href": "?pageid=spotdev-portal" + }, + { + "name": "Developer Playground", + "href": "?pageid=dev-playground" + } + ] + }, + { + "name": "Authentication and security", + "href": "?pageid=auth-overview", + "children": [ + { + "name": "Developer access", + "href": "?pageid=developer-access" + }, + { + "name": "Security settings", + "href": "?pageid=security-settings" + }, + { + "name": "SAML SSO authentication", + "href": "?pageid=saml-sso" + }, + { + "name": "Trusted authentication", + "href": "?pageid=trusted-auth" + }, + { + "name": "Custom domain configuration", + "href": "?pageid=custom-domain-config" + }, + { + "name": "Browser settings for embedding", + "href": "?pageid=browser-settings" + }, + { + "name": "Access control and data security", + "href": "?pageid=embed-object-access" + } + ] + }, + { + "name": "Visual Embed SDK", + "href": "?pageid=visual-embed-sdk", + "children": [ + { + "name": "Get started", + "href": "?pageid=getting-started" + }, + { + "name": "Embed user authentication", + "href": "?pageid=embed-auth" + }, + { + "name": "Embed search", + "href": "?pageid=search-embed" + }, + { + "name": "Embed a pinboard", + "href": "?pageid=embed-pinboard" + }, + { + "name": "Embed a visualization", + "href": "?pageid=embed-a-viz" + }, + { + "name": "Embed full application", + "href": "?pageid=full-embed" + }, + { + "name": "Disable or hide menu actions", + "href": "?pageid=action-config" + }, + { + "name": "Visual Embed SDK Reference", + "href": "?pageid=js-reference" + } + ] + }, + { + "name": "Custom actions", + "href": "?pageid=custom-action-intro", + "children": [ + { + "name": "Custom actions page", + "href": "?pageid=customize-actions" + }, + { + "name": "Configure a URL action", + "href": "?pageid=custom-action-url" + }, + { + "name": "Configure a callback action", + "href": "?pageid=custom-action-callback" + }, + { + "name": "Add a custom action to a visualization", + "href": "?pageid=add-action-viz" + }, + { + "name": "Add custom actions to a worksheet", + "href": "?pageid=add-action-worksheet" + }, + { + "name": "Callback custom action example", + "href": "?pageid=push-data" + }, + { + "name": "Custom action response payload", + "href": "?pageid=custom-action-payload" + } + ] + }, + { + "name": "Customization and rebranding", + "href": "?pageid=customization-intro", + "children": [ + { + "name": "Customize layout and styles", + "href": "?pageid=customize-style" + }, + { + "name": "Customize links", + "href": "?pageid=customize-links" + }, + { + "name": "Customize onboarding settings", + "href": "?pageid=customize-emails" + } + ] + }, + { + "name": "Runtime filters", + "href": "?pageid=runtime-filters" + }, + { + "name": "REST API fundamentals", + "href": "?pageid=rest-apis", + "children": [ + { + "name": "Get started", + "href": "?pageid=rest-api-getstarted" + }, + { + "name": "Authentication", + "href": "?pageid=api-auth-session" + }, + { + "name": "Manage users and user groups", + "href": "?pageid=api-user-management" + }, + { + "name": "Embed data using REST APIs", + "href": "?pageid=embed-data-restapi" + }, + { + "name": "Paginate API response", + "href": "?pageid=rest-api-pagination" + } + ] + }, + { + "name": "REST API Reference", + "href": "?pageid=rest-api-reference", + "children": [ + { + "name": "User APIs", + "href": "?pageid=user-api" + }, + { + "name": "Group APIs", + "href": "?pageid=group-api" + }, + { + "name": "Session APIs", + "href": "?pageid=session-api" + }, + { + "name": "Data connection APIs", + "href": "?pageid=connection-api" + }, + { + "name": "Metadata APIs", + "href": "?pageid=metadata-api" + }, + { + "name": "Admin APIs", + "href": "?pageid=admin-api" + }, + { + "name": "TML APIs", + "href": "?pageid=tml-api" + }, + { + "name": "Dependent objects APIs", + "href": "?pageid=dependent-objects-api" + }, + { + "name": "Search data API", + "href": "?pageid=search-data-api" + }, + { + "name": "Pinboard data API", + "href": "?pageid=pinboard-api" + }, + { + "name": "Pinboard Export API", + "href": "?pageid=pinboard-export-api" + }, + { + "name": "Security APIs", + "href": "?pageid=security-api" + }, + { + "name": "Log streaming service API", + "href": "?pageid=logs-api" + } + ] + }, + { + "name": "Code samples", + "href": "?pageid=code-samples" + }, + { + "name": "Resources", + "children": [ + { + "name": "Playground", + "href": "https://try-everywhere.thoughtspot.cloud/v2/#/everywhere/playground/search" + }, + { + "name": "REST API Explorer (Requires login)", + "href": "https://try-everywhere.thoughtspot.cloud/external/swagger" + }, + { + "name": "ThoughtSpot Developers", + "href": "https://developers.thoughtspot.com" + }, + { + "name": "Community", + "href": "https://community.thoughtspot.com/customers/s/" + }, + { + "name": "Product Documentation", + "href": "https://cloud-docs.thoughtspot.com" + } + ] + } + ] + it('should render correctly and show breadcrumbs', async () => { + const { container, queryByTestId } = await render(); + expect(container).toMatchSnapshot(); + expect(queryByTestId('breadcrumbWrapper')).toBeInTheDocument(); + expect(getBreadcrumsPath).toHaveBeenCalledTimes(1); + }); + +}) \ No newline at end of file diff --git a/docs/src/components/Breadcrums/index.tsx b/docs/src/components/Breadcrums/index.tsx new file mode 100644 index 000000000..b83254cc6 --- /dev/null +++ b/docs/src/components/Breadcrums/index.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { HOME_PAGE_ID } from '../../configs/doc-configs'; +import { getBreadcrumsPath } from '../../utils/doc-utils'; +import './index.scss'; + +type BreadcrumsProps = { + pageid?: string; + breadcrumsData: any; +}; + +const Breadcrums: React.FC = (props: BreadcrumsProps) => { + const breadcrums = getBreadcrumsPath(props.breadcrumsData, props.pageid); + return ( + <> + {breadcrums.length ? ( +
+ +
+ ) : null} + + ); +}; + +export default Breadcrums; diff --git a/docs/src/components/Button/__snapshots__/index.test.tsx.snap b/docs/src/components/Button/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..3bc8bf1ea --- /dev/null +++ b/docs/src/components/Button/__snapshots__/index.test.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`button should renders correctly 1`] = ` + +`; diff --git a/docs/src/components/Button/index.scss b/docs/src/components/Button/index.scss new file mode 100644 index 000000000..42d691c4d --- /dev/null +++ b/docs/src/components/Button/index.scss @@ -0,0 +1,23 @@ +@import '../../assets/styles/variables.scss'; + +.button { + font-size: $font-size-small; + line-height: $line-height-button; + letter-spacing: 0.6px; + padding: 5px 16px; + min-width: 75px; + display: inline-block; + text-align: center; + border: 0; + &.primary { + color: $white; + background: $darkblue; + border-radius: 14px; + outline: none; + } + &.secondary { + color: $white; + background: $gray-80; + outline: none; + } +} diff --git a/docs/src/components/Button/index.test.tsx b/docs/src/components/Button/index.test.tsx new file mode 100644 index 000000000..e9098d430 --- /dev/null +++ b/docs/src/components/Button/index.test.tsx @@ -0,0 +1,25 @@ +import React from "react" +import renderer from "react-test-renderer" +import { render } from "@testing-library/react" + +import Button from "./index" + +describe("button", () => { + const testLabel = 'Test label'; + const testType = `Button`; + + it("should renders correctly", () => { + const tree = renderer + .create( +); + +export default Button; diff --git a/docs/src/components/Docmap/__snapshots__/index.test.tsx.snap b/docs/src/components/Docmap/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..3a2a16ca1 --- /dev/null +++ b/docs/src/components/Docmap/__snapshots__/index.test.tsx.snap @@ -0,0 +1,63 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Docmap should render correctly 1`] = ` +
+ +
+`; diff --git a/docs/src/components/Docmap/index.scss b/docs/src/components/Docmap/index.scss new file mode 100644 index 000000000..de268131e --- /dev/null +++ b/docs/src/components/Docmap/index.scss @@ -0,0 +1,70 @@ +@import '../../assets/styles/variables.scss'; + +.docmapLinks { + width: 16%; + padding: 10px $padding-md $padding-md $padding-md; + border-left: 1px var(--border-color) solid; + position: fixed; + right: 0; + font-size: 14px; + height: 100vh; + overflow-y: auto; + + .tocTitle { + margin: 0; + color: $disabledcolor; + line-height: $line-height-normal; + padding-left: $padding-sm; + } + + div { + ul { + margin-top: 0px; + list-style-type: none; + padding-left: $padding-sm; + background-color: var(--border-color) solid; + li { + margin: $margin-links 0; + + a { + color: var(--primary-color); + font-weight: $font-weight-normal; + } + + a:hover { + color: var(--secondary-color); + } + + ul { + padding-left: $padding-nested-ul; + } + } + } + } + + #toctitle { + display: none; + } +} + +.defaultStyle { + color: var(--primary-color); + padding: 8px 0; + display: inline-block; +} + +.activeTag { + color: var(--secondary-color) !important; +} + +@media screen and (min-width: $tablet-resolution-min) and (max-width: $tablet-resolution-max) { + .docmapLinks { + display: none; + } +} + +@media screen and (max-width: $mobile-resolution-max) { + .docmapLinks { + display: none; + } +} diff --git a/docs/src/components/Docmap/index.test.tsx b/docs/src/components/Docmap/index.test.tsx new file mode 100644 index 000000000..ece841e84 --- /dev/null +++ b/docs/src/components/Docmap/index.test.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import Docmap from './index'; + +const dummyLocation = { + "pathname": "/en/", + "search": "?pageid=visual-embed-sdk", + "hash": "", + "href": "http://localhost:8000/en/?pageid=visual-embed-sdk", + "origin": "http://localhost:8000", + "protocol": "http:", + "host": "localhost:8000", + "hostname": "localhost", + "port": "8000", + "state": { + "key": "1629178873455" + }, + "key": "1629178873455" +}; +const docContentHTML = "

Visual Embed SDK

\n\n
\n
\n
\n

The Visual Embed SDK provides a Javascript library to embed ThoughtSpot elements in your host application.

\n
\n
\n

You can use the Visual Embed SDK for the following purposes:

\n
\n
\n
    \n
  • \n

    Embed specific components of the ThoughtSpot application; for example, search, pinboards, and visualizations.

    \n
  • \n
  • \n

    Render full ThoughtSpot application within a host application.

    \n
  • \n
\n
\n
\n
\n
\n

Configuration requirements

\n
\n
\n
\n
\n

Integration guidelines

\n
\n
\n

Read the integration guidelines to understand the embedding requirements and recommendations.

\n
\n
\n
\n
\n
\n
\n

Security settings

\n
\n
\n

Before you get started, add your application domain to the CORS and CSP allowed list and set your application as a trusted host for secure data exchange.

\n
\n
\n
\n
\n
\n
\n

Start embedding

\n
\n
\n
\n
\n

Get Started

\n
\n
\n

Download the Visual Embed SDK package, set up your application environment, and get started with embedding.

\n
\n
\n
\n
\n
\n
\n

Configure authentication method

\n
\n
\n

Learn how to set up SAML SSO or trusted authentication service, and configure authentication methods in SDK to authenticate your application users.

\n
\n
\n
\n
\n
\n
\n

Embed search

\n
\n
\n

Learn how to embed ThoughtSpot search in your application.

\n
\n
\n
\n
\n
\n
\n

Embed a visualization

\n
\n
\n

Learn how to embed a ThoughtSpot visualization in your application.

\n
\n
\n
\n
\n
\n
\n

Embed a pinboard

\n
\n
\n

Learn how to render pinboards and apply runtime controls on visualizations embedded in your application.

\n
\n
\n
\n
\n
\n
\n

Embed full ThoughtSpot experience

\n
\n
\n

Learn how to embed full ThoughtSpot experience in your application.

\n
\n
\n
\n
\n
\n
\n

Useful resources

\n\n
"; +const docContentHTMLBlank = ""; + +jest.mock('../../utils/lang-utils', () => (key) => key); + +describe('Docmap', () => { + const docContent = docContentHTML; + const options = [{}]; + const location = dummyLocation; + it('should render correctly', () => { + const { container, getByTestId } = render(); + expect(container).toMatchSnapshot(); + expect(getByTestId('toc')).toBeInTheDocument(); + }) + + it('should not render toc if docContent is empty', () => { + const { queryByTestId } = render(); + expect(queryByTestId('toc')).toBeNull(); + }) +}) \ No newline at end of file diff --git a/docs/src/components/Docmap/index.tsx b/docs/src/components/Docmap/index.tsx new file mode 100644 index 000000000..0a4150dde --- /dev/null +++ b/docs/src/components/Docmap/index.tsx @@ -0,0 +1,59 @@ +import React, { useEffect, useState } from 'react'; +import { INTRO_WRAPPER_MARGIN_TOP } from '../../constants/uiConstants'; +import t from '../../utils/lang-utils'; +import './index.scss'; + +const Docmap = (props: { + docContent: string; + options: Object[]; + location: Location; +}) => { + const [toc, setToc] = useState(''); + useEffect(() => { + // GraphQL doesn't provide any seperate html for Table of Content. It is included in the document itself. + // To extract the TOC from document, we first create a temporary element to set the document as it's innerHTML. + // Them we search for TOC using querySelector on the temporary element and then set the obtained TOC to display in the UI. + const doc = document.createElement('div'); + doc.innerHTML = props.docContent; + const tocEl = doc.querySelector('#toc'); + if (tocEl) { + const { hash } = props.location; + if (hash) { + const ele = document.querySelector(hash); + if (ele) { + document.documentElement.scrollTop = + (ele as HTMLElement).offsetTop - + INTRO_WRAPPER_MARGIN_TOP; + } + } + setToc(tocEl.innerHTML); + } else { + setToc(''); + } + }, [props.docContent, props.location.hash]); + + // Currently not using + // const toggleActiveClass = (toc: Element, href: string) => { + // toc.querySelectorAll('a').forEach((tag, index) => { + // const temp = tag; + // if (tag.getAttribute('href') === href) { + // temp.classList.add('activeTag'); + // } else if (tag.classList.contains('activeTag')) { + // temp.classList.remove('activeTag'); + // } + // toc.querySelectorAll('a')[index].innerHTML = temp.innerHTML; + // }); + // return toc; + // }; + + return ( + toc !== '' && ( +
+

{t('RIGHT_NAV_SIDERBAR_TITLE')}

+
+
+ ) + ); +}; + +export default Docmap; diff --git a/docs/src/components/Document/__snapshots__/index.test.tsx.snap b/docs/src/components/Document/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..33bdec068 --- /dev/null +++ b/docs/src/components/Document/__snapshots__/index.test.tsx.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Document should render correctly if isPublicSiteOpen is false 1`] = ` +
+
+
+ test content +
+
+
+`; + +exports[`Document should render correctly if isPublicSiteOpen is true 1`] = ` +
+
+
+ test content +
+
+
+
+`; diff --git a/docs/src/components/Document/helper.tsx b/docs/src/components/Document/helper.tsx new file mode 100644 index 000000000..3de600e10 --- /dev/null +++ b/docs/src/components/Document/helper.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import hljs from 'highlight.js'; +import t from '../../utils/lang-utils'; +import { RiFileCopyFill } from '@react-icons/all-files/ri/RiFileCopyFill'; +import { getHTMLFromComponent } from '../LeftSidebar/helper'; +import selectors from '../../constants/selectorsContant'; + +export const enableCopyToClipboard = ( + element: HTMLElement, + ...args: HTMLElement[] +) => { + element.addEventListener('click', () => { + const textareaElement = document.createElement('textarea'); + textareaElement.value = (args[0] as HTMLElement).innerText; + element.parentElement.appendChild(textareaElement); + textareaElement.select(); + document.execCommand('copy'); + element.parentElement.removeChild(textareaElement); + const divElement = document.createElement('div'); + divElement.classList.add('tooltip'); + const spanElement = document.createElement('span'); + spanElement.classList.add('tooltiptext'); + spanElement.innerText = t('CODE_COPY_BTN_AFTER_CLICK_TEXT'); + divElement.appendChild(spanElement); + element.parentElement.appendChild(divElement); + /* To remove copy tooltip */ + setTimeout(() => { + element.parentElement.removeChild(divElement); + }, 500); + }); +}; + +export const customizeDocContent = () => { + /* To get all the code blocks from document */ + document.querySelectorAll(selectors.codeBlocks).forEach((tag) => { + const buttonElement = document.createElement('button'); + buttonElement.setAttribute('class', 'copyButton'); + enableCopyToClipboard(buttonElement, tag as HTMLElement); + const imageElement = document.createElement('span'); + imageElement.innerHTML = getHTMLFromComponent( + , + 'copyIcon', + ); + buttonElement.appendChild(imageElement); + const spanElement = document.createElement('span'); + spanElement.innerText = tag.getAttribute('data-lang'); + spanElement.classList.add('lang'); + const wrapperDiv = document.createElement('div'); + wrapperDiv.classList.add('wrapperContainer'); + wrapperDiv.appendChild(spanElement); + wrapperDiv.appendChild(buttonElement); + tag.parentElement.appendChild(wrapperDiv); + }); + /* To highlight code snippets */ + document.querySelectorAll('pre code').forEach((block) => { + hljs.highlightBlock(block as HTMLElement); + }); +}; + +// Checks if the HTML element is in viewport. +const isInViewport = (el: HTMLElement) => { + const rect = el.getBoundingClientRect(); + return rect.top >= 0 && rect.left >= 0; +}; + +export const addScrollListener = () => { + document.addEventListener('scroll', () => { + const subLinks = document.querySelectorAll(selectors.docmapLinks); + let flag = false; + subLinks.forEach((link, i: number) => { + const href = (link as HTMLAnchorElement).href; + const hash = href.split('#')[1]; + if (hash) { + const targetElement = document.getElementById(hash) + ?.parentElement; + if (targetElement) { + const isVisible = isInViewport( + targetElement as HTMLElement, + ); + if (isVisible && !flag) { + link.classList.add('active'); + flag = !flag; + } else { + link.classList.remove('active'); + } + } + } + }); + }); +}; diff --git a/docs/src/components/Document/index.scss b/docs/src/components/Document/index.scss new file mode 100644 index 000000000..7ff70ee82 --- /dev/null +++ b/docs/src/components/Document/index.scss @@ -0,0 +1,310 @@ +@import '../../assets/styles/variables.scss'; +@import '../../assets/styles/highlight.scss'; +@import '../../assets/styles/admonition.scss'; +@import '../../assets/styles/grid.scss'; + + +.documentWrapper { + width: calc(100% - #{$docmap-width-desktop}); + color: var(--primary-color); + padding-left: $document-padding; + + + .documentView { + min-height: 75vh; + padding: $padding-md $padding-md 0; + } + + /* In order to hide TOC in main component */ + #toc { + display: none; + } + + h1 { + margin-top: $title-margin; + font-weight: $font-weight-normal; + font-size: $font-size-h1; + } + + p { + font-weight: $font-weight-normal; + font-size: $font-size-doc; + line-height: $line-height-doc; + + code { + background: var(--code-block-color); + font-family: $font-family-code; + a { + color: var(--primary-color); + } + } + } + + .image img { + width: auto; + } + + img { + width: 100%; + } + + pre { + white-space: pre-wrap; + background: var(--code-block-color); + width: auto; + padding: 20px; + display: flex; + font-family: $font-family-code; + justify-content: space-between; + overflow: auto; + font-size: $font-size-code; + max-height: 900px; + line-height: $line-height-code; + box-shadow: var(--box-shadow); + + } + + pre.highlight { + &:hover { + .wrapperContainer { + visibility: visible; + + } + } + + code { + max-width: 100%; + font-family: $font-family-code; + padding-top: 10px; + + } + + .wrapperContainer { + max-width: 15%; + position: relative; + visibility: hidden; + padding: 25px; + + .lang { + position: absolute; + top: -20px; + padding: 5px; + right: 36px; + color: var(--text-color-code-lang); + } + + .copyButton { + position: absolute; + top: -15px; + padding: 5px; + right: 0px; + border: 0; + background: transparent; + + img { + width: 15px; + } + } + + .tooltip { + position: absolute; + top: 15px; + right: -8px; + } + } + } + + #preview-in-playground { + background: var(--secondary-color); + color: $white; + font-size: $font-size-normal; + font-weight: $font-weight-normal; + border: 0; + padding: $preview-padding; + border: 0; + border-radius: $preview-border-radius; + margin-bottom: $preview-margin-bottom; + display: inline-block; + height: $preview-height; + } + + table { + border-spacing: 0; + border-collapse: separate; + width: 100%; + overflow: auto; + + + th { + border-bottom: 1px solid var(--border-color); + font-size: $font-size-doc; + text-align: left; + padding: 20px $padding-sm 20px $padding-sm; + background-color: var(--table-header-color); + position: sticky; + top: 0; + + + } + + td { + font-size: $font-size-table; + border-bottom: 1px solid var(--border-color-tr); + padding: 5px $padding-md $padding-sm $padding-sm; + font-weight: $font-weight-normal; + vertical-align: top; + + p { + font-size: $font-size-table; + } + } + + tr { + border-bottom: 1px solid var(--border-color-tr); + } + } + + + h2 { + margin-top: $margin-lg; + padding-bottom: $padding-sm; + border-bottom: 1px solid var(--border-color); + font-size:$font-size-h2; + font-weight: $font-weight-normal; + } + + h3 { + margin-top: $sub-title-margin; + font-size: $font-size-h3; + font-weight: $font-weight-normal; + } + + h4 { + font-size: $font-size-h4; + margin-top: $sub-title-margin; + font-weight: $font-weight-normal; + margin-bottom: $sub-title-margin-h5; + } + + h5 { + font-size: $font-size-h5; + margin-top: $sub-title-margin-h5; + margin-bottom: $sub-title-margin-h5; + font-weight: $font-weight-bold; + color: var(--primary-color); + } + + ol > li { + &::marker { + font-weight: $font-weight-normal; + + } + + & > p { + margin-left: 5px; + } + } + + ul > li { + &::marker { + font-weight: $font-weight-normal; + + } + + & > p { + margin-left: 5px; + } + } + + + .hdlist { + tr, + th, + td { + border: none; + } + + .hdlist1 { + font-weight: $font-weight-bold; + } + + td { + font-size: $font-size-doc; + + p { + font-size: $font-size-doc; + } + } + } + + .hdlist1 { + font-size: $font-size-doc; + } + + .admonitionblock { + tr, + th, + td { + border: none; + } + } + + .dlist { + dd { + margin-bottom: $margin-links; + } + } + + .ulist { + ul { + padding-inline-start: $padding-md; + + + } + } + + + .admonitionblock { + code { + font-family: $font-family-code; + } + } + + .copyIcon { + height: $icon-width; + width: $icon-height; + } + + a, + a:active { + color: var(--secondary-color); + } +} + +hr { + border-color: var(--border-color); +} + +pre { + white-space: pre-wrap; +} + + +@media screen and (min-width: $tablet-resolution-min) and (max-width: $tablet-resolution-max) { + .documentWrapper { + width: calc(100% - #{$docmap-width-tablet}); + } +} + +@media screen and (max-width: $mobile-resolution-max) { + .documentWrapper { + width: 100%; + overflow-x: auto; + padding: 5px; + margin: 5px; + + pre { + overflow-x: auto; + } + } +} diff --git a/docs/src/components/Document/index.test.tsx b/docs/src/components/Document/index.test.tsx new file mode 100644 index 000000000..8e79465e6 --- /dev/null +++ b/docs/src/components/Document/index.test.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import Document from './index'; +import { addScrollListener, customizeDocContent } from './helper'; + + +jest.mock('../../utils/lang-utils', () => (key) => key); + +jest.mock('../Footer', () => () =>
); + +jest.mock('./helper', () => ({ + customizeDocContent: jest.fn(), + addScrollListener: jest.fn(), +})); + +describe('Document', () => { +const docTitle = 'test title'; +const docContent = 'test content'; +const isPublicSiteOpen = false; + + it('should render correctly if isPublicSiteOpen is false', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }) + it('should render correctly if isPublicSiteOpen is true', () => { + const { container, getByTestId } = render(); + fireEvent.scroll(window, { target: { scrollY: 100 } }) + expect(addScrollListener).toHaveBeenCalledTimes(1); + expect(customizeDocContent).toHaveBeenCalledTimes(1); + + expect(getByTestId('footerDiv')).toBeInTheDocument(); + expect(container).toMatchSnapshot(); + }) +}) \ No newline at end of file diff --git a/docs/src/components/Document/index.tsx b/docs/src/components/Document/index.tsx new file mode 100644 index 000000000..1915e558c --- /dev/null +++ b/docs/src/components/Document/index.tsx @@ -0,0 +1,64 @@ +import React, { useEffect } from 'react'; +import './index.scss'; +import { customizeDocContent, addScrollListener } from './helper'; +import Footer from '../Footer'; +import Breadcrums from '../Breadcrums'; +import LinkableHeader from '../LinkableHeader'; +import { HOME_PAGE_ID } from '../../configs/doc-configs'; +import parse, { HTMLReactParserOptions, domToReact, attributesToProps } from 'html-react-parser'; + +const Document = (props: { + pageid?: string; + docTitle: string; + docContent: string; + isPublicSiteOpen: boolean; + shouldShowRightNav: boolean + breadcrumsData: any; +}) => { + useEffect(() => { + customizeDocContent(); + }, [props.docContent]); + + useEffect(() => { + addScrollListener(); + }, []); + + const options: HTMLReactParserOptions = { + replace: (domNode: any) => { + if (domNode.type === 'tag' && + ['h2', 'h3', 'h4'].includes(domNode.name) && + !domNode.parent?.attribs?.class?.includes('non-link') + ) { + const props = attributesToProps(domNode.attribs); + return ( + {domToReact(domNode.children, options)} + ) + } + } + }; + + return ( +
+ {props.pageid !== HOME_PAGE_ID && ( + + )} +
+ {parse(props.docContent, options)} +
+ {props.isPublicSiteOpen &&
} +
+ ); +}; + +export default Document; diff --git a/docs/src/components/Dropdown/__snapshots__/index.test.tsx.snap b/docs/src/components/Dropdown/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..940709f4f --- /dev/null +++ b/docs/src/components/Dropdown/__snapshots__/index.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Dropdown should renders correctly 1`] = `
`; diff --git a/docs/src/components/Dropdown/index.scss b/docs/src/components/Dropdown/index.scss new file mode 100644 index 000000000..91f7cc975 --- /dev/null +++ b/docs/src/components/Dropdown/index.scss @@ -0,0 +1,53 @@ +@import '../../assets/styles/variables.scss'; + +.dropdownWrapper { + .dropdown { + float: left; + overflow: hidden; + } + + .dropdown .dropbtn { + font-size: $font-size-normal; + border: none; + outline: none; + color: $white; + background-color: inherit; + margin: 0; + } + + + .dropdownContent { + display: none; + position: absolute; + background-color: var(--body-background-color); + min-width: 160px; + box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); + z-index: 1; + right: 10px; + } + + .dropdownContent div { + float: none; + cursor: pointer; + color: var(--primary-color); + padding: 12px 16px; + text-decoration: none; + display: block; + text-align: left; + } + + .dropdownContent div:hover { + color: var(--secondary-color); + } + + .dropdown:hover .dropdownContent { + display: block; + } + + .arrowDown { + height: 0.8rem; + width: 0.8rem; + vertical-align: middle; + margin-left: 5px; + } +} diff --git a/docs/src/components/Dropdown/index.test.tsx b/docs/src/components/Dropdown/index.test.tsx new file mode 100644 index 000000000..199247e2d --- /dev/null +++ b/docs/src/components/Dropdown/index.test.tsx @@ -0,0 +1,32 @@ +import React from "react" +import renderer from "react-test-renderer" +import { fireEvent, render } from "@testing-library/react" + +import Dropdown from "./index" +import { opt_out_tracking } from "mixpanel-browser" + +describe("Dropdown", () => { + window.open = jest.fn(); + const location = { + href: { + replace: jest.fn().mockReturnValue('/'), + }, + pathname: '/visual-embed-sdk/release/en', + }; + + it("should renders correctly", () => { + const tree = renderer + .create() + .toJSON() + expect(tree).toMatchSnapshot() + }) + + it('should redirect to new url on click', () => { + const { getByTestId } = render(); + const option = getByTestId('option-Cloud'); + fireEvent.click(option); + expect(location.href.replace).toHaveBeenCalledTimes(1); + expect(window.open).toHaveBeenCalledTimes(1); + expect(window.open).toHaveBeenCalledWith('/', '_self'); + }) +}) \ No newline at end of file diff --git a/docs/src/components/Dropdown/index.tsx b/docs/src/components/Dropdown/index.tsx new file mode 100644 index 000000000..c50380bb0 --- /dev/null +++ b/docs/src/components/Dropdown/index.tsx @@ -0,0 +1,51 @@ +import React, { useState, useEffect } from 'react'; +import { AiOutlineCaretDown } from '@react-icons/all-files/ai/AiOutlineCaretDown'; +import { VERSION_DROPDOWN } from '../../configs/doc-configs'; +import './index.scss'; + +const Dropdown = (props: { location: Location }) => { + const { location } = props; + const [currentVersion, setCurrentVersion] = useState({}); + const options = VERSION_DROPDOWN; + useEffect(() => { + const pathname = location.pathname; + const selectedOption = options.find(({ link }) => { + return pathname.includes(link); + }); + setCurrentVersion(selectedOption); + }, []); + + const handelClick = (link) => { + if (currentVersion?.link) { + const previousLink = currentVersion.link; + const url = location.href.replace(previousLink, link); + window.open(url, '_self'); + } + }; + + if (!currentVersion?.link) { + return
; + } + + return ( +
+
+ +
+ {options.map(({ label, link }) => { + return ( +
handelClick(link)}> + {label} +
+ ); + })} +
+
+
+ ); +}; + +export default Dropdown; diff --git a/docs/src/components/Footer/__snapshots__/index.test.tsx.snap b/docs/src/components/Footer/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..033a2f22d --- /dev/null +++ b/docs/src/components/Footer/__snapshots__/index.test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Footer should renders correctly 1`] = ` +
+
+
+
+ + COPYRIGHT_TEXT + +
+
+
+
+`; diff --git a/docs/src/components/Footer/index.scss b/docs/src/components/Footer/index.scss new file mode 100644 index 000000000..12b701637 --- /dev/null +++ b/docs/src/components/Footer/index.scss @@ -0,0 +1,14 @@ +@import '../../assets/styles/variables.scss'; + +footer { + width: 100%; + background: var(--body-background-color); + + .footerWrapper { + text-align: center; + color: #777e8b; + font-size: 12px; + font-weight: 300; + margin-top: 50px; + } +} diff --git a/docs/src/components/Footer/index.test.tsx b/docs/src/components/Footer/index.test.tsx new file mode 100644 index 000000000..a0eb60dd0 --- /dev/null +++ b/docs/src/components/Footer/index.test.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import Footer from './index'; + +jest.mock('../../utils/lang-utils', () => (key) => key); + +describe('Footer', () => { + it("should renders correctly", () => { + const { container } = render(